Skip to content

Commit

Permalink
Merge pull request moby#4899 from dancysoft/frontend-restriction
Browse files Browse the repository at this point in the history
buildkitd: Frontend restriction support
  • Loading branch information
tonistiigi authored May 13, 2024
2 parents 4bdc49b + b5c50af commit a17cbfd
Show file tree
Hide file tree
Showing 5 changed files with 132 additions and 6 deletions.
14 changes: 14 additions & 0 deletions cmd/buildkitd/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,11 @@ type Config struct {
DNS *DNSConfig `toml:"dns"`

History *HistoryConfig `toml:"history"`

Frontends struct {
Dockerfile DockerfileFrontendConfig `toml:"dockerfile.v0"`
Gateway GatewayFrontendConfig `toml:"gateway.v0"`
} `toml:"frontend"`
}

type LogConfig struct {
Expand Down Expand Up @@ -155,3 +160,12 @@ type HistoryConfig struct {
MaxAge Duration `toml:"maxAge"`
MaxEntries int64 `toml:"maxEntries"`
}

type DockerfileFrontendConfig struct {
Enabled *bool `toml:"enabled"`
}

type GatewayFrontendConfig struct {
Enabled *bool `toml:"enabled"`
AllowedRepositories []string `toml:"allowedRepositories"`
}
13 changes: 11 additions & 2 deletions cmd/buildkitd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -776,8 +776,17 @@ func newController(c *cli.Context, cfg *config.Config) (*control.Controller, err
return nil, err
}
frontends := map[string]frontend.Frontend{}
frontends["dockerfile.v0"] = forwarder.NewGatewayForwarder(wc.Infos(), dockerfile.Build)
frontends["gateway.v0"] = gateway.NewGatewayFrontend(wc.Infos())

if cfg.Frontends.Dockerfile.Enabled == nil || *cfg.Frontends.Dockerfile.Enabled {
frontends["dockerfile.v0"] = forwarder.NewGatewayForwarder(wc.Infos(), dockerfile.Build)
}
if cfg.Frontends.Gateway.Enabled == nil || *cfg.Frontends.Gateway.Enabled {
gwfe, err := gateway.NewGatewayFrontend(wc.Infos(), cfg.Frontends.Gateway.AllowedRepositories)
if err != nil {
return nil, err
}
frontends["gateway.v0"] = gwfe
}

cacheStorage, err := bboltcachestorage.NewStore(filepath.Join(cfg.Root, "cache.db"))
if err != nil {
Expand Down
17 changes: 17 additions & 0 deletions docs/buildkitd.toml.md
Original file line number Diff line number Diff line change
Expand Up @@ -136,4 +136,21 @@ insecure-entitlements = [ "network.host", "security.insecure" ]
# optionally mirror configuration can be done by defining it as a registry.
[registry."yourmirror.local:5000"]
http = true

# Frontend control
[frontend."dockerfile.v0"]
enabled = true

[frontend."gateway.v0"]
enabled = true

# If allowedRepositories is empty, all gateway sources are allowed.
# Otherwise, only the listed repositories are allowed as a gateway source.
#
# NOTE: Only the repository name (without tag) is compared.
#
# Example:
# allowedRepositories = [ "docker-registry.wikimedia.org/repos/releng/blubber/buildkit" ]
allowedRepositories = []

```
49 changes: 45 additions & 4 deletions frontend/gateway/gateway.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,14 +67,26 @@ const (
keyDevel = "gateway-devel"
)

func NewGatewayFrontend(w worker.Infos) frontend.Frontend {
return &gatewayFrontend{
workers: w,
func NewGatewayFrontend(workers worker.Infos, allowedRepositories []string) (frontend.Frontend, error) {
var parsedAllowedRepositories []string

for _, allowedRepository := range allowedRepositories {
sourceRef, err := reference.ParseNormalizedNamed(allowedRepository)
if err != nil {
return nil, err
}
parsedAllowedRepositories = append(parsedAllowedRepositories, reference.TrimNamed(sourceRef).Name())
}

return &gatewayFrontend{
workers: workers,
allowedRepositories: parsedAllowedRepositories,
}, nil
}

type gatewayFrontend struct {
workers worker.Infos
workers worker.Infos
allowedRepositories []string
}

func filterPrefix(opts map[string]string, pfx string) map[string]string {
Expand All @@ -87,6 +99,30 @@ func filterPrefix(opts map[string]string, pfx string) map[string]string {
return m
}

func (gf *gatewayFrontend) checkSourceIsAllowed(source string) error {
// Returns nil if the source is allowed.
// Returns an error if the source is not allowed.
if len(gf.allowedRepositories) == 0 {
// No source restrictions in place
return nil
}

sourceRef, err := reference.ParseNormalizedNamed(source)
if err != nil {
return err
}

taglessSource := reference.TrimNamed(sourceRef).Name()

for _, allowedRepository := range gf.allowedRepositories {
if taglessSource == allowedRepository {
// Allowed
return nil
}
}
return errors.Errorf("'%s' is not an allowed gateway source", source)
}

func (gf *gatewayFrontend) Solve(ctx context.Context, llbBridge frontend.FrontendLLBBridge, exec executor.Executor, opts map[string]string, inputs map[string]*opspb.Definition, sid string, sm *session.Manager) (*frontend.Result, error) {
source, ok := opts[keySource]
if !ok {
Expand All @@ -101,6 +137,11 @@ func (gf *gatewayFrontend) Solve(ctx context.Context, llbBridge frontend.Fronten

var frontendDef *opspb.Definition

err := gf.checkSourceIsAllowed(source)
if err != nil {
return nil, err
}

if isDevel {
devRes, err := llbBridge.Solve(ctx,
frontend.SolveRequest{
Expand Down
45 changes: 45 additions & 0 deletions frontend/gateway/gateway_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package gateway

import (
"testing"

"github.com/stretchr/testify/assert"
)

func TestCheckSourceIsAllowed(t *testing.T) {
makeGatewayFrontend := func(sources []string) (*gatewayFrontend, error) {
gw, err := NewGatewayFrontend(nil, sources)
if err != nil {
return nil, err
}
gw1 := gw.(*gatewayFrontend)
return gw1, nil
}

var gw *gatewayFrontend
var err error

// no restrictions
gw, err = makeGatewayFrontend([]string{})
assert.NoError(t, err)
err = gw.checkSourceIsAllowed("anything")
assert.NoError(t, err)

gw, err = makeGatewayFrontend([]string{"docker-registry.wikimedia.org/repos/releng/blubber/buildkit:9.9.9"})
assert.NoError(t, err)
err = gw.checkSourceIsAllowed("docker-registry.wikimedia.org/repos/releng/blubber/buildkit")
assert.NoError(t, err)
err = gw.checkSourceIsAllowed("docker-registry.wikimedia.org/repos/releng/blubber/buildkit:v1.2.3")
assert.NoError(t, err)
err = gw.checkSourceIsAllowed("docker-registry.wikimedia.org/something-else")
assert.Error(t, err)

gw, err = makeGatewayFrontend([]string{"alpine"})
assert.NoError(t, err)
err = gw.checkSourceIsAllowed("alpine")
assert.NoError(t, err)
err = gw.checkSourceIsAllowed("library/alpine")
assert.NoError(t, err)
err = gw.checkSourceIsAllowed("docker.io/library/alpine")
assert.NoError(t, err)
}

0 comments on commit a17cbfd

Please sign in to comment.