mirror of
https://github.com/containers/podman.git
synced 2025-06-04 13:08:55 +08:00
202 lines
5.9 KiB
Go
202 lines
5.9 KiB
Go
package createconfig
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
|
|
"github.com/containers/common/pkg/capabilities"
|
|
"github.com/containers/libpod/libpod"
|
|
"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
|
|
// options.
|
|
func (c *SecurityConfig) ToCreateOptions() ([]libpod.CtrCreateOption, error) {
|
|
options := make([]libpod.CtrCreateOption, 0)
|
|
options = append(options, libpod.WithSecLabels(c.LabelOpts))
|
|
options = append(options, libpod.WithPrivileged(c.Privileged))
|
|
return options, nil
|
|
}
|
|
|
|
// SetLabelOpts sets the label options of the SecurityConfig according to the
|
|
// input.
|
|
func (c *SecurityConfig) SetLabelOpts(runtime *libpod.Runtime, pidConfig *PidConfig, ipcConfig *IpcConfig) error {
|
|
if c.Privileged {
|
|
c.LabelOpts = label.DisableSecOpt()
|
|
return nil
|
|
}
|
|
|
|
var labelOpts []string
|
|
if pidConfig.PidMode.IsHost() {
|
|
labelOpts = append(labelOpts, label.DisableSecOpt()...)
|
|
} else if pidConfig.PidMode.IsContainer() {
|
|
ctr, err := runtime.LookupContainer(pidConfig.PidMode.Container())
|
|
if err != nil {
|
|
return errors.Wrapf(err, "container %q not found", pidConfig.PidMode.Container())
|
|
}
|
|
secopts, err := label.DupSecOpt(ctr.ProcessLabel())
|
|
if err != nil {
|
|
return errors.Wrapf(err, "failed to duplicate label %q ", ctr.ProcessLabel())
|
|
}
|
|
labelOpts = append(labelOpts, secopts...)
|
|
}
|
|
|
|
if ipcConfig.IpcMode.IsHost() {
|
|
labelOpts = append(labelOpts, label.DisableSecOpt()...)
|
|
} else if ipcConfig.IpcMode.IsContainer() {
|
|
ctr, err := runtime.LookupContainer(ipcConfig.IpcMode.Container())
|
|
if err != nil {
|
|
return errors.Wrapf(err, "container %q not found", ipcConfig.IpcMode.Container())
|
|
}
|
|
secopts, err := label.DupSecOpt(ctr.ProcessLabel())
|
|
if err != nil {
|
|
return errors.Wrapf(err, "failed to duplicate label %q ", ctr.ProcessLabel())
|
|
}
|
|
labelOpts = append(labelOpts, secopts...)
|
|
}
|
|
|
|
c.LabelOpts = append(c.LabelOpts, labelOpts...)
|
|
return nil
|
|
}
|
|
|
|
// SetSecurityOpts the the security options (labels, apparmor, seccomp, etc.).
|
|
func (c *SecurityConfig) SetSecurityOpts(runtime *libpod.Runtime, securityOpts []string) error {
|
|
for _, opt := range securityOpts {
|
|
if opt == "no-new-privileges" {
|
|
c.NoNewPrivs = 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":
|
|
c.LabelOpts = append(c.LabelOpts, con[1])
|
|
case "apparmor":
|
|
c.ApparmorProfile = con[1]
|
|
case "seccomp":
|
|
c.SeccompProfilePath = con[1]
|
|
default:
|
|
return fmt.Errorf("invalid --security-opt 2: %q", opt)
|
|
}
|
|
}
|
|
}
|
|
|
|
if c.SeccompProfilePath == "" {
|
|
var err error
|
|
c.SeccompProfilePath, err = libpod.DefaultSeccompPath()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
c.SecurityOpts = securityOpts
|
|
return nil
|
|
}
|
|
|
|
// ConfigureGenerator configures the generator according to the input.
|
|
func (c *SecurityConfig) ConfigureGenerator(g *generate.Generator, user *UserConfig) error {
|
|
// HANDLE CAPABILITIES
|
|
// NOTE: Must happen before SECCOMP
|
|
if c.Privileged {
|
|
g.SetupPrivileged(true)
|
|
}
|
|
|
|
useNotRoot := func(user string) bool {
|
|
if user == "" || user == "root" || user == "0" {
|
|
return false
|
|
}
|
|
return true
|
|
}
|
|
|
|
configSpec := g.Config
|
|
var err error
|
|
var defaultCaplist []string
|
|
bounding := configSpec.Process.Capabilities.Bounding
|
|
if useNotRoot(user.User) {
|
|
configSpec.Process.Capabilities.Bounding = defaultCaplist
|
|
}
|
|
defaultCaplist, err = capabilities.MergeCapabilities(configSpec.Process.Capabilities.Bounding, c.CapAdd, c.CapDrop)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
privCapRequired := []string{}
|
|
|
|
if !c.Privileged && len(c.CapRequired) > 0 {
|
|
// Pass CapRequired in CapAdd field to normalize capabilities names
|
|
capRequired, err := capabilities.MergeCapabilities(nil, c.CapRequired, nil)
|
|
if err != nil {
|
|
logrus.Errorf("capabilities 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("capabilities 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) {
|
|
defaultCaplist, err = capabilities.MergeCapabilities(bounding, c.CapAdd, c.CapDrop)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
configSpec.Process.Capabilities.Bounding = defaultCaplist
|
|
|
|
// HANDLE SECCOMP
|
|
if c.SeccompProfilePath != "unconfined" {
|
|
seccompConfig, err := getSeccompConfig(c, configSpec)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
configSpec.Linux.Seccomp = seccompConfig
|
|
}
|
|
|
|
// Clear default Seccomp profile from Generator for privileged containers
|
|
if c.SeccompProfilePath == "unconfined" || c.Privileged {
|
|
configSpec.Linux.Seccomp = nil
|
|
}
|
|
|
|
for _, opt := range c.SecurityOpts {
|
|
// Split on both : and =
|
|
splitOpt := strings.Split(opt, "=")
|
|
if len(splitOpt) == 1 {
|
|
splitOpt = strings.Split(opt, ":")
|
|
}
|
|
if len(splitOpt) < 2 {
|
|
continue
|
|
}
|
|
switch splitOpt[0] {
|
|
case "label":
|
|
configSpec.Annotations[libpod.InspectAnnotationLabel] = splitOpt[1]
|
|
case "seccomp":
|
|
configSpec.Annotations[libpod.InspectAnnotationSeccomp] = splitOpt[1]
|
|
case "apparmor":
|
|
configSpec.Annotations[libpod.InspectAnnotationApparmor] = splitOpt[1]
|
|
}
|
|
}
|
|
|
|
g.SetRootReadonly(c.ReadOnlyRootfs)
|
|
for sysctlKey, sysctlVal := range c.Sysctl {
|
|
g.AddLinuxSysctl(sysctlKey, sysctlVal)
|
|
}
|
|
|
|
return nil
|
|
}
|