Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[0.10 backport] Make SELinux labels opt-in (--oci-worker-selinux=<BOOL>) #3255

Merged
merged 2 commits into from
Nov 10, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions cmd/buildkitd/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"`
}
Expand All @@ -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"`
Expand Down
9 changes: 8 additions & 1 deletion cmd/buildkitd/main_containerd_worker.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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
}
Expand Down Expand Up @@ -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
}
Expand Down
10 changes: 9 additions & 1 deletion cmd/buildkitd/main_oci_worker.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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
}

Expand Down Expand Up @@ -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
}
Expand Down
6 changes: 4 additions & 2 deletions executor/containerdexecutor/executor.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"))
Expand All @@ -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,
}
Expand Down Expand Up @@ -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
}
Expand Down
4 changes: 2 additions & 2 deletions executor/oci/spec.go
Original file line number Diff line number Diff line change
Expand Up @@ -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,
}
Expand Down Expand Up @@ -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
Expand Down
15 changes: 12 additions & 3 deletions executor/oci/spec_unix.go
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -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{
Expand All @@ -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
Expand All @@ -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
Expand Down
2 changes: 1 addition & 1 deletion executor/oci/spec_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -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")
}
Expand Down
5 changes: 4 additions & 1 deletion executor/runcexecutor/executor.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ type Opt struct {
DNS *oci.DNSConfig
OOMScoreAdj *int
ApparmorProfile string
SELinux bool
TracingSocket string
}

Expand All @@ -67,6 +68,7 @@ type runcExecutor struct {
running map[string]chan error
mu sync.Mutex
apparmorProfile string
selinux bool
tracingSocket string
}

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
}
Expand Down
26 changes: 14 additions & 12 deletions worker/containerd/containerd.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"context"
"os"
"path/filepath"
"strconv"
"strings"

"github.com/containerd/containerd"
Expand All @@ -18,24 +19,24 @@ import (
"github.com/moby/buildkit/util/leaseutil"
"github.com/moby/buildkit/util/network/netproviders"
"github.com/moby/buildkit/util/winlayers"
"github.com/moby/buildkit/worker"
"github.com/moby/buildkit/worker/base"
wlabel "github.com/moby/buildkit/worker/label"
ocispecs "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/pkg/errors"
"golang.org/x/sync/semaphore"
)

// 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)
}
Expand Down Expand Up @@ -67,16 +68,17 @@ func newContainerd(root string, client *containerd.Client, snapshotterName, ns s
hostname = "unknown"
}
xlabels := map[string]string{
worker.LabelExecutor: "containerd",
worker.LabelSnapshotter: snapshotterName,
worker.LabelHostname: hostname,
worker.LabelNetwork: npResolvedMode,
wlabel.Executor: "containerd",
wlabel.Snapshotter: snapshotterName,
wlabel.Hostname: hostname,
wlabel.Network: npResolvedMode,
wlabel.SELinuxEnabled: strconv.FormatBool(selinux),
}
if apparmorProfile != "" {
xlabels[worker.LabelApparmorProfile] = apparmorProfile
xlabels[wlabel.ApparmorProfile] = apparmorProfile
}
xlabels[worker.LabelContainerdNamespace] = ns
xlabels[worker.LabelContainerdUUID] = serverInfo.UUID
xlabels[wlabel.ContainerdNamespace] = ns
xlabels[wlabel.ContainerdUUID] = serverInfo.UUID
for k, v := range labels {
xlabels[k] = v
}
Expand Down Expand Up @@ -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),
Expand Down
2 changes: 1 addition & 1 deletion worker/containerd/containerd_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down
16 changes: 16 additions & 0 deletions worker/label/label.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package label

// Pre-defined label keys
const (
prefix = "org.mobyproject.buildkit.worker."

Executor = prefix + "executor" // "oci" or "containerd"
Snapshotter = prefix + "snapshotter" // containerd snapshotter name ("overlay", "native", ...)
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
)
19 changes: 11 additions & 8 deletions worker/runc/runc.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"context"
"os"
"path/filepath"
"strconv"

"github.com/containerd/containerd/content/local"
"github.com/containerd/containerd/diff/apply"
Expand All @@ -20,8 +21,8 @@ import (
"github.com/moby/buildkit/util/leaseutil"
"github.com/moby/buildkit/util/network/netproviders"
"github.com/moby/buildkit/util/winlayers"
"github.com/moby/buildkit/worker"
"github.com/moby/buildkit/worker/base"
wlabel "github.com/moby/buildkit/worker/label"
ocispecs "github.com/opencontainers/image-spec/specs-go/v1"
bolt "go.etcd.io/bbolt"
"golang.org/x/sync/semaphore"
Expand All @@ -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)
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -104,14 +106,15 @@ func NewWorkerOpt(root string, snFactory SnapshotterFactory, rootless bool, proc
hostname = "unknown"
}
xlabels := map[string]string{
worker.LabelExecutor: "oci",
worker.LabelSnapshotter: snFactory.Name,
worker.LabelHostname: hostname,
worker.LabelNetwork: npResolvedMode,
worker.LabelOCIProcessMode: processMode.String(),
wlabel.Executor: "oci",
wlabel.Snapshotter: snFactory.Name,
wlabel.Hostname: hostname,
wlabel.Network: npResolvedMode,
wlabel.OCIProcessMode: processMode.String(),
wlabel.SELinuxEnabled: strconv.FormatBool(selinux),
}
if apparmorProfile != "" {
xlabels[worker.LabelApparmorProfile] = apparmorProfile
xlabels[wlabel.ApparmorProfile] = apparmorProfile
}

for k, v := range labels {
Expand Down
2 changes: 1 addition & 1 deletion worker/runc/runc_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
13 changes: 0 additions & 13 deletions worker/worker.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,16 +41,3 @@ type Infos interface {
GetDefault() (Worker, error)
WorkerInfos() []client.WorkerInfo
}

// Pre-defined label keys
const (
labelPrefix = "org.mobyproject.buildkit.worker."
LabelExecutor = labelPrefix + "executor" // "oci" or "containerd"
LabelSnapshotter = labelPrefix + "snapshotter" // containerd snapshotter name ("overlay", "native", ...)
LabelHostname = labelPrefix + "hostname"
LabelNetwork = labelPrefix + "network" // "cni" or "host"
LabelApparmorProfile = labelPrefix + "apparmor.profile"
LabelOCIProcessMode = labelPrefix + "oci.process-mode" // OCI worker: process mode ("sandbox", "no-sandbox")
LabelContainerdUUID = labelPrefix + "containerd.uuid" // containerd worker: containerd UUID
LabelContainerdNamespace = labelPrefix + "containerd.namespace" // containerd worker: containerd namespace
)