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 }