mirror of
https://github.com/moby/buildkit.git
synced 2026-11-06 05:16:45 +00:00
Make SELinux labels opt-in (--oci-worker-selinux=<BOOL>)
Fix issue 3202 Signed-off-by: Akihiro Suda <akihiro.suda.cz@hco.ntt.co.jp>
This commit is contained in:
13 files changed
+63
-22
No files matched your search
@@ -82,6 +82,9 @@ type OCIConfig struct {
|
||||
// The profile should already be loaded (by a higher level system) before creating a worker.
|
||||
ApparmorProfile string `toml:"apparmor-profile"`
|
||||
|
||||
// SELinux enables applying SELinux labels.
|
||||
SELinux bool `toml:"selinux"`
|
||||
|
||||
// MaxParallelism is the maximum number of parallel build steps that can be run at the same time.
|
||||
MaxParallelism int `toml:"max-parallelism"`
|
||||
}
|
||||
@@ -100,6 +103,9 @@ type ContainerdConfig struct {
|
||||
// The profile should already be loaded (by a higher level system) before creating a worker.
|
||||
ApparmorProfile string `toml:"apparmor-profile"`
|
||||
|
||||
// SELinux enables applying SELinux labels.
|
||||
SELinux bool `toml:"selinux"`
|
||||
|
||||
MaxParallelism int `toml:"max-parallelism"`
|
||||
|
||||
Rootless bool `toml:"rootless"`
|
||||
|
||||
@@ -104,6 +104,10 @@ func init() {
|
||||
Name: "containerd-worker-apparmor-profile",
|
||||
Usage: "set the name of the apparmor profile applied to containers",
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "containerd-worker-selinux",
|
||||
Usage: "apply SELinux labels",
|
||||
},
|
||||
}
|
||||
n := "containerd-worker-rootless"
|
||||
u := "enable rootless mode"
|
||||
@@ -225,6 +229,9 @@ func applyContainerdFlags(c *cli.Context, cfg *config.Config) error {
|
||||
if c.GlobalIsSet("containerd-worker-apparmor-profile") {
|
||||
cfg.Workers.Containerd.ApparmorProfile = c.GlobalString("containerd-worker-apparmor-profile")
|
||||
}
|
||||
if c.GlobalIsSet("containerd-worker-selinux") {
|
||||
cfg.Workers.Containerd.SELinux = c.GlobalBool("containerd-worker-selinux")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -268,7 +275,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.Rootless, cfg.Labels, dns, nc, common.config.Workers.Containerd.ApparmorProfile, parallelismSem, common.traceSocket, ctd.WithTimeout(60*time.Second))
|
||||
opt, err := containerd.NewWorkerOpt(common.config.Root, cfg.Address, snapshotter, cfg.Namespace, cfg.Rootless, cfg.Labels, dns, nc, common.config.Workers.Containerd.ApparmorProfile, common.config.Workers.Containerd.SELinux, parallelismSem, common.traceSocket, ctd.WithTimeout(60*time.Second))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -115,6 +115,10 @@ func init() {
|
||||
Name: "oci-worker-apparmor-profile",
|
||||
Usage: "set the name of the apparmor profile applied to containers",
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "oci-worker-selinux",
|
||||
Usage: "apply SELinux labels",
|
||||
},
|
||||
}
|
||||
n := "oci-worker-rootless"
|
||||
u := "enable rootless mode"
|
||||
@@ -240,6 +244,10 @@ func applyOCIFlags(c *cli.Context, cfg *config.Config) error {
|
||||
if c.GlobalIsSet("oci-worker-apparmor-profile") {
|
||||
cfg.Workers.OCI.ApparmorProfile = c.GlobalString("oci-worker-apparmor-profile")
|
||||
}
|
||||
if c.GlobalIsSet("oci-worker-selinux") {
|
||||
cfg.Workers.OCI.SELinux = c.GlobalBool("oci-worker-selinux")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -299,7 +307,7 @@ func ociWorkerInitializer(c *cli.Context, common workerInitializerOpt) ([]worker
|
||||
parallelismSem = semaphore.NewWeighted(int64(cfg.MaxParallelism))
|
||||
}
|
||||
|
||||
opt, err := runc.NewWorkerOpt(common.config.Root, snFactory, cfg.Rootless, processMode, cfg.Labels, idmapping, nc, dns, cfg.Binary, cfg.ApparmorProfile, parallelismSem, common.traceSocket, cfg.DefaultCgroupParent)
|
||||
opt, err := runc.NewWorkerOpt(common.config.Root, snFactory, cfg.Rootless, processMode, cfg.Labels, idmapping, nc, dns, cfg.Binary, cfg.ApparmorProfile, cfg.SELinux, parallelismSem, common.traceSocket, cfg.DefaultCgroupParent)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -40,12 +40,13 @@ type containerdExecutor struct {
|
||||
running map[string]chan error
|
||||
mu sync.Mutex
|
||||
apparmorProfile string
|
||||
selinux bool
|
||||
traceSocket string
|
||||
rootless bool
|
||||
}
|
||||
|
||||
// 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, apparmorProfile string, traceSocket string, rootless bool) executor.Executor {
|
||||
func New(client *containerd.Client, root, cgroup string, networkProviders map[pb.NetMode]network.Provider, dnsConfig *oci.DNSConfig, apparmorProfile string, selinux bool, traceSocket string, rootless bool) executor.Executor {
|
||||
// clean up old hosts/resolv.conf file. ignore errors
|
||||
os.RemoveAll(filepath.Join(root, "hosts"))
|
||||
os.RemoveAll(filepath.Join(root, "resolv.conf"))
|
||||
@@ -58,6 +59,7 @@ func New(client *containerd.Client, root, cgroup string, networkProviders map[pb
|
||||
dnsConfig: dnsConfig,
|
||||
running: make(map[string]chan error),
|
||||
apparmorProfile: apparmorProfile,
|
||||
selinux: selinux,
|
||||
traceSocket: traceSocket,
|
||||
rootless: rootless,
|
||||
}
|
||||
@@ -162,7 +164,7 @@ func (w *containerdExecutor) Run(ctx context.Context, id string, root executor.M
|
||||
}
|
||||
|
||||
processMode := oci.ProcessSandbox // FIXME(AkihiroSuda)
|
||||
spec, cleanup, err := oci.GenerateSpec(ctx, meta, mounts, id, resolvConf, hostsFile, namespace, w.cgroupParent, processMode, nil, w.apparmorProfile, w.traceSocket, opts...)
|
||||
spec, cleanup, err := oci.GenerateSpec(ctx, meta, mounts, id, resolvConf, hostsFile, namespace, w.cgroupParent, processMode, nil, w.apparmorProfile, w.selinux, w.traceSocket, opts...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -50,7 +50,7 @@ func (pm ProcessMode) String() string {
|
||||
|
||||
// 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, cgroupParent string, processMode ProcessMode, idmap *idtools.IdentityMapping, apparmorProfile string, tracingSocket string, 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, cgroupParent string, processMode ProcessMode, idmap *idtools.IdentityMapping, apparmorProfile string, selinuxB bool, tracingSocket string, opts ...oci.SpecOpts) (*specs.Spec, func(), error) {
|
||||
c := &containers.Container{
|
||||
ID: id,
|
||||
}
|
||||
@@ -81,7 +81,7 @@ func GenerateSpec(ctx context.Context, meta executor.Meta, mounts []executor.Mou
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
if securityOpts, err := generateSecurityOpts(meta.SecurityMode, apparmorProfile); err == nil {
|
||||
if securityOpts, err := generateSecurityOpts(meta.SecurityMode, apparmorProfile, selinuxB); err == nil {
|
||||
opts = append(opts, securityOpts...)
|
||||
} else {
|
||||
return nil, nil, err
|
||||
|
||||
@@ -16,7 +16,9 @@ import (
|
||||
"github.com/moby/buildkit/solver/pb"
|
||||
"github.com/moby/buildkit/util/entitlements/security"
|
||||
specs "github.com/opencontainers/runtime-spec/specs-go"
|
||||
selinux "github.com/opencontainers/selinux/go-selinux"
|
||||
"github.com/opencontainers/selinux/go-selinux/label"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
func generateMountOpts(resolvConf, hostsFile string) ([]oci.SpecOpts, error) {
|
||||
@@ -30,7 +32,10 @@ func generateMountOpts(resolvConf, hostsFile string) ([]oci.SpecOpts, error) {
|
||||
}
|
||||
|
||||
// generateSecurityOpts may affect mounts, so must be called after generateMountOpts
|
||||
func generateSecurityOpts(mode pb.SecurityMode, apparmorProfile string) (opts []oci.SpecOpts, _ error) {
|
||||
func generateSecurityOpts(mode pb.SecurityMode, apparmorProfile string, selinuxB bool) (opts []oci.SpecOpts, _ error) {
|
||||
if selinuxB && !selinux.GetEnabled() {
|
||||
return nil, errors.New("selinux is not available")
|
||||
}
|
||||
switch mode {
|
||||
case pb.SecurityMode_INSECURE:
|
||||
return []oci.SpecOpts{
|
||||
@@ -39,7 +44,9 @@ func generateSecurityOpts(mode pb.SecurityMode, apparmorProfile string) (opts []
|
||||
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"})
|
||||
if selinuxB {
|
||||
s.Process.SelinuxLabel, s.Linux.MountLabel, err = label.InitLabels([]string{"disable"})
|
||||
}
|
||||
return err
|
||||
},
|
||||
}, nil
|
||||
@@ -52,7 +59,9 @@ func generateSecurityOpts(mode pb.SecurityMode, apparmorProfile string) (opts []
|
||||
}
|
||||
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)
|
||||
if selinuxB {
|
||||
s.Process.SelinuxLabel, s.Linux.MountLabel, err = label.InitLabels(nil)
|
||||
}
|
||||
return err
|
||||
})
|
||||
return opts, nil
|
||||
|
||||
@@ -15,7 +15,7 @@ func generateMountOpts(resolvConf, hostsFile string) ([]oci.SpecOpts, error) {
|
||||
}
|
||||
|
||||
// generateSecurityOpts may affect mounts, so must be called after generateMountOpts
|
||||
func generateSecurityOpts(mode pb.SecurityMode, apparmorProfile string) ([]oci.SpecOpts, error) {
|
||||
func generateSecurityOpts(mode pb.SecurityMode, apparmorProfile string, selinuxB bool) ([]oci.SpecOpts, error) {
|
||||
if mode == pb.SecurityMode_INSECURE {
|
||||
return nil, errors.New("no support for running in insecure mode on Windows")
|
||||
}
|
||||
|
||||
@@ -48,6 +48,7 @@ type Opt struct {
|
||||
DNS *oci.DNSConfig
|
||||
OOMScoreAdj *int
|
||||
ApparmorProfile string
|
||||
SELinux bool
|
||||
TracingSocket string
|
||||
}
|
||||
|
||||
@@ -67,6 +68,7 @@ type runcExecutor struct {
|
||||
running map[string]chan error
|
||||
mu sync.Mutex
|
||||
apparmorProfile string
|
||||
selinux bool
|
||||
tracingSocket string
|
||||
}
|
||||
|
||||
@@ -131,6 +133,7 @@ func New(opt Opt, networkProviders map[pb.NetMode]network.Provider) (executor.Ex
|
||||
oomScoreAdj: opt.OOMScoreAdj,
|
||||
running: make(map[string]chan error),
|
||||
apparmorProfile: opt.ApparmorProfile,
|
||||
selinux: opt.SELinux,
|
||||
tracingSocket: opt.TracingSocket,
|
||||
}
|
||||
return w, nil
|
||||
@@ -251,7 +254,7 @@ func (w *runcExecutor) Run(ctx context.Context, id string, root executor.Mount,
|
||||
}
|
||||
}
|
||||
|
||||
spec, cleanup, err := oci.GenerateSpec(ctx, meta, mounts, id, resolvConf, hostsFile, namespace, w.cgroupParent, w.processMode, w.idmap, w.apparmorProfile, w.tracingSocket, opts...)
|
||||
spec, cleanup, err := oci.GenerateSpec(ctx, meta, mounts, id, resolvConf, hostsFile, namespace, w.cgroupParent, w.processMode, w.idmap, w.apparmorProfile, w.selinux, w.tracingSocket, opts...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/containerd/containerd"
|
||||
@@ -26,16 +27,16 @@ import (
|
||||
)
|
||||
|
||||
// NewWorkerOpt creates a WorkerOpt.
|
||||
func NewWorkerOpt(root string, address, snapshotterName, ns string, rootless bool, labels map[string]string, dns *oci.DNSConfig, nopt netproviders.Opt, apparmorProfile string, parallelismSem *semaphore.Weighted, traceSocket string, opts ...containerd.ClientOpt) (base.WorkerOpt, error) {
|
||||
func NewWorkerOpt(root string, address, snapshotterName, ns string, rootless bool, labels map[string]string, dns *oci.DNSConfig, nopt netproviders.Opt, apparmorProfile string, selinux bool, parallelismSem *semaphore.Weighted, traceSocket 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, rootless, labels, dns, nopt, apparmorProfile, parallelismSem, traceSocket)
|
||||
return newContainerd(root, client, snapshotterName, ns, rootless, labels, dns, nopt, apparmorProfile, selinux, parallelismSem, traceSocket)
|
||||
}
|
||||
|
||||
func newContainerd(root string, client *containerd.Client, snapshotterName, ns string, rootless bool, labels map[string]string, dns *oci.DNSConfig, nopt netproviders.Opt, apparmorProfile string, parallelismSem *semaphore.Weighted, traceSocket string) (base.WorkerOpt, error) {
|
||||
func newContainerd(root string, client *containerd.Client, snapshotterName, ns string, rootless bool, labels map[string]string, dns *oci.DNSConfig, nopt netproviders.Opt, apparmorProfile string, selinux bool, parallelismSem *semaphore.Weighted, traceSocket string) (base.WorkerOpt, error) {
|
||||
if strings.Contains(snapshotterName, "/") {
|
||||
return base.WorkerOpt{}, errors.Errorf("bad snapshotter name: %q", snapshotterName)
|
||||
}
|
||||
@@ -67,10 +68,11 @@ func newContainerd(root string, client *containerd.Client, snapshotterName, ns s
|
||||
hostname = "unknown"
|
||||
}
|
||||
xlabels := map[string]string{
|
||||
wlabel.Executor: "containerd",
|
||||
wlabel.Snapshotter: snapshotterName,
|
||||
wlabel.Hostname: hostname,
|
||||
wlabel.Network: npResolvedMode,
|
||||
wlabel.Executor: "containerd",
|
||||
wlabel.Snapshotter: snapshotterName,
|
||||
wlabel.Hostname: hostname,
|
||||
wlabel.Network: npResolvedMode,
|
||||
wlabel.SELinuxEnabled: strconv.FormatBool(selinux),
|
||||
}
|
||||
if apparmorProfile != "" {
|
||||
xlabels[wlabel.ApparmorProfile] = apparmorProfile
|
||||
@@ -135,7 +137,7 @@ func newContainerd(root string, client *containerd.Client, snapshotterName, ns s
|
||||
Labels: xlabels,
|
||||
MetadataStore: md,
|
||||
NetworkProviders: np,
|
||||
Executor: containerdexecutor.New(client, root, "", np, dns, apparmorProfile, traceSocket, rootless),
|
||||
Executor: containerdexecutor.New(client, root, "", np, dns, apparmorProfile, selinux, traceSocket, rootless),
|
||||
Snapshotter: snap,
|
||||
ContentStore: cs,
|
||||
Applier: winlayers.NewFileSystemApplierWithWindows(cs, df),
|
||||
|
||||
@@ -30,7 +30,7 @@ func TestContainerdWorkerIntegration(t *testing.T) {
|
||||
func newWorkerOpt(t *testing.T, addr string) base.WorkerOpt {
|
||||
tmpdir := t.TempDir()
|
||||
rootless := false
|
||||
workerOpt, err := NewWorkerOpt(tmpdir, addr, "overlayfs", "buildkit-test", rootless, nil, nil, netproviders.Opt{Mode: "host"}, "", nil, "")
|
||||
workerOpt, err := NewWorkerOpt(tmpdir, addr, "overlayfs", "buildkit-test", rootless, nil, nil, netproviders.Opt{Mode: "host"}, "", false, nil, "")
|
||||
require.NoError(t, err)
|
||||
return workerOpt
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ const (
|
||||
Hostname = prefix + "hostname"
|
||||
Network = prefix + "network" // "cni" or "host"
|
||||
ApparmorProfile = prefix + "apparmor.profile"
|
||||
SELinuxEnabled = prefix + "selinux.enabled" // "true" or "false"
|
||||
OCIProcessMode = prefix + "oci.process-mode" // OCI worker: process mode ("sandbox", "no-sandbox")
|
||||
ContainerdUUID = prefix + "containerd.uuid" // containerd worker: containerd UUID
|
||||
ContainerdNamespace = prefix + "containerd.namespace" // containerd worker: containerd namespace
|
||||
|
||||
+4
-1
@@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
|
||||
"github.com/containerd/containerd/content/local"
|
||||
"github.com/containerd/containerd/diff/apply"
|
||||
@@ -34,7 +35,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, apparmorProfile string, parallelismSem *semaphore.Weighted, traceSocket, defaultCgroupParent 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, selinux bool, parallelismSem *semaphore.Weighted, traceSocket, defaultCgroupParent string) (base.WorkerOpt, error) {
|
||||
var opt base.WorkerOpt
|
||||
name := "runc-" + snFactory.Name
|
||||
root = filepath.Join(root, name)
|
||||
@@ -65,6 +66,7 @@ func NewWorkerOpt(root string, snFactory SnapshotterFactory, rootless bool, proc
|
||||
IdentityMapping: idmap,
|
||||
DNS: dns,
|
||||
ApparmorProfile: apparmorProfile,
|
||||
SELinux: selinux,
|
||||
TracingSocket: traceSocket,
|
||||
DefaultCgroupParent: defaultCgroupParent,
|
||||
}, np)
|
||||
@@ -109,6 +111,7 @@ func NewWorkerOpt(root string, snFactory SnapshotterFactory, rootless bool, proc
|
||||
wlabel.Hostname: hostname,
|
||||
wlabel.Network: npResolvedMode,
|
||||
wlabel.OCIProcessMode: processMode.String(),
|
||||
wlabel.SELinuxEnabled: strconv.FormatBool(selinux),
|
||||
}
|
||||
if apparmorProfile != "" {
|
||||
xlabels[wlabel.ApparmorProfile] = apparmorProfile
|
||||
|
||||
@@ -38,7 +38,7 @@ func newWorkerOpt(t *testing.T, processMode oci.ProcessMode) base.WorkerOpt {
|
||||
},
|
||||
}
|
||||
rootless := false
|
||||
workerOpt, err := NewWorkerOpt(tmpdir, snFactory, rootless, processMode, nil, nil, netproviders.Opt{Mode: "host"}, nil, "", "", nil, "", "")
|
||||
workerOpt, err := NewWorkerOpt(tmpdir, snFactory, rootless, processMode, nil, nil, netproviders.Opt{Mode: "host"}, nil, "", "", false, nil, "", "")
|
||||
require.NoError(t, err)
|
||||
|
||||
return workerOpt
|
||||
|
||||
Reference in new issue
Block a user