KEP-3619: Fine-grained SupplementalGroups control (#117842)
* Add `Linux{Sandbox,Container}SecurityContext.SupplementalGroupsPolicy` and `ContainerStatus.user` in cri-api * Add `PodSecurityContext.SupplementalGroupsPolicy`, `ContainerStatus.User` and its featuregate * Implement DropDisabledPodFields for PodSecurityContext.SupplementalGroupsPolicy and ContainerStatus.User fields * Implement kubelet so to wire between SecurityContext.SupplementalGroupsPolicy/ContainerStatus.User and cri-api in kubelet * Clarify `SupplementalGroupsPolicy` is an OS depdendent field. * Make `ContainerStatus.User` is initially attached user identity to the first process in the ContainerStatus It is because, the process identity can be dynamic if the initially attached identity has enough privilege calling setuid/setgid/setgroups syscalls in Linux. * Rewording suggestion applied * Add TODO comment for updating SupplementalGroupsPolicy default value in v1.34 * Added validations for SupplementalGroupsPolicy and ContainerUser * No need featuregate check in validation when adding new field with no default value * fix typo: identitiy -> identity
This commit is contained in:
@@ -4318,6 +4318,9 @@ func validateWindows(spec *core.PodSpec, fldPath *field.Path) field.ErrorList {
|
||||
if securityContext.SupplementalGroups != nil {
|
||||
allErrs = append(allErrs, field.Forbidden(fldPath.Child("securityContext").Child("supplementalGroups"), "cannot be set for a windows pod"))
|
||||
}
|
||||
if securityContext.SupplementalGroupsPolicy != nil {
|
||||
allErrs = append(allErrs, field.Forbidden(fldPath.Child("securityContext").Child("supplementalGroupsPolicy"), "cannot be set for a windows pod"))
|
||||
}
|
||||
}
|
||||
podshelper.VisitContainersWithPath(spec, fldPath, func(c *core.Container, cFldPath *field.Path) bool {
|
||||
// validate container security context
|
||||
@@ -4948,6 +4951,10 @@ func validatePodSpecSecurityContext(securityContext *core.PodSecurityContext, sp
|
||||
allErrs = append(allErrs, validateSeccompProfileField(securityContext.SeccompProfile, fldPath.Child("seccompProfile"))...)
|
||||
allErrs = append(allErrs, validateWindowsSecurityContextOptions(securityContext.WindowsOptions, fldPath.Child("windowsOptions"))...)
|
||||
allErrs = append(allErrs, ValidateAppArmorProfileField(securityContext.AppArmorProfile, fldPath.Child("appArmorProfile"))...)
|
||||
|
||||
if securityContext.SupplementalGroupsPolicy != nil {
|
||||
allErrs = append(allErrs, validateSupplementalGroupsPolicy(securityContext.SupplementalGroupsPolicy, fldPath.Child("supplementalGroupsPolicy"))...)
|
||||
}
|
||||
}
|
||||
|
||||
return allErrs
|
||||
@@ -5359,6 +5366,10 @@ func ValidatePodStatusUpdate(newPod, oldPod *core.Pod, opts PodValidationOptions
|
||||
allErrs = append(allErrs, newIPErrs...)
|
||||
}
|
||||
|
||||
allErrs = append(allErrs, validateContainerStatusUsers(newPod.Status.ContainerStatuses, fldPath.Child("containerStatuses"), newPod.Spec.OS)...)
|
||||
allErrs = append(allErrs, validateContainerStatusUsers(newPod.Status.InitContainerStatuses, fldPath.Child("initContainerStatuses"), newPod.Spec.OS)...)
|
||||
allErrs = append(allErrs, validateContainerStatusUsers(newPod.Status.EphemeralContainerStatuses, fldPath.Child("ephemeralContainerStatuses"), newPod.Spec.OS)...)
|
||||
|
||||
return allErrs
|
||||
}
|
||||
|
||||
@@ -8121,3 +8132,56 @@ func validateNodeSelectorTermHasOnlyAdditions(newTerm, oldTerm core.NodeSelector
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
var validSupplementalGroupsPolicies = sets.New(core.SupplementalGroupsPolicyMerge, core.SupplementalGroupsPolicyStrict)
|
||||
|
||||
func validateSupplementalGroupsPolicy(supplementalGroupsPolicy *core.SupplementalGroupsPolicy, fldPath *field.Path) field.ErrorList {
|
||||
allErrors := field.ErrorList{}
|
||||
if !validSupplementalGroupsPolicies.Has(*supplementalGroupsPolicy) {
|
||||
allErrors = append(allErrors, field.NotSupported(fldPath, supplementalGroupsPolicy, sets.List(validSupplementalGroupsPolicies)))
|
||||
}
|
||||
return allErrors
|
||||
}
|
||||
|
||||
func validateContainerStatusUsers(containerStatuses []core.ContainerStatus, fldPath *field.Path, podOS *core.PodOS) field.ErrorList {
|
||||
allErrors := field.ErrorList{}
|
||||
osName := core.Linux
|
||||
if podOS != nil {
|
||||
osName = podOS.Name
|
||||
}
|
||||
for i, containerStatus := range containerStatuses {
|
||||
if containerStatus.User == nil {
|
||||
continue
|
||||
}
|
||||
containerUser := containerStatus.User
|
||||
switch osName {
|
||||
case core.Windows:
|
||||
if containerUser.Linux != nil {
|
||||
allErrors = append(allErrors, field.Forbidden(fldPath.Index(i).Child("linux"), "cannot be set for a windows pod"))
|
||||
}
|
||||
case core.Linux:
|
||||
allErrors = append(allErrors, validateLinuxContainerUser(containerUser.Linux, fldPath.Index(i).Child("linux"))...)
|
||||
}
|
||||
}
|
||||
return allErrors
|
||||
}
|
||||
|
||||
func validateLinuxContainerUser(linuxContainerUser *core.LinuxContainerUser, fldPath *field.Path) field.ErrorList {
|
||||
allErrors := field.ErrorList{}
|
||||
if linuxContainerUser == nil {
|
||||
return allErrors
|
||||
}
|
||||
for _, msg := range validation.IsValidUserID(linuxContainerUser.UID) {
|
||||
allErrors = append(allErrors, field.Invalid(fldPath.Child("uid"), linuxContainerUser.UID, msg))
|
||||
}
|
||||
|
||||
for _, msg := range validation.IsValidGroupID(linuxContainerUser.GID) {
|
||||
allErrors = append(allErrors, field.Invalid(fldPath.Child("gid"), linuxContainerUser.GID, msg))
|
||||
}
|
||||
for g, gid := range linuxContainerUser.SupplementalGroups {
|
||||
for _, msg := range validation.IsValidGroupID(gid) {
|
||||
allErrors = append(allErrors, field.Invalid(fldPath.Child("supplementalGroups").Index(g), gid, msg))
|
||||
}
|
||||
}
|
||||
return allErrors
|
||||
}
|
||||
|
Reference in New Issue
Block a user