mirror of
				https://github.com/optim-enterprises-bv/kubernetes.git
				synced 2025-11-03 19:58:17 +00:00 
			
		
		
		
	api validation: validate proc mount against user namespace
fail if container uses proc mount unmasked but pod does not use user namespace Signed-off-by: Peter Hunt <pehunt@redhat.com>
This commit is contained in:
		@@ -3362,7 +3362,7 @@ func validateResizePolicy(policyList []core.ContainerResizePolicy, fldPath *fiel
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// validateEphemeralContainers is called by pod spec and template validation to validate the list of ephemeral containers.
 | 
					// validateEphemeralContainers is called by pod spec and template validation to validate the list of ephemeral containers.
 | 
				
			||||||
// Note that this is called for pod template even though ephemeral containers aren't allowed in pod templates.
 | 
					// Note that this is called for pod template even though ephemeral containers aren't allowed in pod templates.
 | 
				
			||||||
func validateEphemeralContainers(ephemeralContainers []core.EphemeralContainer, containers, initContainers []core.Container, volumes map[string]core.VolumeSource, podClaimNames sets.Set[string], fldPath *field.Path, opts PodValidationOptions, podRestartPolicy *core.RestartPolicy) field.ErrorList {
 | 
					func validateEphemeralContainers(ephemeralContainers []core.EphemeralContainer, containers, initContainers []core.Container, volumes map[string]core.VolumeSource, podClaimNames sets.Set[string], fldPath *field.Path, opts PodValidationOptions, podRestartPolicy *core.RestartPolicy, hostUsers bool) field.ErrorList {
 | 
				
			||||||
	var allErrs field.ErrorList
 | 
						var allErrs field.ErrorList
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if len(ephemeralContainers) == 0 {
 | 
						if len(ephemeralContainers) == 0 {
 | 
				
			||||||
@@ -3383,7 +3383,7 @@ func validateEphemeralContainers(ephemeralContainers []core.EphemeralContainer,
 | 
				
			|||||||
		idxPath := fldPath.Index(i)
 | 
							idxPath := fldPath.Index(i)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		c := (*core.Container)(&ec.EphemeralContainerCommon)
 | 
							c := (*core.Container)(&ec.EphemeralContainerCommon)
 | 
				
			||||||
		allErrs = append(allErrs, validateContainerCommon(c, volumes, podClaimNames, idxPath, opts, podRestartPolicy)...)
 | 
							allErrs = append(allErrs, validateContainerCommon(c, volumes, podClaimNames, idxPath, opts, podRestartPolicy, hostUsers)...)
 | 
				
			||||||
		// Ephemeral containers don't need looser constraints for pod templates, so it's convenient to apply both validations
 | 
							// Ephemeral containers don't need looser constraints for pod templates, so it's convenient to apply both validations
 | 
				
			||||||
		// here where we've already converted EphemeralContainerCommon to Container.
 | 
							// here where we've already converted EphemeralContainerCommon to Container.
 | 
				
			||||||
		allErrs = append(allErrs, validateContainerOnlyForPod(c, idxPath)...)
 | 
							allErrs = append(allErrs, validateContainerOnlyForPod(c, idxPath)...)
 | 
				
			||||||
@@ -3445,7 +3445,7 @@ func validateFieldAllowList(value interface{}, allowedFields map[string]bool, er
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// validateInitContainers is called by pod spec and template validation to validate the list of init containers
 | 
					// validateInitContainers is called by pod spec and template validation to validate the list of init containers
 | 
				
			||||||
func validateInitContainers(containers []core.Container, regularContainers []core.Container, volumes map[string]core.VolumeSource, podClaimNames sets.Set[string], gracePeriod int64, fldPath *field.Path, opts PodValidationOptions, podRestartPolicy *core.RestartPolicy) field.ErrorList {
 | 
					func validateInitContainers(containers []core.Container, regularContainers []core.Container, volumes map[string]core.VolumeSource, podClaimNames sets.Set[string], gracePeriod int64, fldPath *field.Path, opts PodValidationOptions, podRestartPolicy *core.RestartPolicy, hostUsers bool) field.ErrorList {
 | 
				
			||||||
	var allErrs field.ErrorList
 | 
						var allErrs field.ErrorList
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	allNames := sets.Set[string]{}
 | 
						allNames := sets.Set[string]{}
 | 
				
			||||||
@@ -3456,7 +3456,7 @@ func validateInitContainers(containers []core.Container, regularContainers []cor
 | 
				
			|||||||
		idxPath := fldPath.Index(i)
 | 
							idxPath := fldPath.Index(i)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// Apply the validation common to all container types
 | 
							// Apply the validation common to all container types
 | 
				
			||||||
		allErrs = append(allErrs, validateContainerCommon(&ctr, volumes, podClaimNames, idxPath, opts, podRestartPolicy)...)
 | 
							allErrs = append(allErrs, validateContainerCommon(&ctr, volumes, podClaimNames, idxPath, opts, podRestartPolicy, hostUsers)...)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		restartAlways := false
 | 
							restartAlways := false
 | 
				
			||||||
		// Apply the validation specific to init containers
 | 
							// Apply the validation specific to init containers
 | 
				
			||||||
@@ -3511,7 +3511,7 @@ func validateInitContainers(containers []core.Container, regularContainers []cor
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// validateContainerCommon applies validation common to all container types. It's called by regular, init, and ephemeral
 | 
					// validateContainerCommon applies validation common to all container types. It's called by regular, init, and ephemeral
 | 
				
			||||||
// container list validation to require a properly formatted name, image, etc.
 | 
					// container list validation to require a properly formatted name, image, etc.
 | 
				
			||||||
func validateContainerCommon(ctr *core.Container, volumes map[string]core.VolumeSource, podClaimNames sets.Set[string], path *field.Path, opts PodValidationOptions, podRestartPolicy *core.RestartPolicy) field.ErrorList {
 | 
					func validateContainerCommon(ctr *core.Container, volumes map[string]core.VolumeSource, podClaimNames sets.Set[string], path *field.Path, opts PodValidationOptions, podRestartPolicy *core.RestartPolicy, hostUsers bool) field.ErrorList {
 | 
				
			||||||
	var allErrs field.ErrorList
 | 
						var allErrs field.ErrorList
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	namePath := path.Child("name")
 | 
						namePath := path.Child("name")
 | 
				
			||||||
@@ -3550,7 +3550,7 @@ func validateContainerCommon(ctr *core.Container, volumes map[string]core.Volume
 | 
				
			|||||||
	allErrs = append(allErrs, validatePullPolicy(ctr.ImagePullPolicy, path.Child("imagePullPolicy"))...)
 | 
						allErrs = append(allErrs, validatePullPolicy(ctr.ImagePullPolicy, path.Child("imagePullPolicy"))...)
 | 
				
			||||||
	allErrs = append(allErrs, ValidateResourceRequirements(&ctr.Resources, podClaimNames, path.Child("resources"), opts)...)
 | 
						allErrs = append(allErrs, ValidateResourceRequirements(&ctr.Resources, podClaimNames, path.Child("resources"), opts)...)
 | 
				
			||||||
	allErrs = append(allErrs, validateResizePolicy(ctr.ResizePolicy, path.Child("resizePolicy"), podRestartPolicy)...)
 | 
						allErrs = append(allErrs, validateResizePolicy(ctr.ResizePolicy, path.Child("resizePolicy"), podRestartPolicy)...)
 | 
				
			||||||
	allErrs = append(allErrs, ValidateSecurityContext(ctr.SecurityContext, path.Child("securityContext"))...)
 | 
						allErrs = append(allErrs, ValidateSecurityContext(ctr.SecurityContext, path.Child("securityContext"), hostUsers)...)
 | 
				
			||||||
	return allErrs
 | 
						return allErrs
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -3583,7 +3583,7 @@ func validateHostUsers(spec *core.PodSpec, fldPath *field.Path) field.ErrorList
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// validateContainers is called by pod spec and template validation to validate the list of regular containers.
 | 
					// validateContainers is called by pod spec and template validation to validate the list of regular containers.
 | 
				
			||||||
func validateContainers(containers []core.Container, volumes map[string]core.VolumeSource, podClaimNames sets.Set[string], gracePeriod int64, fldPath *field.Path, opts PodValidationOptions, podRestartPolicy *core.RestartPolicy) field.ErrorList {
 | 
					func validateContainers(containers []core.Container, volumes map[string]core.VolumeSource, podClaimNames sets.Set[string], gracePeriod int64, fldPath *field.Path, opts PodValidationOptions, podRestartPolicy *core.RestartPolicy, hostUsers bool) field.ErrorList {
 | 
				
			||||||
	allErrs := field.ErrorList{}
 | 
						allErrs := field.ErrorList{}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if len(containers) == 0 {
 | 
						if len(containers) == 0 {
 | 
				
			||||||
@@ -3595,7 +3595,7 @@ func validateContainers(containers []core.Container, volumes map[string]core.Vol
 | 
				
			|||||||
		path := fldPath.Index(i)
 | 
							path := fldPath.Index(i)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// Apply validation common to all containers
 | 
							// Apply validation common to all containers
 | 
				
			||||||
		allErrs = append(allErrs, validateContainerCommon(&ctr, volumes, podClaimNames, path, opts, podRestartPolicy)...)
 | 
							allErrs = append(allErrs, validateContainerCommon(&ctr, volumes, podClaimNames, path, opts, podRestartPolicy, hostUsers)...)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// Container names must be unique within the list of regular containers.
 | 
							// Container names must be unique within the list of regular containers.
 | 
				
			||||||
		// Collisions with init or ephemeral container names will be detected by the init or ephemeral
 | 
							// Collisions with init or ephemeral container names will be detected by the init or ephemeral
 | 
				
			||||||
@@ -4139,13 +4139,17 @@ func ValidatePodSpec(spec *core.PodSpec, podMeta *metav1.ObjectMeta, fldPath *fi
 | 
				
			|||||||
		gracePeriod = *spec.TerminationGracePeriodSeconds
 | 
							gracePeriod = *spec.TerminationGracePeriodSeconds
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// The default for hostUsers is true, so a spec with no SecurityContext or no HostUsers field will be true.
 | 
				
			||||||
 | 
						// If the default ever changes, this condition will need to be changed.
 | 
				
			||||||
 | 
						hostUsers := spec.SecurityContext == nil || spec.SecurityContext.HostUsers == nil || *spec.SecurityContext.HostUsers
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	vols, vErrs := ValidateVolumes(spec.Volumes, podMeta, fldPath.Child("volumes"), opts)
 | 
						vols, vErrs := ValidateVolumes(spec.Volumes, podMeta, fldPath.Child("volumes"), opts)
 | 
				
			||||||
	allErrs = append(allErrs, vErrs...)
 | 
						allErrs = append(allErrs, vErrs...)
 | 
				
			||||||
	podClaimNames := gatherPodResourceClaimNames(spec.ResourceClaims)
 | 
						podClaimNames := gatherPodResourceClaimNames(spec.ResourceClaims)
 | 
				
			||||||
	allErrs = append(allErrs, validatePodResourceClaims(podMeta, spec.ResourceClaims, fldPath.Child("resourceClaims"))...)
 | 
						allErrs = append(allErrs, validatePodResourceClaims(podMeta, spec.ResourceClaims, fldPath.Child("resourceClaims"))...)
 | 
				
			||||||
	allErrs = append(allErrs, validateContainers(spec.Containers, vols, podClaimNames, gracePeriod, fldPath.Child("containers"), opts, &spec.RestartPolicy)...)
 | 
						allErrs = append(allErrs, validateContainers(spec.Containers, vols, podClaimNames, gracePeriod, fldPath.Child("containers"), opts, &spec.RestartPolicy, hostUsers)...)
 | 
				
			||||||
	allErrs = append(allErrs, validateInitContainers(spec.InitContainers, spec.Containers, vols, podClaimNames, gracePeriod, fldPath.Child("initContainers"), opts, &spec.RestartPolicy)...)
 | 
						allErrs = append(allErrs, validateInitContainers(spec.InitContainers, spec.Containers, vols, podClaimNames, gracePeriod, fldPath.Child("initContainers"), opts, &spec.RestartPolicy, hostUsers)...)
 | 
				
			||||||
	allErrs = append(allErrs, validateEphemeralContainers(spec.EphemeralContainers, spec.Containers, spec.InitContainers, vols, podClaimNames, fldPath.Child("ephemeralContainers"), opts, &spec.RestartPolicy)...)
 | 
						allErrs = append(allErrs, validateEphemeralContainers(spec.EphemeralContainers, spec.Containers, spec.InitContainers, vols, podClaimNames, fldPath.Child("ephemeralContainers"), opts, &spec.RestartPolicy, hostUsers)...)
 | 
				
			||||||
	allErrs = append(allErrs, validatePodHostNetworkDeps(spec, fldPath, opts)...)
 | 
						allErrs = append(allErrs, validatePodHostNetworkDeps(spec, fldPath, opts)...)
 | 
				
			||||||
	allErrs = append(allErrs, validateRestartPolicy(&spec.RestartPolicy, fldPath.Child("restartPolicy"))...)
 | 
						allErrs = append(allErrs, validateRestartPolicy(&spec.RestartPolicy, fldPath.Child("restartPolicy"))...)
 | 
				
			||||||
	allErrs = append(allErrs, validateDNSPolicy(&spec.DNSPolicy, fldPath.Child("dnsPolicy"))...)
 | 
						allErrs = append(allErrs, validateDNSPolicy(&spec.DNSPolicy, fldPath.Child("dnsPolicy"))...)
 | 
				
			||||||
@@ -7051,7 +7055,7 @@ func validateEndpointPort(port *core.EndpointPort, requireName bool, fldPath *fi
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// ValidateSecurityContext ensures the security context contains valid settings
 | 
					// ValidateSecurityContext ensures the security context contains valid settings
 | 
				
			||||||
func ValidateSecurityContext(sc *core.SecurityContext, fldPath *field.Path) field.ErrorList {
 | 
					func ValidateSecurityContext(sc *core.SecurityContext, fldPath *field.Path, hostUsers bool) field.ErrorList {
 | 
				
			||||||
	allErrs := field.ErrorList{}
 | 
						allErrs := field.ErrorList{}
 | 
				
			||||||
	// this should only be true for testing since SecurityContext is defaulted by the core
 | 
						// this should only be true for testing since SecurityContext is defaulted by the core
 | 
				
			||||||
	if sc == nil {
 | 
						if sc == nil {
 | 
				
			||||||
@@ -7080,6 +7084,9 @@ func ValidateSecurityContext(sc *core.SecurityContext, fldPath *field.Path) fiel
 | 
				
			|||||||
		if err := ValidateProcMountType(fldPath.Child("procMount"), *sc.ProcMount); err != nil {
 | 
							if err := ValidateProcMountType(fldPath.Child("procMount"), *sc.ProcMount); err != nil {
 | 
				
			||||||
			allErrs = append(allErrs, err)
 | 
								allErrs = append(allErrs, err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
							if hostUsers && *sc.ProcMount == core.UnmaskedProcMount {
 | 
				
			||||||
 | 
								allErrs = append(allErrs, field.Invalid(fldPath.Child("procMount"), sc.ProcMount, "`hostUsers` must be false to use `Unmasked`"))
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	allErrs = append(allErrs, validateSeccompProfileField(sc.SeccompProfile, fldPath.Child("seccompProfile"))...)
 | 
						allErrs = append(allErrs, validateSeccompProfileField(sc.SeccompProfile, fldPath.Child("seccompProfile"))...)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -55,6 +55,7 @@ const (
 | 
				
			|||||||
	envVarNameErrMsg                  = "a valid environment variable name must consist of"
 | 
						envVarNameErrMsg                  = "a valid environment variable name must consist of"
 | 
				
			||||||
	relaxedEnvVarNameFmtErrMsg string = "a valid environment variable names must be printable ASCII characters other than '=' character"
 | 
						relaxedEnvVarNameFmtErrMsg string = "a valid environment variable names must be printable ASCII characters other than '=' character"
 | 
				
			||||||
	defaultGracePeriod                = int64(30)
 | 
						defaultGracePeriod                = int64(30)
 | 
				
			||||||
 | 
						noUserNamespace                   = false
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var (
 | 
					var (
 | 
				
			||||||
@@ -7895,17 +7896,17 @@ func TestValidateEphemeralContainers(t *testing.T) {
 | 
				
			|||||||
	} {
 | 
						} {
 | 
				
			||||||
		var PodRestartPolicy core.RestartPolicy
 | 
							var PodRestartPolicy core.RestartPolicy
 | 
				
			||||||
		PodRestartPolicy = "Never"
 | 
							PodRestartPolicy = "Never"
 | 
				
			||||||
		if errs := validateEphemeralContainers(ephemeralContainers, containers, initContainers, vols, nil, field.NewPath("ephemeralContainers"), PodValidationOptions{}, &PodRestartPolicy); len(errs) != 0 {
 | 
							if errs := validateEphemeralContainers(ephemeralContainers, containers, initContainers, vols, nil, field.NewPath("ephemeralContainers"), PodValidationOptions{}, &PodRestartPolicy, noUserNamespace); len(errs) != 0 {
 | 
				
			||||||
			t.Errorf("expected success for '%s' but got errors: %v", title, errs)
 | 
								t.Errorf("expected success for '%s' but got errors: %v", title, errs)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		PodRestartPolicy = "Always"
 | 
							PodRestartPolicy = "Always"
 | 
				
			||||||
		if errs := validateEphemeralContainers(ephemeralContainers, containers, initContainers, vols, nil, field.NewPath("ephemeralContainers"), PodValidationOptions{}, &PodRestartPolicy); len(errs) != 0 {
 | 
							if errs := validateEphemeralContainers(ephemeralContainers, containers, initContainers, vols, nil, field.NewPath("ephemeralContainers"), PodValidationOptions{}, &PodRestartPolicy, noUserNamespace); len(errs) != 0 {
 | 
				
			||||||
			t.Errorf("expected success for '%s' but got errors: %v", title, errs)
 | 
								t.Errorf("expected success for '%s' but got errors: %v", title, errs)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		PodRestartPolicy = "OnFailure"
 | 
							PodRestartPolicy = "OnFailure"
 | 
				
			||||||
		if errs := validateEphemeralContainers(ephemeralContainers, containers, initContainers, vols, nil, field.NewPath("ephemeralContainers"), PodValidationOptions{}, &PodRestartPolicy); len(errs) != 0 {
 | 
							if errs := validateEphemeralContainers(ephemeralContainers, containers, initContainers, vols, nil, field.NewPath("ephemeralContainers"), PodValidationOptions{}, &PodRestartPolicy, noUserNamespace); len(errs) != 0 {
 | 
				
			||||||
			t.Errorf("expected success for '%s' but got errors: %v", title, errs)
 | 
								t.Errorf("expected success for '%s' but got errors: %v", title, errs)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -8230,19 +8231,19 @@ func TestValidateEphemeralContainers(t *testing.T) {
 | 
				
			|||||||
		t.Run(tc.title+"__@L"+tc.line, func(t *testing.T) {
 | 
							t.Run(tc.title+"__@L"+tc.line, func(t *testing.T) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			PodRestartPolicy = "Never"
 | 
								PodRestartPolicy = "Never"
 | 
				
			||||||
			errs := validateEphemeralContainers(tc.ephemeralContainers, containers, initContainers, vols, nil, field.NewPath("ephemeralContainers"), PodValidationOptions{}, &PodRestartPolicy)
 | 
								errs := validateEphemeralContainers(tc.ephemeralContainers, containers, initContainers, vols, nil, field.NewPath("ephemeralContainers"), PodValidationOptions{}, &PodRestartPolicy, noUserNamespace)
 | 
				
			||||||
			if len(errs) == 0 {
 | 
								if len(errs) == 0 {
 | 
				
			||||||
				t.Fatal("expected error but received none")
 | 
									t.Fatal("expected error but received none")
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			PodRestartPolicy = "Always"
 | 
								PodRestartPolicy = "Always"
 | 
				
			||||||
			errs = validateEphemeralContainers(tc.ephemeralContainers, containers, initContainers, vols, nil, field.NewPath("ephemeralContainers"), PodValidationOptions{}, &PodRestartPolicy)
 | 
								errs = validateEphemeralContainers(tc.ephemeralContainers, containers, initContainers, vols, nil, field.NewPath("ephemeralContainers"), PodValidationOptions{}, &PodRestartPolicy, noUserNamespace)
 | 
				
			||||||
			if len(errs) == 0 {
 | 
								if len(errs) == 0 {
 | 
				
			||||||
				t.Fatal("expected error but received none")
 | 
									t.Fatal("expected error but received none")
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			PodRestartPolicy = "OnFailure"
 | 
								PodRestartPolicy = "OnFailure"
 | 
				
			||||||
			errs = validateEphemeralContainers(tc.ephemeralContainers, containers, initContainers, vols, nil, field.NewPath("ephemeralContainers"), PodValidationOptions{}, &PodRestartPolicy)
 | 
								errs = validateEphemeralContainers(tc.ephemeralContainers, containers, initContainers, vols, nil, field.NewPath("ephemeralContainers"), PodValidationOptions{}, &PodRestartPolicy, noUserNamespace)
 | 
				
			||||||
			if len(errs) == 0 {
 | 
								if len(errs) == 0 {
 | 
				
			||||||
				t.Fatal("expected error but received none")
 | 
									t.Fatal("expected error but received none")
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
@@ -8542,7 +8543,7 @@ func TestValidateContainers(t *testing.T) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	var PodRestartPolicy core.RestartPolicy = "Always"
 | 
						var PodRestartPolicy core.RestartPolicy = "Always"
 | 
				
			||||||
	if errs := validateContainers(successCase, volumeDevices, nil, defaultGracePeriod, field.NewPath("field"), PodValidationOptions{}, &PodRestartPolicy); len(errs) != 0 {
 | 
						if errs := validateContainers(successCase, volumeDevices, nil, defaultGracePeriod, field.NewPath("field"), PodValidationOptions{}, &PodRestartPolicy, noUserNamespace); len(errs) != 0 {
 | 
				
			||||||
		t.Errorf("expected success: %v", errs)
 | 
							t.Errorf("expected success: %v", errs)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -9156,7 +9157,7 @@ func TestValidateContainers(t *testing.T) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	for _, tc := range errorCases {
 | 
						for _, tc := range errorCases {
 | 
				
			||||||
		t.Run(tc.title+"__@L"+tc.line, func(t *testing.T) {
 | 
							t.Run(tc.title+"__@L"+tc.line, func(t *testing.T) {
 | 
				
			||||||
			errs := validateContainers(tc.containers, volumeDevices, nil, defaultGracePeriod, field.NewPath("containers"), PodValidationOptions{}, &PodRestartPolicy)
 | 
								errs := validateContainers(tc.containers, volumeDevices, nil, defaultGracePeriod, field.NewPath("containers"), PodValidationOptions{}, &PodRestartPolicy, noUserNamespace)
 | 
				
			||||||
			if len(errs) == 0 {
 | 
								if len(errs) == 0 {
 | 
				
			||||||
				t.Fatal("expected error but received none")
 | 
									t.Fatal("expected error but received none")
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
@@ -9245,7 +9246,7 @@ func TestValidateInitContainers(t *testing.T) {
 | 
				
			|||||||
	},
 | 
						},
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	var PodRestartPolicy core.RestartPolicy = "Never"
 | 
						var PodRestartPolicy core.RestartPolicy = "Never"
 | 
				
			||||||
	if errs := validateInitContainers(successCase, containers, volumeDevices, nil, defaultGracePeriod, field.NewPath("field"), PodValidationOptions{}, &PodRestartPolicy); len(errs) != 0 {
 | 
						if errs := validateInitContainers(successCase, containers, volumeDevices, nil, defaultGracePeriod, field.NewPath("field"), PodValidationOptions{}, &PodRestartPolicy, noUserNamespace); len(errs) != 0 {
 | 
				
			||||||
		t.Errorf("expected success: %v", errs)
 | 
							t.Errorf("expected success: %v", errs)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -9624,7 +9625,7 @@ func TestValidateInitContainers(t *testing.T) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	for _, tc := range errorCases {
 | 
						for _, tc := range errorCases {
 | 
				
			||||||
		t.Run(tc.title+"__@L"+tc.line, func(t *testing.T) {
 | 
							t.Run(tc.title+"__@L"+tc.line, func(t *testing.T) {
 | 
				
			||||||
			errs := validateInitContainers(tc.initContainers, containers, volumeDevices, nil, defaultGracePeriod, field.NewPath("initContainers"), PodValidationOptions{}, &PodRestartPolicy)
 | 
								errs := validateInitContainers(tc.initContainers, containers, volumeDevices, nil, defaultGracePeriod, field.NewPath("initContainers"), PodValidationOptions{}, &PodRestartPolicy, noUserNamespace)
 | 
				
			||||||
			if len(errs) == 0 {
 | 
								if len(errs) == 0 {
 | 
				
			||||||
				t.Fatal("expected error but received none")
 | 
									t.Fatal("expected error but received none")
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
@@ -22624,17 +22625,28 @@ func TestValidateSecurityContext(t *testing.T) {
 | 
				
			|||||||
	noRunAsUser := fullValidSC()
 | 
						noRunAsUser := fullValidSC()
 | 
				
			||||||
	noRunAsUser.RunAsUser = nil
 | 
						noRunAsUser.RunAsUser = nil
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						procMountSet := fullValidSC()
 | 
				
			||||||
 | 
						defPmt := core.DefaultProcMount
 | 
				
			||||||
 | 
						procMountSet.ProcMount = &defPmt
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						umPmt := core.UnmaskedProcMount
 | 
				
			||||||
 | 
						procMountUnmasked := fullValidSC()
 | 
				
			||||||
 | 
						procMountUnmasked.ProcMount = &umPmt
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	successCases := map[string]struct {
 | 
						successCases := map[string]struct {
 | 
				
			||||||
		sc        *core.SecurityContext
 | 
							sc        *core.SecurityContext
 | 
				
			||||||
 | 
							hostUsers bool
 | 
				
			||||||
	}{
 | 
						}{
 | 
				
			||||||
		"all settings":    {allSettings},
 | 
							"all settings":        {allSettings, false},
 | 
				
			||||||
		"no capabilities": {noCaps},
 | 
							"no capabilities":     {noCaps, false},
 | 
				
			||||||
		"no selinux":      {noSELinux},
 | 
							"no selinux":          {noSELinux, false},
 | 
				
			||||||
		"no priv request": {noPrivRequest},
 | 
							"no priv request":     {noPrivRequest, false},
 | 
				
			||||||
		"no run as user":  {noRunAsUser},
 | 
							"no run as user":      {noRunAsUser, false},
 | 
				
			||||||
 | 
							"proc mount set":      {procMountSet, true},
 | 
				
			||||||
 | 
							"proc mount unmasked": {procMountUnmasked, false},
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	for k, v := range successCases {
 | 
						for k, v := range successCases {
 | 
				
			||||||
		if errs := ValidateSecurityContext(v.sc, field.NewPath("field")); len(errs) != 0 {
 | 
							if errs := ValidateSecurityContext(v.sc, field.NewPath("field"), v.hostUsers); len(errs) != 0 {
 | 
				
			||||||
			t.Errorf("[%s] Expected success, got %v", k, errs)
 | 
								t.Errorf("[%s] Expected success, got %v", k, errs)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -22681,12 +22693,19 @@ func TestValidateSecurityContext(t *testing.T) {
 | 
				
			|||||||
			errorDetail:  "cannot set `allowPrivilegeEscalation` to false and `privileged` to true",
 | 
								errorDetail:  "cannot set `allowPrivilegeEscalation` to false and `privileged` to true",
 | 
				
			||||||
			capAllowPriv: true,
 | 
								capAllowPriv: true,
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
 | 
							"with unmasked proc mount type and no user namespace": {
 | 
				
			||||||
 | 
								sc:          procMountUnmasked,
 | 
				
			||||||
 | 
								errorType:   "FieldValueInvalid",
 | 
				
			||||||
 | 
								errorDetail: "`hostUsers` must be false to use `Unmasked`",
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	for k, v := range errorCases {
 | 
						for k, v := range errorCases {
 | 
				
			||||||
		capabilities.SetForTests(capabilities.Capabilities{
 | 
							capabilities.SetForTests(capabilities.Capabilities{
 | 
				
			||||||
			AllowPrivileged: v.capAllowPriv,
 | 
								AllowPrivileged: v.capAllowPriv,
 | 
				
			||||||
		})
 | 
							})
 | 
				
			||||||
		if errs := ValidateSecurityContext(v.sc, field.NewPath("field")); len(errs) == 0 || errs[0].Type != v.errorType || !strings.Contains(errs[0].Detail, v.errorDetail) {
 | 
							// note the unconditional `true` here for hostUsers. The failure case to test for ProcMount only includes it being true,
 | 
				
			||||||
 | 
							// and the field is ignored if ProcMount isn't set. Thus, we can unconditionally set to `true` and simplify the test matrix setup.
 | 
				
			||||||
 | 
							if errs := ValidateSecurityContext(v.sc, field.NewPath("field"), true); len(errs) == 0 || errs[0].Type != v.errorType || !strings.Contains(errs[0].Detail, v.errorDetail) {
 | 
				
			||||||
			t.Errorf("[%s] Expected error type %q with detail %q, got %v", k, v.errorType, v.errorDetail, errs)
 | 
								t.Errorf("[%s] Expected error type %q with detail %q, got %v", k, v.errorType, v.errorDetail, errs)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user