Merge pull request #1966 from thaJeztah/master_apparmor
[master] Add support for apparmor/selinuxv0.9
commit
58038e6371
|
@ -87,6 +87,10 @@ type OCIConfig struct {
|
|||
// Decoding this is delayed in order to remove the dependency from this
|
||||
// config pkg to stargz snapshotter's config pkg.
|
||||
StargzSnapshotterConfig toml.Primitive `toml:"stargzSnapshotter"`
|
||||
|
||||
// ApparmorProfile is the name of the apparmor profile that should be used to constrain build containers.
|
||||
// The profile should already be loaded (by a higher level system) before creating a worker.
|
||||
ApparmorProfile string `toml:"apparmor-profile"`
|
||||
}
|
||||
|
||||
type ContainerdConfig struct {
|
||||
|
@ -98,6 +102,10 @@ type ContainerdConfig struct {
|
|||
GCConfig
|
||||
NetworkConfig
|
||||
Snapshotter string `toml:"snapshotter"`
|
||||
|
||||
// ApparmorProfile is the name of the apparmor profile that should be used to constrain build containers.
|
||||
// The profile should already be loaded (by a higher level system) before creating a worker.
|
||||
ApparmorProfile string `toml:"apparmor-profile"`
|
||||
}
|
||||
|
||||
type GCPolicy struct {
|
||||
|
|
|
@ -91,6 +91,10 @@ func init() {
|
|||
Usage: "snapshotter name to use",
|
||||
Value: ctd.DefaultSnapshotter,
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "containerd-worker-apparmor-profile",
|
||||
Usage: "set the name of the apparmor profile applied to containers",
|
||||
},
|
||||
}
|
||||
|
||||
if defaultConf.Workers.Containerd.GC == nil || *defaultConf.Workers.Containerd.GC {
|
||||
|
@ -192,6 +196,9 @@ func applyContainerdFlags(c *cli.Context, cfg *config.Config) error {
|
|||
if c.GlobalIsSet("containerd-worker-snapshotter") {
|
||||
cfg.Workers.Containerd.Snapshotter = c.GlobalString("containerd-worker-snapshotter")
|
||||
}
|
||||
if c.GlobalIsSet("containerd-worker-apparmor-profile") {
|
||||
cfg.Workers.Containerd.ApparmorProfile = c.GlobalString("containerd-worker-apparmor-profile")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@ -222,7 +229,7 @@ func containerdWorkerInitializer(c *cli.Context, common workerInitializerOpt) ([
|
|||
if cfg.Snapshotter != "" {
|
||||
snapshotter = cfg.Snapshotter
|
||||
}
|
||||
opt, err := containerd.NewWorkerOpt(common.config.Root, cfg.Address, snapshotter, cfg.Namespace, cfg.Labels, dns, nc, ctd.WithTimeout(60*time.Second))
|
||||
opt, err := containerd.NewWorkerOpt(common.config.Root, cfg.Address, snapshotter, cfg.Namespace, cfg.Labels, dns, nc, common.config.Workers.Containerd.ApparmorProfile, ctd.WithTimeout(60*time.Second))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -96,6 +96,10 @@ func init() {
|
|||
Usage: "name of specified oci worker binary",
|
||||
Value: defaultConf.Workers.OCI.Binary,
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "oci-worker-apparmor-profile",
|
||||
Usage: "set the name of the apparmor profile applied to containers",
|
||||
},
|
||||
}
|
||||
n := "oci-worker-rootless"
|
||||
u := "enable rootless mode"
|
||||
|
@ -215,6 +219,9 @@ func applyOCIFlags(c *cli.Context, cfg *config.Config) error {
|
|||
if c.GlobalIsSet("oci-worker-proxy-snapshotter-path") {
|
||||
cfg.Workers.OCI.ProxySnapshotterPath = c.GlobalString("oci-worker-proxy-snapshotter-path")
|
||||
}
|
||||
if c.GlobalIsSet("oci-worker-apparmor-profile") {
|
||||
cfg.Workers.OCI.ApparmorProfile = c.GlobalString("oci-worker-apparmor-profile")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -268,7 +275,7 @@ func ociWorkerInitializer(c *cli.Context, common workerInitializerOpt) ([]worker
|
|||
},
|
||||
}
|
||||
|
||||
opt, err := runc.NewWorkerOpt(common.config.Root, snFactory, cfg.Rootless, processMode, cfg.Labels, idmapping, nc, dns, cfg.Binary)
|
||||
opt, err := runc.NewWorkerOpt(common.config.Root, snFactory, cfg.Rootless, processMode, cfg.Labels, idmapping, nc, dns, cfg.Binary, cfg.ApparmorProfile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -37,10 +37,11 @@ type containerdExecutor struct {
|
|||
dnsConfig *oci.DNSConfig
|
||||
running map[string]chan error
|
||||
mu sync.Mutex
|
||||
apparmorProfile string
|
||||
}
|
||||
|
||||
// New creates a new executor backed by connection to containerd API
|
||||
func New(client *containerd.Client, root, cgroup string, networkProviders map[pb.NetMode]network.Provider, dnsConfig *oci.DNSConfig) executor.Executor {
|
||||
func New(client *containerd.Client, root, cgroup string, networkProviders map[pb.NetMode]network.Provider, dnsConfig *oci.DNSConfig, apparmorProfile string) executor.Executor {
|
||||
// clean up old hosts/resolv.conf file. ignore errors
|
||||
os.RemoveAll(filepath.Join(root, "hosts"))
|
||||
os.RemoveAll(filepath.Join(root, "resolv.conf"))
|
||||
|
@ -52,6 +53,7 @@ func New(client *containerd.Client, root, cgroup string, networkProviders map[pb
|
|||
cgroupParent: cgroup,
|
||||
dnsConfig: dnsConfig,
|
||||
running: make(map[string]chan error),
|
||||
apparmorProfile: apparmorProfile,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -168,7 +170,7 @@ func (w *containerdExecutor) Run(ctx context.Context, id string, root executor.M
|
|||
opts = append(opts, containerdoci.WithCgroup(cgroupsPath))
|
||||
}
|
||||
processMode := oci.ProcessSandbox // FIXME(AkihiroSuda)
|
||||
spec, cleanup, err := oci.GenerateSpec(ctx, meta, mounts, id, resolvConf, hostsFile, namespace, processMode, nil, opts...)
|
||||
spec, cleanup, err := oci.GenerateSpec(ctx, meta, mounts, id, resolvConf, hostsFile, namespace, processMode, nil, w.apparmorProfile, opts...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@ import (
|
|||
"github.com/moby/buildkit/snapshot"
|
||||
"github.com/moby/buildkit/util/network"
|
||||
specs "github.com/opencontainers/runtime-spec/specs-go"
|
||||
"github.com/opencontainers/selinux/go-selinux"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
|
@ -35,7 +36,7 @@ const (
|
|||
|
||||
// GenerateSpec generates spec using containerd functionality.
|
||||
// opts are ignored for s.Process, s.Hostname, and s.Mounts .
|
||||
func GenerateSpec(ctx context.Context, meta executor.Meta, mounts []executor.Mount, id, resolvConf, hostsFile string, namespace network.Namespace, processMode ProcessMode, idmap *idtools.IdentityMapping, opts ...oci.SpecOpts) (*specs.Spec, func(), error) {
|
||||
func GenerateSpec(ctx context.Context, meta executor.Meta, mounts []executor.Mount, id, resolvConf, hostsFile string, namespace network.Namespace, processMode ProcessMode, idmap *idtools.IdentityMapping, apparmorProfile string, opts ...oci.SpecOpts) (*specs.Spec, func(), error) {
|
||||
c := &containers.Container{
|
||||
ID: id,
|
||||
}
|
||||
|
@ -52,7 +53,7 @@ func GenerateSpec(ctx context.Context, meta executor.Meta, mounts []executor.Mou
|
|||
return nil, nil, err
|
||||
}
|
||||
|
||||
if securityOpts, err := generateSecurityOpts(meta.SecurityMode); err == nil {
|
||||
if securityOpts, err := generateSecurityOpts(meta.SecurityMode, apparmorProfile); err == nil {
|
||||
opts = append(opts, securityOpts...)
|
||||
} else {
|
||||
return nil, nil, err
|
||||
|
@ -103,6 +104,9 @@ func GenerateSpec(ctx context.Context, meta executor.Meta, mounts []executor.Mou
|
|||
for _, f := range releasers {
|
||||
f()
|
||||
}
|
||||
if s.Process.SelinuxLabel != "" {
|
||||
selinux.ReleaseLabel(s.Process.SelinuxLabel)
|
||||
}
|
||||
}
|
||||
|
||||
for _, m := range mounts {
|
||||
|
|
|
@ -13,6 +13,7 @@ import (
|
|||
"github.com/moby/buildkit/util/entitlements/security"
|
||||
"github.com/moby/buildkit/util/system"
|
||||
specs "github.com/opencontainers/runtime-spec/specs-go"
|
||||
"github.com/opencontainers/selinux/go-selinux/label"
|
||||
)
|
||||
|
||||
func generateMountOpts(resolvConf, hostsFile string) ([]oci.SpecOpts, error) {
|
||||
|
@ -26,15 +27,32 @@ func generateMountOpts(resolvConf, hostsFile string) ([]oci.SpecOpts, error) {
|
|||
}
|
||||
|
||||
// generateSecurityOpts may affect mounts, so must be called after generateMountOpts
|
||||
func generateSecurityOpts(mode pb.SecurityMode) ([]oci.SpecOpts, error) {
|
||||
if mode == pb.SecurityMode_INSECURE {
|
||||
func generateSecurityOpts(mode pb.SecurityMode, apparmorProfile string) (opts []oci.SpecOpts, _ error) {
|
||||
switch mode {
|
||||
case pb.SecurityMode_INSECURE:
|
||||
return []oci.SpecOpts{
|
||||
security.WithInsecureSpec(),
|
||||
oci.WithWriteableCgroupfs,
|
||||
oci.WithWriteableSysfs,
|
||||
func(_ context.Context, _ oci.Client, _ *containers.Container, s *oci.Spec) error {
|
||||
var err error
|
||||
s.Process.SelinuxLabel, s.Linux.MountLabel, err = label.InitLabels([]string{"disable"})
|
||||
return err
|
||||
},
|
||||
}, nil
|
||||
} else if system.SeccompSupported() && mode == pb.SecurityMode_SANDBOX {
|
||||
return []oci.SpecOpts{withDefaultProfile()}, nil
|
||||
case pb.SecurityMode_SANDBOX:
|
||||
if system.SeccompSupported() {
|
||||
opts = append(opts, withDefaultProfile())
|
||||
}
|
||||
if apparmorProfile != "" {
|
||||
opts = append(opts, oci.WithApparmorProfile(apparmorProfile))
|
||||
}
|
||||
opts = append(opts, func(_ context.Context, _ oci.Client, _ *containers.Container, s *oci.Spec) error {
|
||||
var err error
|
||||
s.Process.SelinuxLabel, s.Linux.MountLabel, err = label.InitLabels(nil)
|
||||
return err
|
||||
})
|
||||
return opts, nil
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@ func generateMountOpts(resolvConf, hostsFile string) ([]oci.SpecOpts, error) {
|
|||
}
|
||||
|
||||
// generateSecurityOpts may affect mounts, so must be called after generateMountOpts
|
||||
func generateSecurityOpts(mode pb.SecurityMode) ([]oci.SpecOpts, error) {
|
||||
func generateSecurityOpts(mode pb.SecurityMode, apparmorProfile string) ([]oci.SpecOpts, error) {
|
||||
if mode == pb.SecurityMode_INSECURE {
|
||||
return nil, errors.New("no support for running in insecure mode on Windows")
|
||||
}
|
||||
|
|
|
@ -42,9 +42,10 @@ type Opt struct {
|
|||
ProcessMode oci.ProcessMode
|
||||
IdentityMapping *idtools.IdentityMapping
|
||||
// runc run --no-pivot (unrecommended)
|
||||
NoPivot bool
|
||||
DNS *oci.DNSConfig
|
||||
OOMScoreAdj *int
|
||||
NoPivot bool
|
||||
DNS *oci.DNSConfig
|
||||
OOMScoreAdj *int
|
||||
ApparmorProfile string
|
||||
}
|
||||
|
||||
var defaultCommandCandidates = []string{"buildkit-runc", "runc"}
|
||||
|
@ -62,6 +63,7 @@ type runcExecutor struct {
|
|||
oomScoreAdj *int
|
||||
running map[string]chan error
|
||||
mu sync.Mutex
|
||||
apparmorProfile string
|
||||
}
|
||||
|
||||
func New(opt Opt, networkProviders map[pb.NetMode]network.Provider) (executor.Executor, error) {
|
||||
|
@ -124,6 +126,7 @@ func New(opt Opt, networkProviders map[pb.NetMode]network.Provider) (executor.Ex
|
|||
dns: opt.DNS,
|
||||
oomScoreAdj: opt.OOMScoreAdj,
|
||||
running: make(map[string]chan error),
|
||||
apparmorProfile: opt.ApparmorProfile,
|
||||
}
|
||||
return w, nil
|
||||
}
|
||||
|
@ -253,7 +256,7 @@ func (w *runcExecutor) Run(ctx context.Context, id string, root executor.Mount,
|
|||
}
|
||||
opts = append(opts, containerdoci.WithCgroup(cgroupsPath))
|
||||
}
|
||||
spec, cleanup, err := oci.GenerateSpec(ctx, meta, mounts, id, resolvConf, hostsFile, namespace, w.processMode, w.idmap, opts...)
|
||||
spec, cleanup, err := oci.GenerateSpec(ctx, meta, mounts, id, resolvConf, hostsFile, namespace, w.processMode, w.idmap, w.apparmorProfile, opts...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
1
go.mod
1
go.mod
|
@ -46,6 +46,7 @@ require (
|
|||
github.com/opencontainers/image-spec v1.0.1
|
||||
github.com/opencontainers/runc v1.0.0-rc92
|
||||
github.com/opencontainers/runtime-spec v1.0.3-0.20200728170252-4d89ac9fbff6
|
||||
github.com/opencontainers/selinux v1.8.0
|
||||
github.com/opentracing-contrib/go-stdlib v1.0.0
|
||||
github.com/opentracing/opentracing-go v1.2.0
|
||||
github.com/pkg/errors v0.9.1
|
||||
|
|
|
@ -23,16 +23,16 @@ import (
|
|||
)
|
||||
|
||||
// NewWorkerOpt creates a WorkerOpt.
|
||||
func NewWorkerOpt(root string, address, snapshotterName, ns string, labels map[string]string, dns *oci.DNSConfig, nopt netproviders.Opt, opts ...containerd.ClientOpt) (base.WorkerOpt, error) {
|
||||
func NewWorkerOpt(root string, address, snapshotterName, ns string, labels map[string]string, dns *oci.DNSConfig, nopt netproviders.Opt, apparmorProfile string, opts ...containerd.ClientOpt) (base.WorkerOpt, error) {
|
||||
opts = append(opts, containerd.WithDefaultNamespace(ns))
|
||||
client, err := containerd.New(address, opts...)
|
||||
if err != nil {
|
||||
return base.WorkerOpt{}, errors.Wrapf(err, "failed to connect client to %q . make sure containerd is running", address)
|
||||
}
|
||||
return newContainerd(root, client, snapshotterName, ns, labels, dns, nopt)
|
||||
return newContainerd(root, client, snapshotterName, ns, labels, dns, nopt, apparmorProfile)
|
||||
}
|
||||
|
||||
func newContainerd(root string, client *containerd.Client, snapshotterName, ns string, labels map[string]string, dns *oci.DNSConfig, nopt netproviders.Opt) (base.WorkerOpt, error) {
|
||||
func newContainerd(root string, client *containerd.Client, snapshotterName, ns string, labels map[string]string, dns *oci.DNSConfig, nopt netproviders.Opt, apparmorProfile string) (base.WorkerOpt, error) {
|
||||
if strings.Contains(snapshotterName, "/") {
|
||||
return base.WorkerOpt{}, errors.Errorf("bad snapshotter name: %q", snapshotterName)
|
||||
}
|
||||
|
@ -104,7 +104,7 @@ func newContainerd(root string, client *containerd.Client, snapshotterName, ns s
|
|||
ID: id,
|
||||
Labels: xlabels,
|
||||
MetadataStore: md,
|
||||
Executor: containerdexecutor.New(client, root, "", np, dns),
|
||||
Executor: containerdexecutor.New(client, root, "", np, dns, apparmorProfile),
|
||||
Snapshotter: snap,
|
||||
ContentStore: cs,
|
||||
Applier: winlayers.NewFileSystemApplierWithWindows(cs, df),
|
||||
|
|
|
@ -30,7 +30,7 @@ func newWorkerOpt(t *testing.T, addr string) (base.WorkerOpt, func()) {
|
|||
tmpdir, err := ioutil.TempDir("", "workertest")
|
||||
require.NoError(t, err)
|
||||
cleanup := func() { os.RemoveAll(tmpdir) }
|
||||
workerOpt, err := NewWorkerOpt(tmpdir, addr, "overlayfs", "buildkit-test", nil, nil, netproviders.Opt{Mode: "host"})
|
||||
workerOpt, err := NewWorkerOpt(tmpdir, addr, "overlayfs", "buildkit-test", nil, nil, netproviders.Opt{Mode: "host"}, "")
|
||||
require.NoError(t, err)
|
||||
return workerOpt, cleanup
|
||||
}
|
||||
|
|
|
@ -32,7 +32,7 @@ type SnapshotterFactory struct {
|
|||
}
|
||||
|
||||
// NewWorkerOpt creates a WorkerOpt.
|
||||
func NewWorkerOpt(root string, snFactory SnapshotterFactory, rootless bool, processMode oci.ProcessMode, labels map[string]string, idmap *idtools.IdentityMapping, nopt netproviders.Opt, dns *oci.DNSConfig, binary string) (base.WorkerOpt, error) {
|
||||
func NewWorkerOpt(root string, snFactory SnapshotterFactory, rootless bool, processMode oci.ProcessMode, labels map[string]string, idmap *idtools.IdentityMapping, nopt netproviders.Opt, dns *oci.DNSConfig, binary, apparmorProfile string) (base.WorkerOpt, error) {
|
||||
var opt base.WorkerOpt
|
||||
name := "runc-" + snFactory.Name
|
||||
root = filepath.Join(root, name)
|
||||
|
@ -62,6 +62,7 @@ func NewWorkerOpt(root string, snFactory SnapshotterFactory, rootless bool, proc
|
|||
ProcessMode: processMode,
|
||||
IdentityMapping: idmap,
|
||||
DNS: dns,
|
||||
ApparmorProfile: apparmorProfile,
|
||||
}, np)
|
||||
if err != nil {
|
||||
return opt, err
|
||||
|
|
|
@ -40,7 +40,7 @@ func newWorkerOpt(t *testing.T, processMode oci.ProcessMode) (base.WorkerOpt, fu
|
|||
},
|
||||
}
|
||||
rootless := false
|
||||
workerOpt, err := NewWorkerOpt(tmpdir, snFactory, rootless, processMode, nil, nil, netproviders.Opt{Mode: "host"}, nil, "")
|
||||
workerOpt, err := NewWorkerOpt(tmpdir, snFactory, rootless, processMode, nil, nil, netproviders.Opt{Mode: "host"}, nil, "", "")
|
||||
require.NoError(t, err)
|
||||
|
||||
return workerOpt, cleanup
|
||||
|
|
Loading…
Reference in New Issue