Skip to content

Commit 17521f0

Browse files
committed
PSA: allow procMount type Unmasked in baseline
a masked proc mount has traditionally been used to prevent untrusted containers from accessing leaky kernel APIs. However, within a user namespace, typical ID checks protect better than masked proc. Further, allowing unmasked proc with a user namespace gives access to a container mounting sub procs, which opens avenues for container-in-container use cases. Update PSS for baseline to allow a container to access an unmasked /proc, if it's in a user namespace and if the UserNamespacesPodSecurityStandards feature is enabled. Signed-off-by: Peter Hunt <[email protected]>
1 parent f820301 commit 17521f0

File tree

2 files changed

+45
-8
lines changed

2 files changed

+45
-8
lines changed

staging/src/k8s.io/pod-security-admission/policy/check_procMount.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,9 @@ spec.initContainers[*].securityContext.procMount
3535
3636
**Allowed Values:** undefined/null, "Default"
3737
38+
However, if the pod is in a user namespace (`hostUsers: false`), and the
39+
UserNamespacesPodSecurityStandards feature is enabled, all values are allowed.
40+
3841
*/
3942

4043
func init() {
@@ -58,6 +61,14 @@ func CheckProcMount() Check {
5861
}
5962

6063
func procMount_1_0(podMetadata *metav1.ObjectMeta, podSpec *corev1.PodSpec) CheckResult {
64+
// TODO: When we remove the UserNamespacesPodSecurityStandards feature gate (and GA this relaxation),
65+
// create a new policy version.
66+
// Note: pod validation will check for well formed procMount type, so avoid double validation and allow everything
67+
// here.
68+
if relaxPolicyForUserNamespacePod(podSpec) {
69+
return CheckResult{Allowed: true}
70+
}
71+
6172
var badContainers []string
6273
forbiddenProcMountTypes := sets.NewString()
6374
visitContainers(podSpec, func(container *corev1.Container) {

staging/src/k8s.io/pod-security-admission/policy/check_procMount_test.go

Lines changed: 34 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,12 @@ func TestProcMount(t *testing.T) {
2929

3030
hostUsers := false
3131
tests := []struct {
32-
name string
33-
pod *corev1.Pod
34-
expectReason string
35-
expectDetail string
32+
name string
33+
pod *corev1.Pod
34+
expectReason string
35+
expectDetail string
36+
expectAllowed bool
37+
relaxForUserNS bool
3638
}{
3739
{
3840
name: "procMount",
@@ -46,16 +48,40 @@ func TestProcMount(t *testing.T) {
4648
},
4749
HostUsers: &hostUsers,
4850
}},
49-
expectReason: `procMount`,
50-
expectDetail: `containers "d", "e" must not set securityContext.procMount to "Unmasked", "other"`,
51+
expectReason: `procMount`,
52+
expectAllowed: false,
53+
expectDetail: `containers "d", "e" must not set securityContext.procMount to "Unmasked", "other"`,
54+
},
55+
{
56+
name: "procMount",
57+
pod: &corev1.Pod{Spec: corev1.PodSpec{
58+
Containers: []corev1.Container{
59+
{Name: "a", SecurityContext: nil},
60+
{Name: "b", SecurityContext: &corev1.SecurityContext{}},
61+
{Name: "c", SecurityContext: &corev1.SecurityContext{ProcMount: &defaultValue}},
62+
{Name: "d", SecurityContext: &corev1.SecurityContext{ProcMount: &unmaskedValue}},
63+
{Name: "e", SecurityContext: &corev1.SecurityContext{ProcMount: &otherValue}},
64+
},
65+
HostUsers: &hostUsers,
66+
}},
67+
expectReason: "",
68+
expectDetail: "",
69+
expectAllowed: true,
70+
relaxForUserNS: true,
5171
},
5272
}
5373

5474
for _, tc := range tests {
5575
t.Run(tc.name, func(t *testing.T) {
76+
if tc.relaxForUserNS {
77+
RelaxPolicyForUserNamespacePods(true)
78+
t.Cleanup(func() {
79+
RelaxPolicyForUserNamespacePods(false)
80+
})
81+
}
5682
result := procMount_1_0(&tc.pod.ObjectMeta, &tc.pod.Spec)
57-
if result.Allowed {
58-
t.Fatal("expected disallowed")
83+
if result.Allowed != tc.expectAllowed {
84+
t.Fatalf("expected Allowed to be %v was %v", tc.expectAllowed, result.Allowed)
5985
}
6086
if e, a := tc.expectReason, result.ForbiddenReason; e != a {
6187
t.Errorf("expected\n%s\ngot\n%s", e, a)

0 commit comments

Comments
 (0)