Skip to content

Commit

Permalink
Make SELinux labels opt-in (--oci-worker-selinux=<BOOL>)
Browse files Browse the repository at this point in the history
Fix issue 3202

Signed-off-by: Akihiro Suda <akihiro.suda.cz@hco.ntt.co.jp>
(cherry picked from commit bd57e5f)
(cherry-pick was not clean)
Signed-off-by: Akihiro Suda <akihiro.suda.cz@hco.ntt.co.jp>
  • Loading branch information
AkihiroSuda committed Nov 3, 2022
1 parent f6c40a4 commit 1e5948b
Showing 13 changed files with 63 additions and 22 deletions.
6 changes: 6 additions & 0 deletions cmd/buildkitd/config/config.go
Original file line number Diff line number Diff line change
@@ -81,6 +81,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"`
}
@@ -99,6 +102,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"`
9 changes: 8 additions & 1 deletion cmd/buildkitd/main_containerd_worker.go
Original file line number Diff line number Diff line change
@@ -99,6 +99,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"
@@ -217,6 +221,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
}
@@ -259,7 +266,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
}
10 changes: 9 additions & 1 deletion cmd/buildkitd/main_oci_worker.go
Original file line number Diff line number Diff line change
@@ -110,6 +110,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"
@@ -232,6 +236,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
}

@@ -290,7 +298,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
}
6 changes: 4 additions & 2 deletions executor/containerdexecutor/executor.go
Original file line number Diff line number Diff line change
@@ -41,12 +41,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"))
@@ -59,6 +60,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,
}
@@ -163,7 +165,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
}
4 changes: 2 additions & 2 deletions executor/oci/spec.go
Original file line number Diff line number Diff line change
@@ -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
15 changes: 12 additions & 3 deletions executor/oci/spec_unix.go
Original file line number Diff line number Diff line change
@@ -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
2 changes: 1 addition & 1 deletion executor/oci/spec_windows.go
Original file line number Diff line number Diff line change
@@ -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")
}
5 changes: 4 additions & 1 deletion executor/runcexecutor/executor.go
Original file line number Diff line number Diff line change
@@ -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
}
18 changes: 10 additions & 8 deletions worker/containerd/containerd.go
Original file line number Diff line number Diff line change
@@ -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
@@ -134,7 +136,7 @@ func newContainerd(root string, client *containerd.Client, snapshotterName, ns s
ID: id,
Labels: xlabels,
MetadataStore: md,
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),
2 changes: 1 addition & 1 deletion worker/containerd/containerd_test.go
Original file line number Diff line number Diff line change
@@ -33,7 +33,7 @@ func newWorkerOpt(t *testing.T, addr string) (base.WorkerOpt, func()) {
require.NoError(t, err)
cleanup := func() { os.RemoveAll(tmpdir) }
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, cleanup
}
1 change: 1 addition & 0 deletions worker/label/label.go
Original file line number Diff line number Diff line change
@@ -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
5 changes: 4 additions & 1 deletion worker/runc/runc.go
Original file line number Diff line number Diff line change
@@ -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
2 changes: 1 addition & 1 deletion worker/runc/runc_test.go
Original file line number Diff line number Diff line change
@@ -41,7 +41,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, "", "", nil, "", "")
workerOpt, err := NewWorkerOpt(tmpdir, snFactory, rootless, processMode, nil, nil, netproviders.Opt{Mode: "host"}, nil, "", "", false, nil, "", "")
require.NoError(t, err)

return workerOpt, cleanup

0 comments on commit 1e5948b

Please sign in to comment.