Skip to content

Commit

Permalink
Merge pull request kubernetes#87790 from marosset/windows-run-as-user…
Browse files Browse the repository at this point in the history
…name-stable

Moving Windows RunAsUserName feature to GA
  • Loading branch information
k8s-ci-robot authored Feb 25, 2020
2 parents f6525db + d44a30f commit 71b7b51
Show file tree
Hide file tree
Showing 8 changed files with 4 additions and 247 deletions.
2 changes: 1 addition & 1 deletion api/openapi-spec/swagger.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

67 changes: 0 additions & 67 deletions pkg/api/pod/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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 {
Expand Down
174 changes: 0 additions & 174 deletions pkg/api/pod/util_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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{
Expand Down
1 change: 0 additions & 1 deletion pkg/apis/core/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -5090,7 +5090,6 @@ type WindowsSecurityContextOptions struct {
// Defaults to the user specified in image metadata if unspecified.
// May also be set in PodSecurityContext. If set in both SecurityContext and
// PodSecurityContext, the value specified in SecurityContext takes precedence.
// This field is beta-level and may be disabled with the WindowsRunAsUserName feature flag.
// +optional
RunAsUserName *string
}
Expand Down
3 changes: 2 additions & 1 deletion pkg/features/kube_features.go
Original file line number Diff line number Diff line change
Expand Up @@ -432,6 +432,7 @@ const (
// owner: @bclau
// alpha: v1.16
// beta: v1.17
// GA: v1.18
//
// Enables support for running container entrypoints as different usernames than their default ones.
WindowsRunAsUserName featuregate.Feature = "WindowsRunAsUserName"
Expand Down Expand Up @@ -609,7 +610,7 @@ var defaultKubernetesFeatureGates = map[featuregate.Feature]featuregate.FeatureS
TTLAfterFinished: {Default: false, PreRelease: featuregate.Alpha},
KubeletPodResources: {Default: true, PreRelease: featuregate.Beta},
WindowsGMSA: {Default: true, PreRelease: featuregate.Beta},
WindowsRunAsUserName: {Default: true, PreRelease: featuregate.Beta},
WindowsRunAsUserName: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.20
ServiceLoadBalancerFinalizer: {Default: true, PreRelease: featuregate.GA, LockToDefault: true},
LocalStorageCapacityIsolationFSQuotaMonitoring: {Default: false, PreRelease: featuregate.Alpha},
NonPreemptingPriority: {Default: false, PreRelease: featuregate.Alpha},
Expand Down
1 change: 0 additions & 1 deletion staging/src/k8s.io/api/core/v1/generated.proto

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion staging/src/k8s.io/api/core/v1/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -5837,7 +5837,6 @@ type WindowsSecurityContextOptions struct {
// Defaults to the user specified in image metadata if unspecified.
// May also be set in PodSecurityContext. If set in both SecurityContext and
// PodSecurityContext, the value specified in SecurityContext takes precedence.
// This field is beta-level and may be disabled with the WindowsRunAsUserName feature flag.
// +optional
RunAsUserName *string `json:"runAsUserName,omitempty" protobuf:"bytes,3,opt,name=runAsUserName"`
}
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 71b7b51

Please sign in to comment.