// determineEffectiveSecurityContext gets container's security context from api.Pod and api.Container. func (m *kubeGenericRuntimeManager) determineEffectiveSecurityContext(pod *api.Pod, container *api.Container, imageUser string) *runtimeapi.LinuxContainerSecurityContext { effectiveSc := securitycontext.DetermineEffectiveSecurityContext(pod, container) synthesized := convertToRuntimeSecurityContext(effectiveSc) if synthesized == nil { synthesized = &runtimeapi.LinuxContainerSecurityContext{} } // set RunAsUser. if synthesized.RunAsUser == nil { synthesized.RunAsUser = &imageUser } // set namespace options and supplemental groups. podSc := pod.Spec.SecurityContext if podSc == nil { return synthesized } synthesized.NamespaceOptions = &runtimeapi.NamespaceOption{ HostNetwork: &podSc.HostNetwork, HostIpc: &podSc.HostIPC, HostPid: &podSc.HostPID, } if podSc.FSGroup != nil { synthesized.SupplementalGroups = append(synthesized.SupplementalGroups, *podSc.FSGroup) } if groups := m.runtimeHelper.GetExtraSupplementalGroupsForPod(pod); len(groups) > 0 { synthesized.SupplementalGroups = append(synthesized.SupplementalGroups, groups...) } if podSc.SupplementalGroups != nil { synthesized.SupplementalGroups = append(synthesized.SupplementalGroups, podSc.SupplementalGroups...) } return synthesized }
// verifyRunAsNonRoot verifies RunAsNonRoot. func verifyRunAsNonRoot(pod *api.Pod, container *api.Container, imageUser string) error { effectiveSc := securitycontext.DetermineEffectiveSecurityContext(pod, container) if effectiveSc == nil || effectiveSc.RunAsNonRoot == nil { return nil } if effectiveSc.RunAsUser != nil { if *effectiveSc.RunAsUser == 0 { return fmt.Errorf("container's runAsUser breaks non-root policy") } return nil } // Non-root verification only supports numeric user now. For non-numeric user, // just return nil to by-pass the verfication. // TODO: Support non-numeric user. uid, err := strconv.ParseInt(imageUser, 10, 64) if err != nil { glog.Warningf("Non-root verification doesn't support non-numeric user (%s)", imageUser) return nil } if uid == 0 { return fmt.Errorf("container has runAsNonRoot and image will run as root") } return nil }
// assignSecurityContext creates a security context for each container in the pod // and validates that the sc falls within the scc constraints. All containers must validate against // the same scc or is not considered valid. func assignSecurityContext(provider scc.SecurityContextConstraintsProvider, pod *kapi.Pod, fldPath *field.Path) field.ErrorList { generatedSCs := make([]*kapi.SecurityContext, len(pod.Spec.Containers)) errs := field.ErrorList{} psc, err := provider.CreatePodSecurityContext(pod) if err != nil { errs = append(errs, field.Invalid(field.NewPath("spec", "securityContext"), pod.Spec.SecurityContext, err.Error())) } // save the original PSC and validate the generated PSC. Leave the generated PSC // set for container generation/validation. We will reset to original post container // validation. originalPSC := pod.Spec.SecurityContext pod.Spec.SecurityContext = psc errs = append(errs, provider.ValidatePodSecurityContext(pod, field.NewPath("spec", "securityContext"))...) // Note: this is not changing the original container, we will set container SCs later so long // as all containers validated under the same SCC. for i, containerCopy := range pod.Spec.Containers { // We will determine the effective security context for the container and validate against that // since that is how the sc provider will eventually apply settings in the runtime. // This results in an SC that is based on the Pod's PSC with the set fields from the container // overriding pod level settings. containerCopy.SecurityContext = sc.DetermineEffectiveSecurityContext(pod, &containerCopy) sc, err := provider.CreateContainerSecurityContext(pod, &containerCopy) if err != nil { errs = append(errs, field.Invalid(field.NewPath("spec", "containers").Index(i).Child("securityContext"), "", err.Error())) continue } generatedSCs[i] = sc containerCopy.SecurityContext = sc errs = append(errs, provider.ValidateContainerSecurityContext(pod, &containerCopy, field.NewPath("spec", "containers").Index(i).Child("securityContext"))...) } if len(errs) > 0 { // ensure psc is not mutated if there are errors pod.Spec.SecurityContext = originalPSC return errs } // if we've reached this code then we've generated and validated an SC for every container in the // pod so let's apply what we generated. Note: the psc is already applied. for i, sc := range generatedSCs { pod.Spec.Containers[i].SecurityContext = sc } return nil }
// resolveContainerSecurityContext checks the provided container against the provider, returning any // validation errors encountered on the resulting security context, or the security context that was // resolved. The SecurityContext field of the container is updated, so ensure that a copy of the original // container is passed here if you wish to preserve the original input. func resolveContainerSecurityContext(provider scc.SecurityContextConstraintsProvider, pod *kapi.Pod, container *kapi.Container, path *field.Path) (*kapi.SecurityContext, field.ErrorList) { // We will determine the effective security context for the container and validate against that // since that is how the sc provider will eventually apply settings in the runtime. // This results in an SC that is based on the Pod's PSC with the set fields from the container // overriding pod level settings. container.SecurityContext = sc.DetermineEffectiveSecurityContext(pod, container) csc, err := provider.CreateContainerSecurityContext(pod, container) if err != nil { return nil, field.ErrorList{field.Invalid(path.Child("securityContext"), "", err.Error())} } container.SecurityContext = csc return csc, provider.ValidateContainerSecurityContext(pod, container, path.Child("securityContext")) }
// verifyRunAsNonRoot verifies RunAsNonRoot. func verifyRunAsNonRoot(pod *api.Pod, container *api.Container, imageUser int64) error { effectiveSc := securitycontext.DetermineEffectiveSecurityContext(pod, container) if effectiveSc == nil || effectiveSc.RunAsNonRoot == nil { return nil } if effectiveSc.RunAsUser != nil && *effectiveSc.RunAsUser == 0 { return fmt.Errorf("container's runAsUser breaks non-root policy") } if imageUser == 0 { return fmt.Errorf("container has runAsNonRoot and image will run as root") } return nil }
func (r *Runtime) newAppcRuntimeApp(pod *api.Pod, c api.Container, pullSecrets []api.Secret) (*appcschema.RuntimeApp, []kubecontainer.PortMapping, error) { if err, _ := r.imagePuller.PullImage(pod, &c, pullSecrets); err != nil { return nil, nil, err } imgManifest, err := r.getImageManifest(c.Image) if err != nil { return nil, nil, err } if imgManifest.App == nil { imgManifest.App = new(appctypes.App) } imageID, err := r.getImageID(c.Image) if err != nil { return nil, nil, err } hash, err := appctypes.NewHash(imageID) if err != nil { return nil, nil, err } opts, err := r.generator.GenerateRunContainerOptions(pod, &c) if err != nil { return nil, nil, err } ctx := securitycontext.DetermineEffectiveSecurityContext(pod, &c) if err := setApp(imgManifest.App, &c, opts, ctx, pod.Spec.SecurityContext); err != nil { return nil, nil, err } return &appcschema.RuntimeApp{ Name: convertToACName(c.Name), Image: appcschema.RuntimeImage{ID: *hash}, App: imgManifest.App, Annotations: []appctypes.Annotation{ { Name: *appctypes.MustACIdentifier(k8sRktContainerHashAnno), Value: strconv.FormatUint(kubecontainer.HashContainer(&c), 10), }, }, }, opts.PortMappings, nil }
func (r *Runtime) newAppcRuntimeApp(pod *api.Pod, c api.Container, pullSecrets []api.Secret, manifest *appcschema.PodManifest) error { if err, _ := r.imagePuller.PullImage(pod, &c, pullSecrets); err != nil { return nil } imgManifest, err := r.getImageManifest(c.Image) if err != nil { return err } if imgManifest.App == nil { imgManifest.App = new(appctypes.App) } imageID, err := r.getImageID(c.Image) if err != nil { return err } hash, err := appctypes.NewHash(imageID) if err != nil { return err } opts, err := r.runtimeHelper.GenerateRunContainerOptions(pod, &c) if err != nil { return err } // create the container log file and make a mount pair. mnt, err := makeContainerLogMount(opts, &c) if err != nil { return err } ctx := securitycontext.DetermineEffectiveSecurityContext(pod, &c) if err := setApp(imgManifest.App, &c, opts, ctx, pod.Spec.SecurityContext); err != nil { return err } ra := appcschema.RuntimeApp{ Name: convertToACName(c.Name), Image: appcschema.RuntimeImage{ID: *hash}, App: imgManifest.App, Annotations: []appctypes.Annotation{ { Name: *appctypes.MustACIdentifier(k8sRktContainerHashAnno), Value: strconv.FormatUint(kubecontainer.HashContainer(&c), 10), }, }, } if mnt != nil { ra.Annotations = append(ra.Annotations, appctypes.Annotation{ Name: *appctypes.MustACIdentifier(k8sRktTerminationMessagePathAnno), Value: mnt.HostPath, }) manifest.Volumes = append(manifest.Volumes, appctypes.Volume{ Name: convertToACName(mnt.Name), Kind: "host", Source: mnt.HostPath, }) } manifest.Apps = append(manifest.Apps, ra) // Set global ports. for _, port := range opts.PortMappings { manifest.Ports = append(manifest.Ports, appctypes.ExposedPort{ Name: convertToACName(port.Name), HostPort: uint(port.HostPort), }) } return nil }