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>
This commit is contained in:
Daniel J Walsh
2020-02-27 14:19:07 -04:00
parent 47c4ea3919
commit b163640c61
11 changed files with 230 additions and 262 deletions

View File

@ -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" {