// Ensure a pod's SecurityContext is in compliance with the given constraints. func (s *simpleProvider) ValidatePodSecurityContext(pod *api.Pod, fldPath *field.Path) field.ErrorList { allErrs := field.ErrorList{} if pod.Spec.SecurityContext == nil { allErrs = append(allErrs, field.Invalid(fldPath.Child("securityContext"), pod.Spec.SecurityContext, "No security context is set")) return allErrs } fsGroups := []int64{} if pod.Spec.SecurityContext.FSGroup != nil { fsGroups = append(fsGroups, *pod.Spec.SecurityContext.FSGroup) } allErrs = append(allErrs, s.strategies.FSGroupStrategy.Validate(pod, fsGroups)...) allErrs = append(allErrs, s.strategies.SupplementalGroupStrategy.Validate(pod, pod.Spec.SecurityContext.SupplementalGroups)...) allErrs = append(allErrs, s.strategies.SeccompStrategy.ValidatePod(pod)...) // make a dummy container context to reuse the selinux strategies container := &api.Container{ Name: pod.Name, SecurityContext: &api.SecurityContext{ SELinuxOptions: pod.Spec.SecurityContext.SELinuxOptions, }, } allErrs = append(allErrs, s.strategies.SELinuxStrategy.Validate(pod, container)...) if !s.psp.Spec.HostNetwork && pod.Spec.SecurityContext.HostNetwork { allErrs = append(allErrs, field.Invalid(fldPath.Child("hostNetwork"), pod.Spec.SecurityContext.HostNetwork, "Host network is not allowed to be used")) } if !s.psp.Spec.HostPID && pod.Spec.SecurityContext.HostPID { allErrs = append(allErrs, field.Invalid(fldPath.Child("hostPID"), pod.Spec.SecurityContext.HostPID, "Host PID is not allowed to be used")) } if !s.psp.Spec.HostIPC && pod.Spec.SecurityContext.HostIPC { allErrs = append(allErrs, field.Invalid(fldPath.Child("hostIPC"), pod.Spec.SecurityContext.HostIPC, "Host IPC is not allowed to be used")) } allErrs = append(allErrs, s.strategies.SysctlsStrategy.Validate(pod)...) // TODO(timstclair): ValidatePodSecurityContext should be renamed to ValidatePod since its scope // is not limited to the PodSecurityContext. if len(pod.Spec.Volumes) > 0 && !psputil.PSPAllowsAllVolumes(s.psp) { allowedVolumes := psputil.FSTypeToStringSet(s.psp.Spec.Volumes) for i, v := range pod.Spec.Volumes { fsType, err := psputil.GetVolumeFSType(v) if err != nil { allErrs = append(allErrs, field.Invalid(field.NewPath("spec", "volumes").Index(i), string(fsType), err.Error())) continue } if !allowedVolumes.Has(string(fsType)) { allErrs = append(allErrs, field.Invalid( field.NewPath("spec", "volumes").Index(i), string(fsType), fmt.Sprintf("%s volumes are not allowed to be used", string(fsType)))) } } } return allErrs }
// Ensure a container's SecurityContext is in compliance with the given constraints func (s *simpleProvider) ValidateContainerSecurityContext(pod *api.Pod, container *api.Container, fldPath *field.Path) field.ErrorList { allErrs := field.ErrorList{} if container.SecurityContext == nil { allErrs = append(allErrs, field.Invalid(fldPath.Child("securityContext"), container.SecurityContext, "No security context is set")) return allErrs } sc := container.SecurityContext allErrs = append(allErrs, s.strategies.RunAsUserStrategy.Validate(pod, container)...) allErrs = append(allErrs, s.strategies.SELinuxStrategy.Validate(pod, container)...) if !s.psp.Spec.Privileged && *sc.Privileged { allErrs = append(allErrs, field.Invalid(fldPath.Child("privileged"), *sc.Privileged, "Privileged containers are not allowed")) } allErrs = append(allErrs, s.strategies.CapabilitiesStrategy.Validate(pod, container)...) if len(pod.Spec.Volumes) > 0 && !psputil.PSPAllowsAllVolumes(s.psp) { allowedVolumes := psputil.FSTypeToStringSet(s.psp.Spec.Volumes) for i, v := range pod.Spec.Volumes { fsType, err := psputil.GetVolumeFSType(v) if err != nil { allErrs = append(allErrs, field.Invalid(fldPath.Child("volumes").Index(i), string(fsType), err.Error())) continue } if !allowedVolumes.Has(string(fsType)) { allErrs = append(allErrs, field.Invalid( fldPath.Child("volumes").Index(i), string(fsType), fmt.Sprintf("%s volumes are not allowed to be used", string(fsType)))) } } } if !s.psp.Spec.HostNetwork && pod.Spec.SecurityContext.HostNetwork { allErrs = append(allErrs, field.Invalid(fldPath.Child("hostNetwork"), pod.Spec.SecurityContext.HostNetwork, "Host network is not allowed to be used")) } containersPath := fldPath.Child("containers") for idx, c := range pod.Spec.Containers { idxPath := containersPath.Index(idx) allErrs = append(allErrs, s.hasInvalidHostPort(&c, idxPath)...) } if !s.psp.Spec.HostPID && pod.Spec.SecurityContext.HostPID { allErrs = append(allErrs, field.Invalid(fldPath.Child("hostPID"), pod.Spec.SecurityContext.HostPID, "Host PID is not allowed to be used")) } if !s.psp.Spec.HostIPC && pod.Spec.SecurityContext.HostIPC { allErrs = append(allErrs, field.Invalid(fldPath.Child("hostIPC"), pod.Spec.SecurityContext.HostIPC, "Host IPC is not allowed to be used")) } if s.psp.Spec.ReadOnlyRootFilesystem { if sc.ReadOnlyRootFilesystem == nil { allErrs = append(allErrs, field.Invalid(fldPath.Child("readOnlyRootFilesystem"), sc.ReadOnlyRootFilesystem, "ReadOnlyRootFilesystem may not be nil and must be set to true")) } else if !*sc.ReadOnlyRootFilesystem { allErrs = append(allErrs, field.Invalid(fldPath.Child("readOnlyRootFilesystem"), *sc.ReadOnlyRootFilesystem, "ReadOnlyRootFilesystem must be set to true")) } } return allErrs }