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