diff options
author | Daniel J Walsh <dwalsh@redhat.com> | 2020-02-27 14:19:07 -0400 |
---|---|---|
committer | Daniel J Walsh <dwalsh@redhat.com> | 2020-03-02 16:37:32 -0500 |
commit | b163640c61dcb10953949a1ee28599d8a19fd046 (patch) | |
tree | e7b56307cc2778c6cab81f658515ea145d990979 /pkg/spec | |
parent | 47c4ea39196cedac87e7a4e4c1ead54ed9d7ed50 (diff) | |
download | podman-b163640c61dcb10953949a1ee28599d8a19fd046.tar.gz podman-b163640c61dcb10953949a1ee28599d8a19fd046.tar.bz2 podman-b163640c61dcb10953949a1ee28599d8a19fd046.zip |
Allow devs to set labels in container images for default capabilities.
This patch allows users to specify the list of capabilities required
to run their container image.
Setting a image/container label "io.containers.capabilities=setuid,setgid"
tells podman that the contained image should work fine with just these two
capabilties, instead of running with the default capabilities, podman will
launch the container with just these capabilties.
If the user or image specified capabilities that are not in the default set,
the container will print an error message and will continue to run with the
default capabilities.
Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
Diffstat (limited to 'pkg/spec')
-rw-r--r-- | pkg/spec/createconfig.go | 1 | ||||
-rw-r--r-- | pkg/spec/security.go | 45 | ||||
-rw-r--r-- | pkg/spec/spec.go | 14 |
3 files changed, 49 insertions, 11 deletions
diff --git a/pkg/spec/createconfig.go b/pkg/spec/createconfig.go index 02678a687..1d9633bb3 100644 --- a/pkg/spec/createconfig.go +++ b/pkg/spec/createconfig.go @@ -112,6 +112,7 @@ type NetworkConfig struct { type SecurityConfig struct { CapAdd []string // cap-add CapDrop []string // cap-drop + CapRequired []string // cap-required LabelOpts []string //SecurityOpts NoNewPrivs bool //SecurityOpts ApparmorProfile string //SecurityOpts diff --git a/pkg/spec/security.go b/pkg/spec/security.go index 3bad9f97a..ca025eb3e 100644 --- a/pkg/spec/security.go +++ b/pkg/spec/security.go @@ -4,11 +4,13 @@ import ( "fmt" "strings" + "github.com/containers/common/pkg/capabilities" "github.com/containers/libpod/libpod" - "github.com/containers/libpod/pkg/capabilities" + "github.com/containers/libpod/pkg/util" "github.com/opencontainers/runtime-tools/generate" "github.com/opencontainers/selinux/go-selinux/label" "github.com/pkg/errors" + "github.com/sirupsen/logrus" ) // ToCreateOptions convert the SecurityConfig to a slice of container create @@ -113,28 +115,49 @@ func (c *SecurityConfig) ConfigureGenerator(g *generate.Generator, user *UserCon configSpec := g.Config var err error - var caplist []string + var defaultCaplist []string bounding := configSpec.Process.Capabilities.Bounding if useNotRoot(user.User) { - configSpec.Process.Capabilities.Bounding = caplist + configSpec.Process.Capabilities.Bounding = defaultCaplist } - caplist, err = capabilities.MergeCapabilities(configSpec.Process.Capabilities.Bounding, c.CapAdd, c.CapDrop) + defaultCaplist, err = capabilities.MergeCapabilities(configSpec.Process.Capabilities.Bounding, c.CapAdd, c.CapDrop) if err != nil { return err } - configSpec.Process.Capabilities.Bounding = caplist - configSpec.Process.Capabilities.Permitted = caplist - configSpec.Process.Capabilities.Inheritable = caplist - configSpec.Process.Capabilities.Effective = caplist - configSpec.Process.Capabilities.Ambient = caplist + privCapRequired := []string{} + + if !c.Privileged && len(c.CapRequired) > 0 { + // Pass CapRequired in CapAdd field to normalize capabilties names + capRequired, err := capabilities.MergeCapabilities(nil, c.CapRequired, nil) + if err != nil { + logrus.Errorf("capabilties requested by user or image are not valid: %q", strings.Join(c.CapRequired, ",")) + } else { + // Verify all capRequiered are in the defaultCapList + for _, cap := range capRequired { + if !util.StringInSlice(cap, defaultCaplist) { + privCapRequired = append(privCapRequired, cap) + } + } + } + if len(privCapRequired) == 0 { + defaultCaplist = capRequired + } else { + logrus.Errorf("capabilties requested by user or image are not allowed by default: %q", strings.Join(privCapRequired, ",")) + } + } + configSpec.Process.Capabilities.Bounding = defaultCaplist + configSpec.Process.Capabilities.Permitted = defaultCaplist + configSpec.Process.Capabilities.Inheritable = defaultCaplist + configSpec.Process.Capabilities.Effective = defaultCaplist + configSpec.Process.Capabilities.Ambient = defaultCaplist if useNotRoot(user.User) { - caplist, err = capabilities.MergeCapabilities(bounding, c.CapAdd, c.CapDrop) + defaultCaplist, err = capabilities.MergeCapabilities(bounding, c.CapAdd, c.CapDrop) if err != nil { return err } } - configSpec.Process.Capabilities.Bounding = caplist + configSpec.Process.Capabilities.Bounding = defaultCaplist // HANDLE SECCOMP if c.SeccompProfilePath != "unconfined" { diff --git a/pkg/spec/spec.go b/pkg/spec/spec.go index a4ae22efd..0e5c3f429 100644 --- a/pkg/spec/spec.go +++ b/pkg/spec/spec.go @@ -3,12 +3,14 @@ package createconfig import ( "strings" + "github.com/containers/common/pkg/capabilities" "github.com/containers/libpod/libpod" libpodconfig "github.com/containers/libpod/libpod/config" "github.com/containers/libpod/libpod/define" "github.com/containers/libpod/pkg/cgroups" "github.com/containers/libpod/pkg/rootless" "github.com/containers/libpod/pkg/sysinfo" + "github.com/containers/libpod/pkg/util" "github.com/docker/go-units" "github.com/opencontainers/runc/libcontainer/user" spec "github.com/opencontainers/runtime-spec/specs-go" @@ -327,6 +329,18 @@ func (config *CreateConfig) createConfigToOCISpec(runtime *libpod.Runtime, userM } configSpec := g.Config + // If the container image specifies an label with a + // capabilities.ContainerImageLabel then split the comma separated list + // of capabilities and record them. This list indicates the only + // capabilities, required to run the container. + var capRequired []string + for key, val := range config.Labels { + if util.StringInSlice(key, capabilities.ContainerImageLabels) { + capRequired = strings.Split(val, ",") + } + } + config.Security.CapRequired = capRequired + if err := config.Security.ConfigureGenerator(&g, &config.User); err != nil { return nil, err } |