diff --git a/staging/src/k8s.io/pod-security-admission/policy/check_privileged.go b/staging/src/k8s.io/pod-security-admission/policy/check_privileged.go index 20fafa3bb1e..6824cf8d8bc 100644 --- a/staging/src/k8s.io/pod-security-admission/policy/check_privileged.go +++ b/staging/src/k8s.io/pod-security-admission/policy/check_privileged.go @@ -17,7 +17,7 @@ limitations under the License. package policy import ( - "strings" + "fmt" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -32,7 +32,7 @@ Restricted Fields: spec.containers[*].securityContext.privileged spec.initContainers[*].securityContext.privileged -Allowed Values: false, undefined/nil +Allowed Values: false, undefined/null */ func init() { @@ -40,7 +40,7 @@ func init() { } // CheckPrivileged returns a baseline level check -// that requires privileged=false in 1.0+ +// that forbids privileged=true in 1.0+ func CheckPrivileged() Check { return Check{ ID: "privileged", @@ -55,17 +55,21 @@ func CheckPrivileged() Check { } func privileged_1_0(podMetadata *metav1.ObjectMeta, podSpec *corev1.PodSpec) CheckResult { - var forbiddenPaths []string + var badContainers []string visitContainersWithPath(podSpec, field.NewPath("spec"), func(container *corev1.Container, path *field.Path) { if container.SecurityContext != nil && container.SecurityContext.Privileged != nil && *container.SecurityContext.Privileged { - forbiddenPaths = append(forbiddenPaths, path.Child("securityContext", "privileged").String()) + badContainers = append(badContainers, container.Name) } }) - if len(forbiddenPaths) > 0 { + if len(badContainers) > 0 { return CheckResult{ Allowed: false, - ForbiddenReason: "privileged == true", - ForbiddenDetail: strings.Join(forbiddenPaths, ", "), + ForbiddenReason: "privileged", + ForbiddenDetail: fmt.Sprintf( + `%s %s must not set securityContext.privileged=true`, + pluralize("container", "containers", len(badContainers)), + joinQuote(badContainers), + ), } } return CheckResult{Allowed: true} diff --git a/staging/src/k8s.io/pod-security-admission/policy/check_privileged_test.go b/staging/src/k8s.io/pod-security-admission/policy/check_privileged_test.go new file mode 100644 index 00000000000..ed469620ebb --- /dev/null +++ b/staging/src/k8s.io/pod-security-admission/policy/check_privileged_test.go @@ -0,0 +1,63 @@ +/* +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. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package policy + +import ( + "testing" + + corev1 "k8s.io/api/core/v1" + utilpointer "k8s.io/utils/pointer" +) + +func TestPrivileged(t *testing.T) { + tests := []struct { + name string + pod *corev1.Pod + expectReason string + expectDetail string + }{ + { + name: "privileged", + pod: &corev1.Pod{Spec: corev1.PodSpec{ + Containers: []corev1.Container{ + {Name: "a", SecurityContext: nil}, + {Name: "b", SecurityContext: &corev1.SecurityContext{}}, + {Name: "c", SecurityContext: &corev1.SecurityContext{Privileged: utilpointer.Bool(false)}}, + {Name: "d", SecurityContext: &corev1.SecurityContext{Privileged: utilpointer.Bool(true)}}, + {Name: "e", SecurityContext: &corev1.SecurityContext{Privileged: utilpointer.Bool(true)}}, + }, + }}, + expectReason: `privileged`, + expectDetail: `containers "d", "e" must not set securityContext.privileged=true`, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + result := privileged_1_0(&tc.pod.ObjectMeta, &tc.pod.Spec) + if result.Allowed { + t.Fatal("expected disallowed") + } + if e, a := tc.expectReason, result.ForbiddenReason; e != a { + t.Errorf("expected\n%s\ngot\n%s", e, a) + } + if e, a := tc.expectDetail, result.ForbiddenDetail; e != a { + t.Errorf("expected\n%s\ngot\n%s", e, a) + } + }) + } +} diff --git a/staging/src/k8s.io/pod-security-admission/test/fixtures_privileged.go b/staging/src/k8s.io/pod-security-admission/test/fixtures_privileged.go index ffac5e3a45c..babdcf6ba65 100644 --- a/staging/src/k8s.io/pod-security-admission/test/fixtures_privileged.go +++ b/staging/src/k8s.io/pod-security-admission/test/fixtures_privileged.go @@ -36,7 +36,7 @@ func init() { generatePass: func(p *corev1.Pod) []*corev1.Pod { p = ensureSecurityContext(p) return []*corev1.Pod{ - // privileged set to false + // privileged explicitly set to false tweak(p, func(p *corev1.Pod) { p.Spec.Containers[0].SecurityContext.Privileged = pointer.BoolPtr(false) p.Spec.InitContainers[0].SecurityContext.Privileged = pointer.BoolPtr(false)