mirror of
https://github.com/containers/podman.git
synced 2025-05-21 17:16:22 +08:00
Parse SecurityOpts
This should turn on handling of SELinux, NoNewPrivs, seccomp and Apparmor Signed-off-by: Daniel J Walsh <dwalsh@redhat.com> Closes: #15 Approved by: rhatdan
This commit is contained in:

committed by
Atomic Bot

parent
79a26cbd6d
commit
098389dc3e
@ -2,9 +2,12 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"os"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/docker/go-units"
|
"github.com/docker/go-units"
|
||||||
|
"github.com/opencontainers/selinux/go-selinux/label"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"github.com/projectatomic/libpod/libpod"
|
"github.com/projectatomic/libpod/libpod"
|
||||||
"github.com/urfave/cli"
|
"github.com/urfave/cli"
|
||||||
@ -94,7 +97,6 @@ type createConfig struct {
|
|||||||
readOnlyRootfs bool //read-only
|
readOnlyRootfs bool //read-only
|
||||||
resources createResourceConfig
|
resources createResourceConfig
|
||||||
rm bool //rm
|
rm bool //rm
|
||||||
securityOpts []string //security-opt
|
|
||||||
sigProxy bool //sig-proxy
|
sigProxy bool //sig-proxy
|
||||||
stopSignal string // stop-signal
|
stopSignal string // stop-signal
|
||||||
stopTimeout int64 // stop-timeout
|
stopTimeout int64 // stop-timeout
|
||||||
@ -107,6 +109,11 @@ type createConfig struct {
|
|||||||
volumes []string //volume
|
volumes []string //volume
|
||||||
volumesFrom []string //volumes-from
|
volumesFrom []string //volumes-from
|
||||||
workDir string //workdir
|
workDir string //workdir
|
||||||
|
mountLabel string //SecurityOpts
|
||||||
|
processLabel string //SecurityOpts
|
||||||
|
noNewPrivileges bool //SecurityOpts
|
||||||
|
apparmorProfile string //SecurityOpts
|
||||||
|
seccompProfilePath string //SecurityOpts
|
||||||
}
|
}
|
||||||
|
|
||||||
var createDescription = "Creates a new container from the given image or" +
|
var createDescription = "Creates a new container from the given image or" +
|
||||||
@ -169,6 +176,7 @@ func createCmd(c *cli.Context) error {
|
|||||||
}
|
}
|
||||||
// Gather up the options for NewContainer which consist of With... funcs
|
// Gather up the options for NewContainer which consist of With... funcs
|
||||||
options = append(options, libpod.WithRootFSFromImage(imageID, imageName, false))
|
options = append(options, libpod.WithRootFSFromImage(imageID, imageName, false))
|
||||||
|
options = append(options, libpod.WithSELinuxMountLabel(createConfig.mountLabel))
|
||||||
ctr, err := runtime.NewContainer(runtimeSpec, options...)
|
ctr, err := runtime.NewContainer(runtimeSpec, options...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -183,6 +191,49 @@ func createCmd(c *cli.Context) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const seccompDefaultPath = "/etc/crio/seccomp.json"
|
||||||
|
|
||||||
|
func parseSecurityOpt(config *createConfig, securityOpts []string) error {
|
||||||
|
var (
|
||||||
|
labelOpts []string
|
||||||
|
err error
|
||||||
|
)
|
||||||
|
|
||||||
|
for _, opt := range securityOpts {
|
||||||
|
if opt == "no-new-privileges" {
|
||||||
|
config.noNewPrivileges = true
|
||||||
|
} else {
|
||||||
|
con := strings.SplitN(opt, "=", 2)
|
||||||
|
if len(con) != 2 {
|
||||||
|
return fmt.Errorf("Invalid --security-opt 1: %q", opt)
|
||||||
|
}
|
||||||
|
|
||||||
|
switch con[0] {
|
||||||
|
case "label":
|
||||||
|
labelOpts = append(labelOpts, con[1])
|
||||||
|
case "apparmor":
|
||||||
|
config.apparmorProfile = con[1]
|
||||||
|
case "seccomp":
|
||||||
|
config.seccompProfilePath = con[1]
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("Invalid --security-opt 2: %q", opt)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if config.seccompProfilePath == "" {
|
||||||
|
if _, err := os.Stat(seccompDefaultPath); err != nil {
|
||||||
|
if !os.IsNotExist(err) {
|
||||||
|
return errors.Wrapf(err, "can't check if %q exists", seccompDefaultPath)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
config.seccompProfilePath = seccompDefaultPath
|
||||||
|
}
|
||||||
|
}
|
||||||
|
config.processLabel, config.mountLabel, err = label.InitLabels(labelOpts)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
// Parses CLI options related to container creation into a config which can be
|
// Parses CLI options related to container creation into a config which can be
|
||||||
// parsed into an OCI runtime spec
|
// parsed into an OCI runtime spec
|
||||||
func parseCreateOpts(c *cli.Context, runtime *libpod.Runtime) (*createConfig, error) {
|
func parseCreateOpts(c *cli.Context, runtime *libpod.Runtime) (*createConfig, error) {
|
||||||
@ -324,7 +375,6 @@ func parseCreateOpts(c *cli.Context, runtime *libpod.Runtime) (*createConfig, er
|
|||||||
ulimit: c.StringSlice("ulimit"),
|
ulimit: c.StringSlice("ulimit"),
|
||||||
},
|
},
|
||||||
rm: c.Bool("rm"),
|
rm: c.Bool("rm"),
|
||||||
securityOpts: c.StringSlice("security-opt"),
|
|
||||||
sigProxy: c.Bool("sig-proxy"),
|
sigProxy: c.Bool("sig-proxy"),
|
||||||
stopSignal: c.String("stop-signal"),
|
stopSignal: c.String("stop-signal"),
|
||||||
stopTimeout: c.Int64("stop-timeout"),
|
stopTimeout: c.Int64("stop-timeout"),
|
||||||
@ -339,5 +389,11 @@ func parseCreateOpts(c *cli.Context, runtime *libpod.Runtime) (*createConfig, er
|
|||||||
workDir: c.String("workdir"),
|
workDir: c.String("workdir"),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !config.privileged {
|
||||||
|
if err := parseSecurityOpt(config, c.StringSlice("security-opt")); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return config, nil
|
return config, nil
|
||||||
}
|
}
|
||||||
|
@ -69,6 +69,7 @@ func runCmd(c *cli.Context) error {
|
|||||||
}
|
}
|
||||||
// Gather up the options for NewContainer which consist of With... funcs
|
// Gather up the options for NewContainer which consist of With... funcs
|
||||||
options = append(options, libpod.WithRootFSFromImage(imageID, imageName, false))
|
options = append(options, libpod.WithRootFSFromImage(imageID, imageName, false))
|
||||||
|
options = append(options, libpod.WithSELinuxMountLabel(createConfig.mountLabel))
|
||||||
ctr, err := runtime.NewContainer(runtimeSpec, options...)
|
ctr, err := runtime.NewContainer(runtimeSpec, options...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
spec "github.com/opencontainers/runtime-spec/specs-go"
|
spec "github.com/opencontainers/runtime-spec/specs-go"
|
||||||
@ -91,16 +93,30 @@ func createConfigToOCISpec(config *createConfig) (*spec.Spec, error) {
|
|||||||
configSpec.Linux.Resources.Pids.Limit = config.resources.pidsLimit
|
configSpec.Linux.Resources.Pids.Limit = config.resources.pidsLimit
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SECURITY OPTS
|
||||||
|
configSpec.Process.NoNewPrivileges = config.noNewPrivileges
|
||||||
|
configSpec.Process.ApparmorProfile = config.apparmorProfile
|
||||||
|
configSpec.Process.SelinuxLabel = config.processLabel
|
||||||
|
configSpec.Linux.MountLabel = config.mountLabel
|
||||||
|
if config.seccompProfilePath != "" && config.seccompProfilePath != "unconfined" {
|
||||||
|
seccompProfile, err := ioutil.ReadFile(config.seccompProfilePath)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrapf(err, "opening seccomp profile (%s) failed", config.seccompProfilePath)
|
||||||
|
}
|
||||||
|
var seccompConfig spec.LinuxSeccomp
|
||||||
|
if err := json.Unmarshal(seccompProfile, &seccompConfig); err != nil {
|
||||||
|
return nil, errors.Wrapf(err, "decoding seccomp profile (%s) failed", config.seccompProfilePath)
|
||||||
|
}
|
||||||
|
configSpec.Linux.Seccomp = &seccompConfig
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Capabilities: &configSpec.LinuxCapabilities{
|
Capabilities: &configSpec.LinuxCapabilities{
|
||||||
// Rlimits []PosixRlimit // Where does this come from
|
// Rlimits []PosixRlimit // Where does this come from
|
||||||
// Type string
|
// Type string
|
||||||
// Hard uint64
|
// Hard uint64
|
||||||
// Limit uint64
|
// Limit uint64
|
||||||
// NoNewPrivileges bool // No user input for this
|
|
||||||
// ApparmorProfile string // No user input for this
|
|
||||||
OOMScoreAdj: &config.resources.oomScoreAdj,
|
OOMScoreAdj: &config.resources.oomScoreAdj,
|
||||||
// Selinuxlabel
|
|
||||||
},
|
},
|
||||||
Hooks: &configSpec.Hooks{},
|
Hooks: &configSpec.Hooks{},
|
||||||
//Annotations
|
//Annotations
|
||||||
@ -116,7 +132,6 @@ func createConfigToOCISpec(config *createConfig) (*spec.Spec, error) {
|
|||||||
//CgroupsPath:
|
//CgroupsPath:
|
||||||
//Namespaces: []LinuxNamespace
|
//Namespaces: []LinuxNamespace
|
||||||
//Devices
|
//Devices
|
||||||
Seccomp: &configSpec.LinuxSeccomp{
|
|
||||||
// DefaultAction:
|
// DefaultAction:
|
||||||
// Architectures
|
// Architectures
|
||||||
// Syscalls:
|
// Syscalls:
|
||||||
|
@ -95,6 +95,7 @@ type containerConfig struct {
|
|||||||
// Information on the image used for the root filesystem
|
// Information on the image used for the root filesystem
|
||||||
RootfsImageID string `json:"rootfsImageID,omitempty"`
|
RootfsImageID string `json:"rootfsImageID,omitempty"`
|
||||||
RootfsImageName string `json:"rootfsImageName,omitempty"`
|
RootfsImageName string `json:"rootfsImageName,omitempty"`
|
||||||
|
MountLabel string `json:"MountLabel,omitempty"`
|
||||||
UseImageConfig bool `json:"useImageConfig"`
|
UseImageConfig bool `json:"useImageConfig"`
|
||||||
// Whether to keep container STDIN open
|
// Whether to keep container STDIN open
|
||||||
Stdin bool
|
Stdin bool
|
||||||
@ -223,8 +224,7 @@ func (c *Container) setupImageRootfs() error {
|
|||||||
return errors.Wrapf(ErrInvalidArg, "must provide image ID and image name to use an image")
|
return errors.Wrapf(ErrInvalidArg, "must provide image ID and image name to use an image")
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO SELinux mount label
|
containerInfo, err := c.runtime.storageService.CreateContainerStorage(c.runtime.imageContext, c.config.RootfsImageName, c.config.RootfsImageID, c.config.Name, c.config.ID, c.config.MountLabel)
|
||||||
containerInfo, err := c.runtime.storageService.CreateContainerStorage(c.runtime.imageContext, c.config.RootfsImageName, c.config.RootfsImageID, c.config.Name, c.config.ID, "")
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrapf(err, "error creating container storage")
|
return errors.Wrapf(err, "error creating container storage")
|
||||||
}
|
}
|
||||||
|
@ -255,6 +255,18 @@ func WithRootFSFromPath(path string) CtrCreateOption {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WithSELinuxMountLabel sets the mount label for SELinux
|
||||||
|
func WithSELinuxMountLabel(mountLabel string) CtrCreateOption {
|
||||||
|
return func(ctr *Container) error {
|
||||||
|
if ctr.valid {
|
||||||
|
return ErrCtrFinalized
|
||||||
|
}
|
||||||
|
|
||||||
|
ctr.config.MountLabel = mountLabel
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// WithRootFSFromImage sets up a fresh root filesystem using the given image
|
// WithRootFSFromImage sets up a fresh root filesystem using the given image
|
||||||
// If useImageConfig is specified, image volumes, environment variables, and
|
// If useImageConfig is specified, image volumes, environment variables, and
|
||||||
// other configuration from the image will be added to the config
|
// other configuration from the image will be added to the config
|
||||||
|
@ -18,3 +18,21 @@ ALPINE="docker.io/library/alpine:latest"
|
|||||||
echo "$output"
|
echo "$output"
|
||||||
[ "$status" -eq 0 ]
|
[ "$status" -eq 0 ]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@test "run selinux test" {
|
||||||
|
|
||||||
|
if [ ! -e /usr/sbin/selinuxenabled ] || /usr/sbin/selinuxenabled; then
|
||||||
|
skip "SELinux not enabled"
|
||||||
|
fi
|
||||||
|
|
||||||
|
firstLabel=$(${KPOD_BINARY} ${KPOD_OPTIONS} run ${ALPINE} cat /proc/self/attr/current)
|
||||||
|
run ${KPOD_BINARY} ${KPOD_OPTIONS} run ${ALPINE} cat /proc/self/attr/current
|
||||||
|
echo "$output"
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
[ "$output" != "${firstLabel}" ]
|
||||||
|
|
||||||
|
run bash -c "${KPOD_BINARY} ${KPOD_OPTIONS} run --security-opt label:level=s0:c1,c2 ${ALPINE} cat /proc/self/attr/current | grep s0:c1,c2"
|
||||||
|
echo "$output"
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user