policy: enable proxy network from source policy caps
Evaluate source policy caps before solve requests so policies can enable
BuildKit proxy networking. Policy can return caps {"exec.proxy": true}
during the caps request to enable proxy network
support for the solve.
Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
This commit is contained in:
@@ -140,6 +140,7 @@ type policyFileSpec struct {
|
||||
type policyEvalOpt struct {
|
||||
Strict bool
|
||||
LogLevel *logrus.Level
|
||||
SkipCaps bool
|
||||
}
|
||||
|
||||
type policyOpt struct {
|
||||
|
||||
@@ -667,6 +667,7 @@ func configureSourcePolicy(ctx context.Context, np *noderesolver.ResolvedNode, o
|
||||
Data: policy.DefaultPolicyData(),
|
||||
}},
|
||||
}
|
||||
builtin.SkipCaps = true
|
||||
popts = append([]policyOpt{builtin}, popts...)
|
||||
}
|
||||
|
||||
@@ -742,6 +743,11 @@ func configureSourcePolicy(ctx context.Context, np *noderesolver.ResolvedNode, o
|
||||
DefaultPlatform: defaultPlatform(bopts),
|
||||
SourceResolver: sourceResolver,
|
||||
})
|
||||
if !popt.SkipCaps {
|
||||
if err := applyPolicyCaps(ctx, p, bopts, so); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
policies = append(policies, p)
|
||||
cbs = append(cbs, p.CheckPolicy)
|
||||
if popt.Strict {
|
||||
@@ -750,10 +756,30 @@ func configureSourcePolicy(ctx context.Context, np *noderesolver.ResolvedNode, o
|
||||
}
|
||||
}
|
||||
}
|
||||
if so.ProxyNetwork {
|
||||
if policyLogger != nil {
|
||||
policyLogger.Log("policy enabled network proxy")
|
||||
}
|
||||
}
|
||||
so.SourcePolicyProvider = policysession.NewPolicyProvider(policy.MultiPolicyCallback(cbs...))
|
||||
return defers, nil
|
||||
}
|
||||
|
||||
func applyPolicyCaps(ctx context.Context, p *policy.Policy, bopts gateway.BuildOpts, so *client.SolveOpt) error {
|
||||
caps, err := p.CheckCaps(ctx)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to evaluate policy caps")
|
||||
}
|
||||
if !caps[policy.CapExecProxy] {
|
||||
return nil
|
||||
}
|
||||
if err := bopts.LLBCaps.Supports(pb.CapExecMetaNetworkProxy); err != nil {
|
||||
return errors.New("network proxy requested by policy is not supported by the current BuildKit daemon, please upgrade to version v0.31+")
|
||||
}
|
||||
so.ProxyNetwork = true
|
||||
return nil
|
||||
}
|
||||
|
||||
func policyEnvFilename(inp Inputs) string {
|
||||
base := filepath.Base(filepath.Clean(inp.DockerfilePath))
|
||||
if base != "." && base != string(filepath.Separator) {
|
||||
|
||||
@@ -5,11 +5,15 @@ import (
|
||||
"sync"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/buildx/policy"
|
||||
"github.com/docker/buildx/util/buildflags"
|
||||
"github.com/docker/buildx/util/ocilayout"
|
||||
"github.com/docker/buildx/util/progress"
|
||||
"github.com/moby/buildkit/client"
|
||||
"github.com/moby/buildkit/client/ociindex"
|
||||
gateway "github.com/moby/buildkit/frontend/gateway/client"
|
||||
"github.com/moby/buildkit/solver/pb"
|
||||
"github.com/moby/buildkit/util/apicaps"
|
||||
"github.com/opencontainers/go-digest"
|
||||
ocispecs "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
"github.com/pkg/errors"
|
||||
@@ -163,6 +167,67 @@ func TestProxyArgKeyExists(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestApplyPolicyCapsEnablesProxyNetwork(t *testing.T) {
|
||||
p := policyWithDecision(`
|
||||
package docker
|
||||
|
||||
decision := {
|
||||
"allow": false,
|
||||
"caps": {"exec.proxy": true},
|
||||
}
|
||||
`)
|
||||
var so client.SolveOpt
|
||||
|
||||
err := applyPolicyCaps(context.Background(), p, buildOptsWithCaps(pb.CapExecMetaNetworkProxy), &so)
|
||||
require.NoError(t, err)
|
||||
require.True(t, so.ProxyNetwork)
|
||||
}
|
||||
|
||||
func TestApplyPolicyCapsOrsProxyNetwork(t *testing.T) {
|
||||
falsePolicy := policyWithDecision(`
|
||||
package docker
|
||||
|
||||
decision := {
|
||||
"allow": true,
|
||||
"caps": {"exec.proxy": false},
|
||||
}
|
||||
`)
|
||||
truePolicy := policyWithDecision(`
|
||||
package docker
|
||||
|
||||
decision := {
|
||||
"allow": true,
|
||||
"caps": {"exec.proxy": true},
|
||||
}
|
||||
`)
|
||||
var so client.SolveOpt
|
||||
|
||||
err := applyPolicyCaps(context.Background(), falsePolicy, buildOptsWithCaps(pb.CapExecMetaNetworkProxy), &so)
|
||||
require.NoError(t, err)
|
||||
require.False(t, so.ProxyNetwork)
|
||||
|
||||
err = applyPolicyCaps(context.Background(), truePolicy, buildOptsWithCaps(pb.CapExecMetaNetworkProxy), &so)
|
||||
require.NoError(t, err)
|
||||
require.True(t, so.ProxyNetwork)
|
||||
}
|
||||
|
||||
func TestApplyPolicyCapsRequiresBuildKitCap(t *testing.T) {
|
||||
p := policyWithDecision(`
|
||||
package docker
|
||||
|
||||
decision := {
|
||||
"allow": true,
|
||||
"caps": {"exec.proxy": true},
|
||||
}
|
||||
`)
|
||||
var so client.SolveOpt
|
||||
|
||||
err := applyPolicyCaps(context.Background(), p, buildOptsWithCaps(), &so)
|
||||
require.ErrorContains(t, err, "network proxy requested by policy is not supported by the current BuildKit daemon")
|
||||
require.ErrorContains(t, err, "please upgrade to version v0.31+")
|
||||
require.False(t, so.ProxyNetwork)
|
||||
}
|
||||
|
||||
func TestLoadInputsOCILayoutNamedContext(t *testing.T) {
|
||||
layoutPath := t.TempDir()
|
||||
|
||||
@@ -299,3 +364,25 @@ func (w *captureProgressWriter) ValidateLogSource(digest.Digest, any) bool { ret
|
||||
func (w *captureProgressWriter) ClearLogSource(any) {}
|
||||
|
||||
var _ progress.Writer = (*captureProgressWriter)(nil)
|
||||
|
||||
func policyWithDecision(decision string) *policy.Policy {
|
||||
return policy.NewPolicy(policy.Opt{
|
||||
Files: []policy.File{{
|
||||
Filename: "policy.rego",
|
||||
Data: []byte(decision),
|
||||
}},
|
||||
})
|
||||
}
|
||||
|
||||
func buildOptsWithCaps(caps ...apicaps.CapID) gateway.BuildOpts {
|
||||
out := make([]*apicaps.PBCap, 0, len(caps))
|
||||
for _, c := range caps {
|
||||
out = append(out, &apicaps.PBCap{
|
||||
ID: string(c),
|
||||
Enabled: true,
|
||||
})
|
||||
}
|
||||
return gateway.BuildOpts{
|
||||
LLBCaps: pb.Caps.CapSet(out),
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user