Skip to content

Commit

Permalink
security entitlement support
Browse files Browse the repository at this point in the history
Signed-off-by: Kunal Kushwaha <[email protected]>
  • Loading branch information
kunalkushwaha committed Sep 5, 2018
1 parent 68e25c6 commit 50c12a4
Show file tree
Hide file tree
Showing 19 changed files with 669 additions and 23 deletions.
4 changes: 0 additions & 4 deletions api/services/control/control.proto
Original file line number Diff line number Diff line change
Expand Up @@ -62,11 +62,7 @@ message SolveRequest {
string Frontend = 6;
map<string, string> FrontendAttrs = 7;
CacheOptions Cache = 8 [(gogoproto.nullable) = false];
<<<<<<< af46188e9b3e8c78cfee8a223919498680276122
repeated string Entitlements = 9 [(gogoproto.customtype) = "github.com/moby/buildkit/util/entitlements.Entitlement" ];
=======
repeated string Entitlements = 9 [(gogoproto.customtype) = "github.com/moby/buildkit/util/entitlements.Entitlement"];
>>>>>>> proto defination
}

message CacheOptions {
Expand Down
33 changes: 32 additions & 1 deletion client/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import (
"github.com/moby/buildkit/identity"
"github.com/moby/buildkit/session"
"github.com/moby/buildkit/session/secrets/secretsprovider"
"github.com/moby/buildkit/util/entitlements"
"github.com/moby/buildkit/util/testutil"
"github.com/moby/buildkit/util/testutil/httpserver"
"github.com/moby/buildkit/util/testutil/integration"
Expand Down Expand Up @@ -72,6 +73,7 @@ func TestClientIntegration(t *testing.T) {
testExtraHosts,
testNetworkMode,
testFrontendMetadataReturn,
testSecurityMode,
})
}

Expand Down Expand Up @@ -120,12 +122,41 @@ func testNetworkMode(t *testing.T, sb integration.Sandbox) {

_, err = c.Solve(context.TODO(), def, SolveOpt{
// Currently disabled globally by default
// AllowedEntitlements: []entitlements.Entitlement{entitlements.EntitlementNetworkHost},
AllowedEntitlements: []entitlements.Entitlement{entitlements.EntitlementNetworkHost},
}, nil)
require.Error(t, err)
require.Contains(t, err.Error(), "network.host is not allowed")
}

func testSecurityMode(t *testing.T, sb integration.Sandbox) {
t.Parallel()
c, err := New(context.TODO(), sb.Address())
require.NoError(t, err)
defer c.Close()

st := llb.Image("busybox:latest").
Run(llb.Shlex(`sh -c 'echo confined'`))

def, err := st.Marshal()
require.NoError(t, err)

_, err = c.Solve(context.TODO(), def, SolveOpt{}, nil)
require.NoError(t, err)

st2 := llb.Image("busybox:latest").
Run(llb.Shlex(`sh -c 'echo unconfined'`), llb.Security(llb.SecurityModeUnconfined))

def, err = st2.Marshal()
require.NoError(t, err)

_, err = c.Solve(context.TODO(), def, SolveOpt{
// Currently disabled globally by default
AllowedEntitlements: []entitlements.Entitlement{entitlements.EntitlementSecurityUnconfined},
}, nil)
require.Error(t, err)
require.Contains(t, err.Error(), "security.unconfined is not allowed")
}

