diff --git a/staging/src/k8s.io/pod-security-admission/policy/check_dropCapabilities.go b/staging/src/k8s.io/pod-security-admission/policy/check_dropCapabilities.go index 602bbb286eb..894cd86b4e5 100644 --- a/staging/src/k8s.io/pod-security-admission/policy/check_dropCapabilities.go +++ b/staging/src/k8s.io/pod-security-admission/policy/check_dropCapabilities.go @@ -29,7 +29,7 @@ import ( const ( capabilityAll = "ALL" - capabilityNetBindService = "CAP_NET_BIND_SERVICE" + capabilityNetBindService = "NET_BIND_SERVICE" ) func init() { @@ -52,12 +52,18 @@ func CheckDropCapabilities() Check { } func dropCapabilities_1_22(podMetadata *metav1.ObjectMeta, podSpec *corev1.PodSpec) CheckResult { - containers := sets.NewString() + var ( + containersMissingDropAll []string + containersAddingForbidden []string + forbiddenCapabilities = sets.NewString() + ) + visitContainersWithPath(podSpec, field.NewPath("spec"), func(container *corev1.Container, path *field.Path) { if container.SecurityContext == nil || container.SecurityContext.Capabilities == nil { - containers.Insert(container.Name) + containersMissingDropAll = append(containersMissingDropAll, container.Name) return } + found := false for _, c := range container.SecurityContext.Capabilities.Drop { if c == capabilityAll { @@ -66,23 +72,29 @@ func dropCapabilities_1_22(podMetadata *metav1.ObjectMeta, podSpec *corev1.PodSp } } if !found { - containers.Insert(container.Name) - return + containersMissingDropAll = append(containersMissingDropAll, container.Name) } - for index, c := range container.SecurityContext.Capabilities.Add { + + for _, c := range container.SecurityContext.Capabilities.Add { if c != capabilityNetBindService { - capabilityPath := path.Child("securityContext", "capabilities", "add").Index(index) - msg := fmt.Sprintf("%s=%s", capabilityPath.String(), string(c)) - containers.Insert(msg) + containersAddingForbidden = append(containersAddingForbidden, container.Name) + forbiddenCapabilities.Insert(string(c)) } } }) - if len(containers) > 0 { + var forbiddenDetails []string + if len(containersMissingDropAll) > 0 { + forbiddenDetails = append(forbiddenDetails, fmt.Sprintf("containers %q must drop ALL", containersMissingDropAll)) + } + if len(containersAddingForbidden) > 0 { + forbiddenDetails = append(forbiddenDetails, fmt.Sprintf("containers %q must not add %q", containersAddingForbidden, forbiddenCapabilities.List())) + } + if len(forbiddenDetails) > 0 { return CheckResult{ Allowed: false, - ForbiddenReason: "containers must drop ALL capability", - ForbiddenDetail: strings.Join(containers.List(), ", "), + ForbiddenReason: "containers must restrict capabilities", + ForbiddenDetail: strings.Join(forbiddenDetails, "; "), } } return CheckResult{Allowed: true} diff --git a/staging/src/k8s.io/pod-security-admission/test/fixtures.go b/staging/src/k8s.io/pod-security-admission/test/fixtures.go index 3e2af52b60c..33d801c1c9d 100644 --- a/staging/src/k8s.io/pod-security-admission/test/fixtures.go +++ b/staging/src/k8s.io/pod-security-admission/test/fixtures.go @@ -66,6 +66,13 @@ func init() { } }) minimalValidPods[api.LevelRestricted][api.MajorMinorVersion(1, 19)] = restricted_1_19 + + // 1.22+: capabilities.drop=["ALL"] + restricted_1_22 := tweak(restricted_1_19, func(p *corev1.Pod) { + p.Spec.Containers[0].SecurityContext.Capabilities = &corev1.Capabilities{Drop: []corev1.Capability{"ALL"}} + p.Spec.InitContainers[0].SecurityContext.Capabilities = &corev1.Capabilities{Drop: []corev1.Capability{"ALL"}} + }) + minimalValidPods[api.LevelRestricted][api.MajorMinorVersion(1, 22)] = restricted_1_22 } // getValidPod returns a minimal valid pod for the specified level and version. diff --git a/staging/src/k8s.io/pod-security-admission/test/fixtures_addCapabilities.go b/staging/src/k8s.io/pod-security-admission/test/fixtures_addCapabilities.go index 5a00b015b1d..6d752de6c10 100644 --- a/staging/src/k8s.io/pod-security-admission/test/fixtures_addCapabilities.go +++ b/staging/src/k8s.io/pod-security-admission/test/fixtures_addCapabilities.go @@ -50,9 +50,11 @@ func init() { expectErrorSubstring: "forbidden capabilities", generatePass: func(p *corev1.Pod) []*corev1.Pod { // don't generate fixtures if minimal valid pod drops ALL - for _, capability := range p.Spec.Containers[0].SecurityContext.Capabilities.Drop { - if capability == corev1.Capability("ALL") { - return nil + if p.Spec.Containers[0].SecurityContext != nil && p.Spec.Containers[0].SecurityContext.Capabilities != nil { + for _, capability := range p.Spec.Containers[0].SecurityContext.Capabilities.Drop { + if capability == corev1.Capability("ALL") { + return nil + } } } diff --git a/staging/src/k8s.io/pod-security-admission/test/fixtures_dropCapabilities.go b/staging/src/k8s.io/pod-security-admission/test/fixtures_dropCapabilities.go index 31893d873e8..e2e791b21f3 100644 --- a/staging/src/k8s.io/pod-security-admission/test/fixtures_dropCapabilities.go +++ b/staging/src/k8s.io/pod-security-admission/test/fixtures_dropCapabilities.go @@ -1,9 +1,12 @@ /* Copyright 2021 The Kubernetes Authors. + Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -27,8 +30,9 @@ containerFields: []string{ func init() { fixtureData_1_22 := fixtureGenerator{ - expectErrorSubstring: "drop all", + expectErrorSubstring: "restrict capabilities", generatePass: func(p *corev1.Pod) []*corev1.Pod { + p = ensureCapabilities(p) return []*corev1.Pod{ tweak(p, func(p *corev1.Pod) { p.Spec.Containers[0].SecurityContext.Capabilities.Drop = []corev1.Capability{"ALL"} @@ -37,8 +41,8 @@ func init() { tweak(p, func(p *corev1.Pod) { p.Spec.Containers[0].SecurityContext.Capabilities.Drop = []corev1.Capability{"ALL"} p.Spec.InitContainers[0].SecurityContext.Capabilities.Drop = []corev1.Capability{"ALL"} - p.Spec.Containers[0].SecurityContext.Capabilities.Add = []corev1.Capability{"CAP_NET_BIND_SERVICE"} - p.Spec.InitContainers[0].SecurityContext.Capabilities.Add = []corev1.Capability{"CAP_NET_BIND_SERVICE"} + p.Spec.Containers[0].SecurityContext.Capabilities.Add = []corev1.Capability{"NET_BIND_SERVICE"} + p.Spec.InitContainers[0].SecurityContext.Capabilities.Add = []corev1.Capability{"NET_BIND_SERVICE"} }), } }, @@ -51,44 +55,34 @@ func init() { }), tweak(p, func(p *corev1.Pod) { p.Spec.Containers[0].SecurityContext.Capabilities.Drop = []corev1.Capability{ - "CAP_SYS_TIME", "CAP_SYS_MODULE", "CAP_SYS_RAWIO", "CAP_SYS_PACCT", "CAP_SYS_ADMIN", "CAP_SYS_NICE", - "CAP_SYS_RESOURCE", "CAP_SYS_TIME", "CAP_SYS_TTY_CONFIG", "CAP_MKNOD", "CAP_AUDIT_WRITE", - "CAP_AUDIT_CONTROL", "CAP_MAC_OVERRIDE", "CAP_MAC_ADMIN", "CAP_NET_ADMIN", "CAP_SYSLOG", - "CAP_CHOWN", "CAP_NET_RAW", "CAP_DAC_OVERRIDE", "CAP_FOWNER", "CAP_DAC_READ_SEARCH", - "CAP_FSETID", "CAP_KILL", "CAP_SETGID", "CAP_SETUID", "CAP_LINUX_IMMUTABLE", "CAP_NET_BIND_SERVICE", - "CAP_NET_BROADCAST", "CAP_IPC_LOCK", "CAP_IPC_OWNER", "CAP_SYS_CHROOT", "CAP_SYS_PTRACE", - "CAP_SYS_BOOT", "CAP_LEASE", "CAP_SETFCAP", "CAP_WAKE_ALARM", "CAP_BLOCK_SUSPEND", + "SYS_TIME", "SYS_MODULE", "SYS_RAWIO", "SYS_PACCT", "SYS_ADMIN", "SYS_NICE", + "SYS_RESOURCE", "SYS_TIME", "SYS_TTY_CONFIG", "MKNOD", "AUDIT_WRITE", + "AUDIT_CONTROL", "MAC_OVERRIDE", "MAC_ADMIN", "NET_ADMIN", "SYSLOG", + "CHOWN", "NET_RAW", "DAC_OVERRIDE", "FOWNER", "DAC_READ_SEARCH", + "FSETID", "KILL", "SETGID", "SETUID", "LINUX_IMMUTABLE", "NET_BIND_SERVICE", + "NET_BROADCAST", "IPC_LOCK", "IPC_OWNER", "SYS_CHROOT", "SYS_PTRACE", + "SYS_BOOT", "LEASE", "SETFCAP", "WAKE_ALARM", "BLOCK_SUSPEND", } p.Spec.InitContainers[0].SecurityContext.Capabilities.Drop = []corev1.Capability{ - "CAP_SYS_TIME", "CAP_SYS_MODULE", "CAP_SYS_RAWIO", "CAP_SYS_PACCT", "CAP_SYS_ADMIN", "CAP_SYS_NICE", - "CAP_SYS_RESOURCE", "CAP_SYS_TIME", "CAP_SYS_TTY_CONFIG", "CAP_MKNOD", "CAP_AUDIT_WRITE", - "CAP_AUDIT_CONTROL", "CAP_MAC_OVERRIDE", "CAP_MAC_ADMIN", "CAP_NET_ADMIN", "CAP_SYSLOG", - "CAP_CHOWN", "CAP_NET_RAW", "CAP_DAC_OVERRIDE", "CAP_FOWNER", "CAP_DAC_READ_SEARCH", - "CAP_FSETID", "CAP_KILL", "CAP_SETGID", "CAP_SETUID", "CAP_LINUX_IMMUTABLE", "CAP_NET_BIND_SERVICE", - "CAP_NET_BROADCAST", "CAP_IPC_LOCK", "CAP_IPC_OWNER", "CAP_SYS_CHROOT", "CAP_SYS_PTRACE", - "CAP_SYS_BOOT", "CAP_LEASE", "CAP_SETFCAP", "CAP_WAKE_ALARM", "CAP_BLOCK_SUSPEND", + "SYS_TIME", "SYS_MODULE", "SYS_RAWIO", "SYS_PACCT", "SYS_ADMIN", "SYS_NICE", + "SYS_RESOURCE", "SYS_TIME", "SYS_TTY_CONFIG", "MKNOD", "AUDIT_WRITE", + "AUDIT_CONTROL", "MAC_OVERRIDE", "MAC_ADMIN", "NET_ADMIN", "SYSLOG", + "CHOWN", "NET_RAW", "DAC_OVERRIDE", "FOWNER", "DAC_READ_SEARCH", + "FSETID", "KILL", "SETGID", "SETUID", "LINUX_IMMUTABLE", "NET_BIND_SERVICE", + "NET_BROADCAST", "IPC_LOCK", "IPC_OWNER", "SYS_CHROOT", "SYS_PTRACE", + "SYS_BOOT", "LEASE", "SETFCAP", "WAKE_ALARM", "BLOCK_SUSPEND", } }), tweak(p, func(p *corev1.Pod) { p.Spec.Containers[0].SecurityContext.Capabilities.Drop = []corev1.Capability{"ALL"} p.Spec.InitContainers[0].SecurityContext.Capabilities.Drop = []corev1.Capability{"ALL"} p.Spec.Containers[0].SecurityContext.Capabilities.Add = []corev1.Capability{ - "CAP_SYS_TIME", "CAP_SYS_MODULE", "CAP_SYS_RAWIO", "CAP_SYS_PACCT", "CAP_SYS_ADMIN", "CAP_SYS_NICE", - "CAP_SYS_RESOURCE", "CAP_SYS_TIME", "CAP_SYS_TTY_CONFIG", "CAP_MKNOD", "CAP_AUDIT_WRITE", - "CAP_AUDIT_CONTROL", "CAP_MAC_OVERRIDE", "CAP_MAC_ADMIN", "CAP_NET_ADMIN", "CAP_SYSLOG", - "CAP_CHOWN", "CAP_NET_RAW", "CAP_DAC_OVERRIDE", "CAP_FOWNER", "CAP_DAC_READ_SEARCH", - "CAP_FSETID", "CAP_KILL", "CAP_SETGID", "CAP_SETUID", "CAP_LINUX_IMMUTABLE", "CAP_NET_BROADCAST", - "CAP_IPC_LOCK", "CAP_IPC_OWNER", "CAP_SYS_CHROOT", "CAP_SYS_PTRACE", "CAP_SYS_BOOT", "CAP_LEASE", - "CAP_SETFCAP", "CAP_WAKE_ALARM", "CAP_BLOCK_SUSPEND", + // try adding back capabilities other than NET_BIND_SERVICE, should be forbidden + "AUDIT_WRITE", "CHOWN", "DAC_OVERRIDE", "FOWNER", "FSETID", "KILL", "MKNOD", "NET_BIND_SERVICE", "SETFCAP", "SETGID", "SETPCAP", "SETUID", "SYS_CHROOT", } p.Spec.InitContainers[0].SecurityContext.Capabilities.Add = []corev1.Capability{ - "CAP_SYS_TIME", "CAP_SYS_MODULE", "CAP_SYS_RAWIO", "CAP_SYS_PACCT", "CAP_SYS_ADMIN", "CAP_SYS_NICE", - "CAP_SYS_RESOURCE", "CAP_SYS_TIME", "CAP_SYS_TTY_CONFIG", "CAP_MKNOD", "CAP_AUDIT_WRITE", - "CAP_AUDIT_CONTROL", "CAP_MAC_OVERRIDE", "CAP_MAC_ADMIN", "CAP_NET_ADMIN", "CAP_SYSLOG", - "CAP_CHOWN", "CAP_NET_RAW", "CAP_DAC_OVERRIDE", "CAP_FOWNER", "CAP_DAC_READ_SEARCH", - "CAP_FSETID", "CAP_KILL", "CAP_SETGID", "CAP_SETUID", "CAP_LINUX_IMMUTABLE", "CAP_NET_BROADCAST", - "CAP_IPC_LOCK", "CAP_IPC_OWNER", "CAP_SYS_CHROOT", "CAP_SYS_PTRACE", "CAP_SYS_BOOT", "CAP_LEASE", - "CAP_SETFCAP", "CAP_WAKE_ALARM", "CAP_BLOCK_SUSPEND", + // try adding back capabilities other than NET_BIND_SERVICE, should be forbidden + "AUDIT_WRITE", "CHOWN", "DAC_OVERRIDE", "FOWNER", "FSETID", "KILL", "MKNOD", "NET_BIND_SERVICE", "SETFCAP", "SETGID", "SETPCAP", "SETUID", "SYS_CHROOT", } }), }