Skip to content

Commit cd8686b

Browse files
Strip unnecessary security contexts on Windows
As of now, the kubelet is passing the security context to container runtime even if the security context has invalid options for a particular OS. As a result, the pod fails to come up on the node. This error is particularly pronounced on the Windows nodes where kubelet is allowing Linux specific options like SELinux, RunAsUser etc where as in [documentation](https://kubernetes.io/docs/setup/production-environment/windows/intro-windows-in-kubernetes/#v1-container), we clearly state they are not supported. This PR ensures that the kubelet strips the security contexts of the pod, if they don't make sense on the Windows OS.
1 parent 5a50c5c commit cd8686b

File tree

3 files changed

+34
-10
lines changed

3 files changed

+34
-10
lines changed

pkg/kubelet/kuberuntime/kuberuntime_container_windows.go

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ limitations under the License.
1919
package kuberuntime
2020

2121
import (
22-
"fmt"
2322
"runtime"
2423

2524
"k8s.io/api/core/v1"
@@ -125,10 +124,7 @@ func (m *kubeGenericRuntimeManager) generateWindowsContainerConfig(container *v1
125124

126125
// setup security context
127126
effectiveSc := securitycontext.DetermineEffectiveSecurityContext(pod, container)
128-
// RunAsUser only supports int64 from Kubernetes API, but Windows containers only support username.
129-
if effectiveSc.RunAsUser != nil {
130-
return nil, fmt.Errorf("run as uid (%d) is not supported on Windows", *effectiveSc.RunAsUser)
131-
}
127+
132128
if username != "" {
133129
wc.SecurityContext.RunAsUsername = username
134130
}

pkg/kubelet/kuberuntime/kuberuntime_sandbox.go

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import (
2020
"fmt"
2121
"net"
2222
"net/url"
23+
"runtime"
2324
"sort"
2425

2526
v1 "k8s.io/api/core/v1"
@@ -143,6 +144,9 @@ func (m *kubeGenericRuntimeManager) generatePodSandboxConfig(pod *v1.Pod, attemp
143144
}
144145

145146
// generatePodSandboxLinuxConfig generates LinuxPodSandboxConfig from v1.Pod.
147+
// We've to call PodSandboxLinuxConfig always irrespective of the underlying OS as securityContext is not part of
148+
// podSandboxConfig. It is currently part of LinuxPodSandboxConfig. In future, if we have securityContext pulled out
149+
// in podSandboxConfig we should be able to use it.
146150
func (m *kubeGenericRuntimeManager) generatePodSandboxLinuxConfig(pod *v1.Pod) (*runtimeapi.LinuxPodSandboxConfig, error) {
147151
cgroupParent := m.runtimeHelper.GetPodCgroupParent(pod)
148152
lc := &runtimeapi.LinuxPodSandboxConfig{
@@ -169,15 +173,15 @@ func (m *kubeGenericRuntimeManager) generatePodSandboxLinuxConfig(pod *v1.Pod) (
169173

170174
if pod.Spec.SecurityContext != nil {
171175
sc := pod.Spec.SecurityContext
172-
if sc.RunAsUser != nil {
176+
if sc.RunAsUser != nil && runtime.GOOS != "windows" {
173177
lc.SecurityContext.RunAsUser = &runtimeapi.Int64Value{Value: int64(*sc.RunAsUser)}
174178
}
175-
if sc.RunAsGroup != nil {
179+
if sc.RunAsGroup != nil && runtime.GOOS != "windows" {
176180
lc.SecurityContext.RunAsGroup = &runtimeapi.Int64Value{Value: int64(*sc.RunAsGroup)}
177181
}
178182
lc.SecurityContext.NamespaceOptions = namespacesForPod(pod)
179183

180-
if sc.FSGroup != nil {
184+
if sc.FSGroup != nil && runtime.GOOS != "windows" {
181185
lc.SecurityContext.SupplementalGroups = append(lc.SecurityContext.SupplementalGroups, int64(*sc.FSGroup))
182186
}
183187
if groups := m.runtimeHelper.GetExtraSupplementalGroupsForPod(pod); len(groups) > 0 {
@@ -188,7 +192,7 @@ func (m *kubeGenericRuntimeManager) generatePodSandboxLinuxConfig(pod *v1.Pod) (
188192
lc.SecurityContext.SupplementalGroups = append(lc.SecurityContext.SupplementalGroups, int64(sg))
189193
}
190194
}
191-
if sc.SELinuxOptions != nil {
195+
if sc.SELinuxOptions != nil && runtime.GOOS != "windows" {
192196
lc.SecurityContext.SelinuxOptions = &runtimeapi.SELinuxOption{
193197
User: sc.SELinuxOptions.User,
194198
Role: sc.SELinuxOptions.Role,

test/e2e/windows/security_context.go

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ import (
3131

3232
const runAsUserNameContainerName = "run-as-username-container"
3333

34-
var _ = SIGDescribe("[Feature:Windows] SecurityContext RunAsUserName", func() {
34+
var _ = SIGDescribe("[Feature:Windows] SecurityContext", func() {
3535
f := framework.NewDefaultFramework("windows-run-as-username")
3636

3737
ginkgo.It("should be able create pods and run containers with a given username", func() {
@@ -71,6 +71,29 @@ var _ = SIGDescribe("[Feature:Windows] SecurityContext RunAsUserName", func() {
7171
f.TestContainerOutput("check overridden username", pod, 0, []string{"ContainerUser"})
7272
f.TestContainerOutput("check pod SecurityContext username", pod, 1, []string{"ContainerAdministrator"})
7373
})
74+
ginkgo.It("should ignore Linux Specific SecurityContext if set", func() {
75+
ginkgo.By("Creating a pod with SELinux options")
76+
// It is sufficient to show that the pod comes up here. Since we're stripping the SELinux and other linux
77+
// security contexts in apiserver and not updating the pod object in the apiserver, we cannot validate the
78+
// the pod object to not have those security contexts. However the pod coming to running state is a sufficient
79+
// enough condition for us to validate since prior to https://github.com/kubernetes/kubernetes/pull/93475
80+
// the pod would have failed to come up.
81+
windowsPodWithSELinux := createTestPod(f, windowsBusyBoximage, windowsOS)
82+
windowsPodWithSELinux.Spec.Containers[0].Args = []string{"test-webserver-with-selinux"}
83+
windowsPodWithSELinux.Spec.SecurityContext = &v1.PodSecurityContext{}
84+
containerUserName := "ContainerAdministrator"
85+
windowsPodWithSELinux.Spec.SecurityContext.SELinuxOptions = &v1.SELinuxOptions{Level: "s0:c24,c9"}
86+
windowsPodWithSELinux.Spec.Containers[0].SecurityContext = &v1.SecurityContext{
87+
SELinuxOptions: &v1.SELinuxOptions{Level: "s0:c24,c9"},
88+
WindowsOptions: &v1.WindowsSecurityContextOptions{RunAsUserName: &containerUserName}}
89+
windowsPodWithSELinux.Spec.Tolerations = []v1.Toleration{{Key: "os", Value: "Windows"}}
90+
windowsPodWithSELinux, err := f.ClientSet.CoreV1().Pods(f.Namespace.Name).Create(context.TODO(),
91+
windowsPodWithSELinux, metav1.CreateOptions{})
92+
framework.ExpectNoError(err)
93+
framework.Logf("Created pod %v", windowsPodWithSELinux)
94+
framework.ExpectNoError(e2epod.WaitForPodNameRunningInNamespace(f.ClientSet, windowsPodWithSELinux.Name,
95+
f.Namespace.Name), "failed to wait for pod %s to be running", windowsPodWithSELinux.Name)
96+
})
7497
})
7598

7699
func runAsUserNamePod(username *string) *v1.Pod {
@@ -80,6 +103,7 @@ func runAsUserNamePod(username *string) *v1.Pod {
80103
Name: podName,
81104
},
82105
Spec: v1.PodSpec{
106+
NodeSelector: map[string]string{"kubernetes.io/os": "windows"},
83107
Containers: []v1.Container{
84108
{
85109
Name: runAsUserNameContainerName,

0 commit comments

Comments
 (0)