func testFrontendImageNaming(t *testing.T, sb integration.Sandbox) {
requiresLinux(t)
t.Parallel()
Expand Down
21 changes: 19 additions & 2 deletions client/llb/exec.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ type Meta struct {
ProxyEnv *ProxyEnv
ExtraHosts []HostIP
Network pb.NetMode
Security pb.SecMode
}

func NewExecOp(root Output, meta Meta, readOnly bool, c Constraints) *ExecOp {
Expand Down Expand Up @@ -145,13 +146,18 @@ func (e *ExecOp) Marshal(c *Constraints) (digest.Digest, []byte, *pb.OpMetadata,
}

peo := &pb.ExecOp{
Meta: meta,
Network: e.meta.Network,
Meta: meta,
Network: e.meta.Network,
Security: e.meta.Security,
}
if e.meta.Network != NetModeSandbox {
addCap(&e.constraints, pb.CapExecMetaNetwork)
}

if e.meta.Security != SecurityModeConfined {
addCap(&e.constraints, pb.CapExecMetaSecurity)
}

if p := e.meta.ProxyEnv; p != nil {
peo.Meta.ProxyEnv = &pb.ProxyEnv{
HttpProxy: p.HttpProxy,
Expand Down Expand Up @@ -368,6 +374,12 @@ func Network(n pb.NetMode) RunOption {
})
}

func Security(s pb.SecMode) RunOption {
return runOptionFunc(func(ei *ExecInfo) {
ei.State = security(s)(ei.State)
})
}

func Shlex(str string) RunOption {
return Shlexf(str)
}
Expand Down Expand Up @@ -526,3 +538,8 @@ const (
NetModeHost = pb.NetMode_HOST
NetModeNone = pb.NetMode_NONE
)

const (
SecurityModeUnconfined = pb.SecMode_UNCONFINED
SecurityModeConfined = pb.SecMode_CONFINED
)
16 changes: 15 additions & 1 deletion client/llb/meta.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ var (
keyExtraHost = contextKeyT("llb.exec.extrahost")
keyPlatform = contextKeyT("llb.platform")
keyNetwork = contextKeyT("llb.network")
keySecurity = contextKeyT("llb.security")
)

func addEnv(key, value string) StateOption {
Expand Down Expand Up @@ -152,7 +153,6 @@ func network(v pb.NetMode) StateOption {
return s.WithValue(keyNetwork, v)
}
}

func getNetwork(s State) pb.NetMode {
v := s.Value(keyNetwork)
if v != nil {
Expand All @@ -162,6 +162,20 @@ func getNetwork(s State) pb.NetMode {
return NetModeSandbox
}

func security(v pb.SecMode) StateOption {
return func(s State) State {
return s.WithValue(keySecurity, v)
}
}
func getSecurity(s State) pb.SecMode {
v := s.Value(keySecurity)
if v != nil {
n := v.(pb.SecMode)
return n
}
return SecurityModeConfined
}

type EnvList []KeyValue

type KeyValue struct {
Expand Down
8 changes: 8 additions & 0 deletions client/llb/state.go
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,7 @@ func (s State) Run(ro ...RunOption) ExecState {
ProxyEnv: ei.ProxyEnv,
ExtraHosts: getExtraHosts(ei.State),
Network: getNetwork(ei.State),
Security: getSecurity(ei.State),
}

exec := NewExecOp(s.Output(), meta, ei.ReadonlyRootFS, ei.Constraints)
Expand Down Expand Up @@ -257,6 +258,13 @@ func (s State) Network(n pb.NetMode) State {
func (s State) GetNetwork() pb.NetMode {
return getNetwork(s)
}
func (s State) Security(n pb.SecMode) State {
return security(n)(s)
}

func (s State) GetSecurity() pb.SecMode {
return getSecurity(s)
}

func (s State) With(so ...StateOption) State {
for _, o := range so {
Expand Down
17 changes: 17 additions & 0 deletions cmd/buildkitd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import (
"github.com/moby/buildkit/frontend/gateway/forwarder"
"github.com/moby/buildkit/session"
"github.com/moby/buildkit/solver/boltdbcachestorage"
"github.com/moby/buildkit/solver/llbsolver"
"github.com/moby/buildkit/util/apicaps"
"github.com/moby/buildkit/util/appcontext"
"github.com/moby/buildkit/util/appdefaults"
Expand Down Expand Up @@ -150,6 +151,10 @@ func main() {
Usage: "ca certificate to verify clients",
Value: defaultConf.GRPC.TLS.CA,
},
cli.StringSliceFlag{
Name: "allow-insecure-entitlement",
Usage: "allows insecure entitlements like network.host & security.unconfined",
},
)
app.Flags = append(app.Flags, appFlags...)

Expand Down Expand Up @@ -207,6 +212,18 @@ func main() {

controller.Register(server)

ents := c.GlobalStringSlice("allow-insecure-entitlement")
for _, e := range ents {
switch e {
case "security.unconfined":
llbsolver.AllowSecurityUnconfinedUnstable = true
case "network.host":
llbsolver.AllowNetworkHostUnstable = true
default:
return fmt.Errorf("invalid entitlement : %v", e)
}
}

errCh := make(chan error, 1)
if err := serveGRPC(cfg.GRPC, server, errCh); err != nil {
return err
Expand Down
6 changes: 1 addition & 5 deletions executor/containerdexecutor/executor.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import (

"github.com/containerd/containerd"
"github.com/containerd/containerd/cio"
"github.com/containerd/containerd/contrib/seccomp"
containerdoci "github.com/containerd/containerd/oci"
"github.com/moby/buildkit/cache"
"github.com/moby/buildkit/executor"
Expand All @@ -17,7 +16,6 @@ import (
"github.com/moby/buildkit/snapshot"
"github.com/moby/buildkit/solver/pb"
"github.com/moby/buildkit/util/network"
"github.com/moby/buildkit/util/system"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
)
Expand Down Expand Up @@ -97,9 +95,7 @@ func (w containerdExecutor) Exec(ctx context.Context, meta executor.Meta, root c
if meta.ReadonlyRootFS {
opts = append(opts, containerdoci.WithRootFSReadonly())
}
if system.SeccompSupported() {
opts = append(opts, seccomp.WithDefaultProfile())
}

spec, cleanup, err := oci.GenerateSpec(ctx, meta, mounts, id, resolvConf, hostsFile, namespace, opts...)
if err != nil {
return err
Expand Down
1 change: 1 addition & 0 deletions executor/executor.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ type Meta struct {
ReadonlyRootFS bool
ExtraHosts []HostIP
NetMode pb.NetMode
SecMode pb.SecMode
}

type Mount struct {
Expand Down
7 changes: 7 additions & 0 deletions executor/oci/spec_unix.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,16 @@ import (
"sync"

"github.com/containerd/containerd/containers"
"github.com/containerd/containerd/contrib/seccomp"
"github.com/containerd/containerd/mount"
"github.com/containerd/containerd/namespaces"
"github.com/containerd/containerd/oci"
"github.com/mitchellh/hashstructure"
"github.com/moby/buildkit/executor"
"github.com/moby/buildkit/snapshot"
"github.com/moby/buildkit/solver/pb"
"github.com/moby/buildkit/util/network"
"github.com/moby/buildkit/util/system"
specs "github.com/opencontainers/runtime-spec/specs-go"
"github.com/pkg/errors"
)
Expand All @@ -31,6 +34,10 @@ func GenerateSpec(ctx context.Context, meta executor.Meta, mounts []executor.Mou
ctx = namespaces.WithNamespace(ctx, "buildkit")
}

if system.SeccompSupported() && meta.SecMode == pb.SecMode_CONFINED {
opts = append(opts, seccomp.WithDefaultProfile())
}

// Note that containerd.GenerateSpec is namespaced so as to make
// specs.Linux.CgroupsPath namespaced
s, err := oci.GenerateSpec(ctx, nil, c, opts...)
Expand Down
6 changes: 1 addition & 5 deletions executor/runcexecutor/executor.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import (
"strings"
"syscall"

"github.com/containerd/containerd/contrib/seccomp"
"github.com/containerd/containerd/mount"
containerdoci "github.com/containerd/containerd/oci"
"github.com/containerd/continuity/fs"
Expand All @@ -24,7 +23,6 @@ import (
"github.com/moby/buildkit/solver/pb"
"github.com/moby/buildkit/util/network"
rootlessspecconv "github.com/moby/buildkit/util/rootless/specconv"
"github.com/moby/buildkit/util/system"
specs "github.com/opencontainers/runtime-spec/specs-go"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
Expand Down Expand Up @@ -167,9 +165,7 @@ func (w *runcExecutor) Exec(ctx context.Context, meta executor.Meta, root cache.
defer f.Close()

opts := []containerdoci.SpecOpts{oci.WithUIDGID(uid, gid, sgids)}
if system.SeccompSupported() {
opts = append(opts, seccomp.WithDefaultProfile())
}

if meta.ReadonlyRootFS {
opts = append(opts, containerdoci.WithRootFSReadonly())
}
Expand Down
21 changes: 21 additions & 0 deletions frontend/dockerfile/builder/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ const (
keyImageResolveMode = "image-resolve-mode"
keyGlobalAddHosts = "add-hosts"
keyForceNetwork = "force-network-mode"
keyForceSecurity = "force-security-mode"
keyOverrideCopyImage = "override-copy-image" // remove after CopyOp implemented
)

Expand Down Expand Up @@ -79,6 +80,11 @@ func Build(ctx context.Context, c client.Client) (*client.Result, error) {
return nil, err
}

defaultSecMode, err := parseSecMode(opts[keyForceSecurity])
if err != nil {
return nil, err
}

filename := opts[keyFilename]
if filename == "" {
filename = defaultDockerfileName
Expand Down Expand Up @@ -271,6 +277,7 @@ func Build(ctx context.Context, c client.Client) (*client.Result, error) {
PrefixPlatform: exportMap,
ExtraHosts: extraHosts,
ForceNetMode: defaultNetMode,
ForceSecMode: defaultSecMode,
OverrideCopyImage: opts[keyOverrideCopyImage],
})

Expand Down Expand Up @@ -477,3 +484,17 @@ func parseNetMode(v string) (pb.NetMode, error) {
return 0, errors.Errorf("invalid netmode %s", v)
}
}

func parseSecMode(v string) (pb.SecMode, error) {
if v == "" {
return llb.SecurityModeConfined, nil
}
switch v {
case "confined":
return llb.SecurityModeConfined, nil
case "unconfined":
return llb.SecurityModeUnconfined, nil
default:
return 0, errors.Errorf("invalid secmode %s", v)
}
}
1 change: 1 addition & 0 deletions frontend/dockerfile/dockerfile2llb/convert.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ type ConvertOpt struct {
PrefixPlatform bool
ExtraHosts []llb.HostIP
ForceNetMode pb.NetMode
ForceSecMode pb.SecMode
OverrideCopyImage string
}

Expand Down
1 change: 0 additions & 1 deletion solver/llbsolver/bridge.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,6 @@ func (b *llbBridge) Solve(ctx context.Context, req frontend.SolveRequest) (res *
if err != nil {
return nil, err
}

edge, err := Load(req.Definition, ValidateEntitlements(ent), WithCacheSources(cms), RuntimePlatforms(b.platforms), WithValidateCaps())
if err != nil {
return nil, err
Expand Down
1 change: 1 addition & 0 deletions solver/llbsolver/ops/exec.go
Original file line number Diff line number Diff line change
Expand Up @@ -528,6 +528,7 @@ func (e *execOp) Exec(ctx context.Context, inputs []solver.Result) ([]solver.Res
ReadonlyRootFS: readonlyRootFS,
ExtraHosts: extraHosts,
NetMode: e.op.Network,
SecMode: e.op.Security,
}

if e.op.Meta.ProxyEnv != nil {
Expand Down
6 changes: 5 additions & 1 deletion solver/llbsolver/solver.go
Original file line number Diff line number Diff line change
Expand Up @@ -281,13 +281,17 @@ func notifyCompleted(ctx context.Context, v *client.Vertex, err error, cached bo
pw.Write(v.Digest.String(), *v)
}

var AllowNetworkHostUnstable = false // TODO: enable in constructor
var AllowNetworkHostUnstable = false // TODO: enable in constructor
var AllowSecurityUnconfinedUnstable = false // TODO: enable in constructor

func supportedEntitlements() []entitlements.Entitlement {
out := []entitlements.Entitlement{} // nil means no filter
if AllowNetworkHostUnstable {
out = append(out, entitlements.EntitlementNetworkHost)
}
if AllowSecurityUnconfinedUnstable {
out = append(out, entitlements.EntitlementSecurityUnconfined)
}
return out
}

Expand Down
Loading

0 comments on commit 50c12a4

Please sign in to comment.