mirror of
https://github.com/k3s-io/kubernetes.git
synced 2026-01-05 07:27:21 +00:00
Moving Windows RunAsUserName feature to GA
This commit is contained in:
@@ -391,8 +391,6 @@ func dropDisabledFields(
|
||||
|
||||
dropDisabledGMSAFields(podSpec, oldPodSpec)
|
||||
|
||||
dropDisabledRunAsUserNameFields(podSpec, oldPodSpec)
|
||||
|
||||
if !utilfeature.DefaultFeatureGate.Enabled(features.RuntimeClass) && !runtimeClassInUse(oldPodSpec) {
|
||||
// Set RuntimeClassName to nil only if feature is disabled and it is not used
|
||||
podSpec.RuntimeClassName = nil
|
||||
@@ -469,38 +467,6 @@ func dropDisabledGMSAFieldsFromContainers(containers []api.Container) {
|
||||
}
|
||||
}
|
||||
|
||||
// dropDisabledRunAsUserNameFields removes disabled fields related to WindowsOptions.RunAsUserName
|
||||
// from the given PodSpec.
|
||||
func dropDisabledRunAsUserNameFields(podSpec, oldPodSpec *api.PodSpec) {
|
||||
if utilfeature.DefaultFeatureGate.Enabled(features.WindowsRunAsUserName) ||
|
||||
runAsUserNameFieldsInUse(oldPodSpec) {
|
||||
return
|
||||
}
|
||||
|
||||
if podSpec.SecurityContext != nil {
|
||||
dropDisabledRunAsUserNameFieldsFromWindowsSecurityOptions(podSpec.SecurityContext.WindowsOptions)
|
||||
}
|
||||
dropDisabledRunAsUserNameFieldsFromContainers(podSpec.Containers)
|
||||
dropDisabledRunAsUserNameFieldsFromContainers(podSpec.InitContainers)
|
||||
}
|
||||
|
||||
// dropDisabledRunAsUserNameFieldsFromWindowsSecurityOptions removes disabled fields
|
||||
// related to RunAsUserName from the given WindowsSecurityContextOptions.
|
||||
func dropDisabledRunAsUserNameFieldsFromWindowsSecurityOptions(windowsOptions *api.WindowsSecurityContextOptions) {
|
||||
if windowsOptions != nil {
|
||||
windowsOptions.RunAsUserName = nil
|
||||
}
|
||||
}
|
||||
|
||||
// dropDisabledRunAsUserNameFieldsFromContainers removes disabled fields
|
||||
func dropDisabledRunAsUserNameFieldsFromContainers(containers []api.Container) {
|
||||
for i := range containers {
|
||||
if containers[i].SecurityContext != nil {
|
||||
dropDisabledRunAsUserNameFieldsFromWindowsSecurityOptions(containers[i].SecurityContext.WindowsOptions)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// dropDisabledProcMountField removes disabled fields from PodSpec related
|
||||
// to ProcMount only if it is not already used by the old spec
|
||||
func dropDisabledProcMountField(podSpec, oldPodSpec *api.PodSpec) {
|
||||
@@ -758,39 +724,6 @@ func gMSAFieldsInUseInAnyContainer(containers []api.Container) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// runAsUserNameFieldsInUse returns true if the pod spec is non-nil and has the RunAsUserName
|
||||
// field set in the PodSecurityContext or any container's SecurityContext.
|
||||
func runAsUserNameFieldsInUse(podSpec *api.PodSpec) bool {
|
||||
if podSpec == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
if podSpec.SecurityContext != nil && runAsUserNameFieldsInUseInWindowsSecurityOptions(podSpec.SecurityContext.WindowsOptions) {
|
||||
return true
|
||||
}
|
||||
|
||||
return runAsUserNameFieldsInUseInAnyContainer(podSpec.Containers) ||
|
||||
runAsUserNameFieldsInUseInAnyContainer(podSpec.InitContainers)
|
||||
}
|
||||
|
||||
// runAsUserNameFieldsInUseInWindowsSecurityOptions returns true if the given WindowsSecurityContextOptions is
|
||||
// non-nil and its RunAsUserName field is set.
|
||||
func runAsUserNameFieldsInUseInWindowsSecurityOptions(windowsOptions *api.WindowsSecurityContextOptions) bool {
|
||||
return windowsOptions != nil && windowsOptions.RunAsUserName != nil
|
||||
}
|
||||
|
||||
// runAsUserNameFieldsInUseInAnyContainer returns true if any of the given Containers has its
|
||||
// SecurityContext's RunAsUserName field set.
|
||||
func runAsUserNameFieldsInUseInAnyContainer(containers []api.Container) bool {
|
||||
for _, container := range containers {
|
||||
if container.SecurityContext != nil && runAsUserNameFieldsInUseInWindowsSecurityOptions(container.SecurityContext.WindowsOptions) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// subpathExprInUse returns true if the pod spec is non-nil and has a volume mount that makes use of the subPathExpr feature
|
||||
func subpathExprInUse(podSpec *api.PodSpec) bool {
|
||||
if podSpec == nil {
|
||||
|
||||
@@ -1517,180 +1517,6 @@ func TestDropGMSAFields(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestDropWindowsRunAsUserNameFields(t *testing.T) {
|
||||
defaultContainerSecurityContextFactory := func() *api.SecurityContext {
|
||||
defaultProcMount := api.DefaultProcMount
|
||||
return &api.SecurityContext{ProcMount: &defaultProcMount}
|
||||
}
|
||||
podWithoutWindowsOptionsFactory := func() *api.Pod {
|
||||
return &api.Pod{
|
||||
Spec: api.PodSpec{
|
||||
RestartPolicy: api.RestartPolicyNever,
|
||||
SecurityContext: &api.PodSecurityContext{},
|
||||
Containers: []api.Container{{Name: "container1", Image: "testimage", SecurityContext: defaultContainerSecurityContextFactory()}},
|
||||
InitContainers: []api.Container{{Name: "initContainer1", Image: "testimage", SecurityContext: defaultContainerSecurityContextFactory()}},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
type podFactoryInfo struct {
|
||||
description string
|
||||
hasRunAsUserNameField bool
|
||||
// this factory should generate the input pod whose spec will be fed to dropDisabledFields
|
||||
podFactory func() *api.Pod
|
||||
// this factory should generate the expected pod after the RunAsUserName fields have been dropped
|
||||
// we can't just use podWithoutWindowsOptionsFactory as is for this, since in some cases
|
||||
// we'll be left with a WindowsSecurityContextOptions struct with no RunAsUserName field set,
|
||||
// as oposed to a nil pointer in the pod generated by podWithoutWindowsOptionsFactory
|
||||
// if this field is not set, it will default to the podFactory
|
||||
strippedPodFactory func() *api.Pod
|
||||
}
|
||||
|
||||
toPtr := func(s string) *string {
|
||||
return &s
|
||||
}
|
||||
|
||||
podFactoryInfos := []podFactoryInfo{
|
||||
{
|
||||
description: "is nil",
|
||||
hasRunAsUserNameField: false,
|
||||
podFactory: func() *api.Pod { return nil },
|
||||
},
|
||||
{
|
||||
description: "does not have any RunAsUserName field set",
|
||||
hasRunAsUserNameField: false,
|
||||
podFactory: podWithoutWindowsOptionsFactory,
|
||||
},
|
||||
{
|
||||
description: "has a pod-level WindowsSecurityContextOptions struct with no RunAsUserName field set",
|
||||
hasRunAsUserNameField: false,
|
||||
podFactory: func() *api.Pod {
|
||||
pod := podWithoutWindowsOptionsFactory()
|
||||
pod.Spec.SecurityContext.WindowsOptions = &api.WindowsSecurityContextOptions{}
|
||||
return pod
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "has a WindowsSecurityContextOptions struct with no RunAsUserName field set on a container",
|
||||
hasRunAsUserNameField: false,
|
||||
podFactory: func() *api.Pod {
|
||||
pod := podWithoutWindowsOptionsFactory()
|
||||
pod.Spec.Containers[0].SecurityContext.WindowsOptions = &api.WindowsSecurityContextOptions{}
|
||||
return pod
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "has a WindowsSecurityContextOptions struct with no RunAsUserName field set on an init container",
|
||||
hasRunAsUserNameField: false,
|
||||
podFactory: func() *api.Pod {
|
||||
pod := podWithoutWindowsOptionsFactory()
|
||||
pod.Spec.InitContainers[0].SecurityContext.WindowsOptions = &api.WindowsSecurityContextOptions{}
|
||||
return pod
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "has RunAsUserName field set in the PodSecurityContext",
|
||||
hasRunAsUserNameField: true,
|
||||
podFactory: func() *api.Pod {
|
||||
pod := podWithoutWindowsOptionsFactory()
|
||||
pod.Spec.SecurityContext.WindowsOptions = &api.WindowsSecurityContextOptions{RunAsUserName: toPtr("foo-lish")}
|
||||
return pod
|
||||
},
|
||||
strippedPodFactory: func() *api.Pod {
|
||||
pod := podWithoutWindowsOptionsFactory()
|
||||
pod.Spec.SecurityContext.WindowsOptions = &api.WindowsSecurityContextOptions{}
|
||||
return pod
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "has RunAsUserName field set in a container's SecurityContext",
|
||||
hasRunAsUserNameField: true,
|
||||
podFactory: func() *api.Pod {
|
||||
pod := podWithoutWindowsOptionsFactory()
|
||||
pod.Spec.Containers[0].SecurityContext.WindowsOptions = &api.WindowsSecurityContextOptions{RunAsUserName: toPtr("foo-lish")}
|
||||
return pod
|
||||
},
|
||||
strippedPodFactory: func() *api.Pod {
|
||||
pod := podWithoutWindowsOptionsFactory()
|
||||
pod.Spec.Containers[0].SecurityContext.WindowsOptions = &api.WindowsSecurityContextOptions{}
|
||||
return pod
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "has RunAsUserName field set in an init container's PodSecurityContext",
|
||||
hasRunAsUserNameField: true,
|
||||
podFactory: func() *api.Pod {
|
||||
pod := podWithoutWindowsOptionsFactory()
|
||||
pod.Spec.InitContainers[0].SecurityContext.WindowsOptions = &api.WindowsSecurityContextOptions{RunAsUserName: toPtr("foo-lish")}
|
||||
return pod
|
||||
},
|
||||
strippedPodFactory: func() *api.Pod {
|
||||
pod := podWithoutWindowsOptionsFactory()
|
||||
pod.Spec.InitContainers[0].SecurityContext.WindowsOptions = &api.WindowsSecurityContextOptions{}
|
||||
return pod
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, enabled := range []bool{true, false} {
|
||||
for _, oldPodFactoryInfo := range podFactoryInfos {
|
||||
for _, newPodFactoryInfo := range podFactoryInfos {
|
||||
newPodHasRunAsUserNameField, newPod := newPodFactoryInfo.hasRunAsUserNameField, newPodFactoryInfo.podFactory()
|
||||
if newPod == nil {
|
||||
continue
|
||||
}
|
||||
oldPodHasRunAsUserNameField, oldPod := oldPodFactoryInfo.hasRunAsUserNameField, oldPodFactoryInfo.podFactory()
|
||||
|
||||
t.Run(fmt.Sprintf("feature enabled=%v, old pod %s, new pod %s", enabled, oldPodFactoryInfo.description, newPodFactoryInfo.description), func(t *testing.T) {
|
||||
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.WindowsRunAsUserName, enabled)()
|
||||
|
||||
var oldPodSpec *api.PodSpec
|
||||
if oldPod != nil {
|
||||
oldPodSpec = &oldPod.Spec
|
||||
}
|
||||
dropDisabledFields(&newPod.Spec, nil, oldPodSpec, nil)
|
||||
|
||||
// old pod should never be changed
|
||||
if !reflect.DeepEqual(oldPod, oldPodFactoryInfo.podFactory()) {
|
||||
t.Errorf("old pod changed: %v", diff.ObjectReflectDiff(oldPod, oldPodFactoryInfo.podFactory()))
|
||||
}
|
||||
|
||||
switch {
|
||||
case enabled || oldPodHasRunAsUserNameField:
|
||||
// new pod should not be changed if the feature is enabled, or if the old pod had the RunAsUserName field set
|
||||
if !reflect.DeepEqual(newPod, newPodFactoryInfo.podFactory()) {
|
||||
t.Errorf("new pod changed: %v", diff.ObjectReflectDiff(newPod, newPodFactoryInfo.podFactory()))
|
||||
}
|
||||
case newPodHasRunAsUserNameField:
|
||||
// new pod should be changed
|
||||
if reflect.DeepEqual(newPod, newPodFactoryInfo.podFactory()) {
|
||||
t.Errorf("%v", oldPod)
|
||||
t.Errorf("%v", newPod)
|
||||
t.Errorf("new pod was not changed")
|
||||
}
|
||||
// new pod should not have the RunAsUserName field set
|
||||
var expectedStrippedPod *api.Pod
|
||||
if newPodFactoryInfo.strippedPodFactory == nil {
|
||||
expectedStrippedPod = newPodFactoryInfo.podFactory()
|
||||
} else {
|
||||
expectedStrippedPod = newPodFactoryInfo.strippedPodFactory()
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(newPod, expectedStrippedPod) {
|
||||
t.Errorf("new pod had some RunAsUserName field set: %v", diff.ObjectReflectDiff(newPod, expectedStrippedPod))
|
||||
}
|
||||
default:
|
||||
// new pod should not need to be changed
|
||||
if !reflect.DeepEqual(newPod, newPodFactoryInfo.podFactory()) {
|
||||
t.Errorf("new pod changed: %v", diff.ObjectReflectDiff(newPod, newPodFactoryInfo.podFactory()))
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestDropPodSysctls(t *testing.T) {
|
||||
podWithSysctls := func() *api.Pod {
|
||||
return &api.Pod{
|
||||
|
||||
Reference in New Issue
Block a user