github.com/containers/podman/v2@v2.2.2-0.20210501105131-c1e07d070c4c/pkg/spec/security.go (about)

     1  package createconfig
     2  
     3  import (
     4  	"fmt"
     5  	"strings"
     6  
     7  	"github.com/containers/common/pkg/capabilities"
     8  	"github.com/containers/podman/v2/libpod"
     9  	"github.com/containers/podman/v2/libpod/define"
    10  	"github.com/containers/podman/v2/pkg/util"
    11  	"github.com/opencontainers/runtime-tools/generate"
    12  	"github.com/opencontainers/selinux/go-selinux/label"
    13  	"github.com/pkg/errors"
    14  	"github.com/sirupsen/logrus"
    15  )
    16  
    17  // ToCreateOptions convert the SecurityConfig to a slice of container create
    18  // options.
    19  func (c *SecurityConfig) ToCreateOptions() ([]libpod.CtrCreateOption, error) {
    20  	options := make([]libpod.CtrCreateOption, 0)
    21  	options = append(options, libpod.WithSecLabels(c.LabelOpts))
    22  	options = append(options, libpod.WithPrivileged(c.Privileged))
    23  	return options, nil
    24  }
    25  
    26  // SetLabelOpts sets the label options of the SecurityConfig according to the
    27  // input.
    28  func (c *SecurityConfig) SetLabelOpts(runtime *libpod.Runtime, pidConfig *PidConfig, ipcConfig *IpcConfig) error {
    29  	if c.Privileged {
    30  		c.LabelOpts = label.DisableSecOpt()
    31  		return nil
    32  	}
    33  
    34  	var labelOpts []string
    35  	if pidConfig.PidMode.IsHost() {
    36  		labelOpts = append(labelOpts, label.DisableSecOpt()...)
    37  	} else if pidConfig.PidMode.IsContainer() {
    38  		ctr, err := runtime.LookupContainer(pidConfig.PidMode.Container())
    39  		if err != nil {
    40  			return errors.Wrapf(err, "container %q not found", pidConfig.PidMode.Container())
    41  		}
    42  		secopts, err := label.DupSecOpt(ctr.ProcessLabel())
    43  		if err != nil {
    44  			return errors.Wrapf(err, "failed to duplicate label %q ", ctr.ProcessLabel())
    45  		}
    46  		labelOpts = append(labelOpts, secopts...)
    47  	}
    48  
    49  	if ipcConfig.IpcMode.IsHost() {
    50  		labelOpts = append(labelOpts, label.DisableSecOpt()...)
    51  	} else if ipcConfig.IpcMode.IsContainer() {
    52  		ctr, err := runtime.LookupContainer(ipcConfig.IpcMode.Container())
    53  		if err != nil {
    54  			return errors.Wrapf(err, "container %q not found", ipcConfig.IpcMode.Container())
    55  		}
    56  		secopts, err := label.DupSecOpt(ctr.ProcessLabel())
    57  		if err != nil {
    58  			return errors.Wrapf(err, "failed to duplicate label %q ", ctr.ProcessLabel())
    59  		}
    60  		labelOpts = append(labelOpts, secopts...)
    61  	}
    62  
    63  	c.LabelOpts = append(c.LabelOpts, labelOpts...)
    64  	return nil
    65  }
    66  
    67  // SetSecurityOpts the the security options (labels, apparmor, seccomp, etc.).
    68  func (c *SecurityConfig) SetSecurityOpts(runtime *libpod.Runtime, securityOpts []string) error {
    69  	for _, opt := range securityOpts {
    70  		if opt == "no-new-privileges" {
    71  			c.NoNewPrivs = true
    72  		} else {
    73  			con := strings.SplitN(opt, "=", 2)
    74  			if len(con) != 2 {
    75  				return fmt.Errorf("invalid --security-opt 1: %q", opt)
    76  			}
    77  
    78  			switch con[0] {
    79  			case "proc-opts":
    80  				c.ProcOpts = strings.Split(con[1], ",")
    81  			case "label":
    82  				c.LabelOpts = append(c.LabelOpts, con[1])
    83  			case "apparmor":
    84  				c.ApparmorProfile = con[1]
    85  			case "seccomp":
    86  				c.SeccompProfilePath = con[1]
    87  			default:
    88  				return fmt.Errorf("invalid --security-opt 2: %q", opt)
    89  			}
    90  		}
    91  	}
    92  
    93  	if c.SeccompProfilePath == "" {
    94  		var err error
    95  		c.SeccompProfilePath, err = libpod.DefaultSeccompPath()
    96  		if err != nil {
    97  			return err
    98  		}
    99  	}
   100  	c.SecurityOpts = securityOpts
   101  	return nil
   102  }
   103  
   104  // ConfigureGenerator configures the generator according to the input.
   105  func (c *SecurityConfig) ConfigureGenerator(g *generate.Generator, user *UserConfig) error {
   106  	// HANDLE CAPABILITIES
   107  	// NOTE: Must happen before SECCOMP
   108  	if c.Privileged {
   109  		g.SetupPrivileged(true)
   110  	}
   111  
   112  	useNotRoot := func(user string) bool {
   113  		if user == "" || user == "root" || user == "0" {
   114  			return false
   115  		}
   116  		return true
   117  	}
   118  
   119  	configSpec := g.Config
   120  	var err error
   121  	var defaultCaplist []string
   122  	bounding := configSpec.Process.Capabilities.Bounding
   123  	if useNotRoot(user.User) {
   124  		configSpec.Process.Capabilities.Bounding = defaultCaplist
   125  	}
   126  	defaultCaplist, err = capabilities.MergeCapabilities(configSpec.Process.Capabilities.Bounding, c.CapAdd, c.CapDrop)
   127  	if err != nil {
   128  		return err
   129  	}
   130  
   131  	privCapRequired := []string{}
   132  
   133  	if !c.Privileged && len(c.CapRequired) > 0 {
   134  		// Pass CapRequired in CapAdd field to normalize capabilities names
   135  		capRequired, err := capabilities.MergeCapabilities(nil, c.CapRequired, nil)
   136  		if err != nil {
   137  			logrus.Errorf("capabilities requested by user or image are not valid: %q", strings.Join(c.CapRequired, ","))
   138  		} else {
   139  			// Verify all capRequiered are in the defaultCapList
   140  			for _, cap := range capRequired {
   141  				if !util.StringInSlice(cap, defaultCaplist) {
   142  					privCapRequired = append(privCapRequired, cap)
   143  				}
   144  			}
   145  		}
   146  		if len(privCapRequired) == 0 {
   147  			defaultCaplist = capRequired
   148  		} else {
   149  			logrus.Errorf("capabilities requested by user or image are not allowed by default: %q", strings.Join(privCapRequired, ","))
   150  		}
   151  	}
   152  	configSpec.Process.Capabilities.Bounding = defaultCaplist
   153  	configSpec.Process.Capabilities.Permitted = defaultCaplist
   154  	configSpec.Process.Capabilities.Inheritable = defaultCaplist
   155  	configSpec.Process.Capabilities.Effective = defaultCaplist
   156  	configSpec.Process.Capabilities.Ambient = defaultCaplist
   157  	if useNotRoot(user.User) {
   158  		defaultCaplist, err = capabilities.MergeCapabilities(bounding, c.CapAdd, c.CapDrop)
   159  		if err != nil {
   160  			return err
   161  		}
   162  	}
   163  	configSpec.Process.Capabilities.Bounding = defaultCaplist
   164  
   165  	// HANDLE SECCOMP
   166  	if c.SeccompProfilePath != "unconfined" {
   167  		seccompConfig, err := getSeccompConfig(c, configSpec)
   168  		if err != nil {
   169  			return err
   170  		}
   171  		configSpec.Linux.Seccomp = seccompConfig
   172  	}
   173  
   174  	// Clear default Seccomp profile from Generator for privileged containers
   175  	if c.SeccompProfilePath == "unconfined" || c.Privileged {
   176  		configSpec.Linux.Seccomp = nil
   177  	}
   178  
   179  	for _, opt := range c.SecurityOpts {
   180  		// Split on both : and =
   181  		splitOpt := strings.SplitN(opt, "=", 2)
   182  		if len(splitOpt) == 1 {
   183  			splitOpt = strings.Split(opt, ":")
   184  		}
   185  		if len(splitOpt) < 2 {
   186  			continue
   187  		}
   188  		switch splitOpt[0] {
   189  		case "label":
   190  			configSpec.Annotations[define.InspectAnnotationLabel] = splitOpt[1]
   191  		case "seccomp":
   192  			configSpec.Annotations[define.InspectAnnotationSeccomp] = splitOpt[1]
   193  		case "apparmor":
   194  			configSpec.Annotations[define.InspectAnnotationApparmor] = splitOpt[1]
   195  		}
   196  	}
   197  
   198  	g.SetRootReadonly(c.ReadOnlyRootfs)
   199  	for sysctlKey, sysctlVal := range c.Sysctl {
   200  		g.AddLinuxSysctl(sysctlKey, sysctlVal)
   201  	}
   202  
   203  	return nil
   204  }