mirror of
https://github.com/moby/buildkit.git
synced 2026-08-08 16:50:44 +00:00
Merge pull request #4899 from dancysoft/frontend-restriction
buildkitd: Frontend restriction support
This commit is contained in:
@@ -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 {
|
||||
@@ -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"`
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 = []
|
||||
|
||||
```
|
||||
|
||||
@@ -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 {
|
||||
@@ -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 {
|
||||
@@ -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{
|
||||
|
||||
45
frontend/gateway/gateway_test.go
Normal file
45
frontend/gateway/gateway_test.go
Normal file
@@ -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)
|
||||
}
|
||||
Reference in New Issue
Block a user