Merge pull request #126163 from haircommander/procMount-baseline
PSA: allow procMount type Unmasked in baseline
This commit is contained in:
		| @@ -35,6 +35,9 @@ spec.initContainers[*].securityContext.procMount | ||||
|  | ||||
| **Allowed Values:** undefined/null, "Default" | ||||
|  | ||||
| However, if the pod is in a user namespace (`hostUsers: false`), and the | ||||
| UserNamespacesPodSecurityStandards feature is enabled, all values are allowed. | ||||
|  | ||||
| */ | ||||
|  | ||||
| func init() { | ||||
| @@ -58,6 +61,14 @@ func CheckProcMount() Check { | ||||
| } | ||||
|  | ||||
| func procMount_1_0(podMetadata *metav1.ObjectMeta, podSpec *corev1.PodSpec) CheckResult { | ||||
| 	// TODO: When we remove the UserNamespacesPodSecurityStandards feature gate (and GA this relaxation), | ||||
| 	// create a new policy version. | ||||
| 	// Note: pod validation will check for well formed procMount type, so avoid double validation and allow everything | ||||
| 	// here. | ||||
| 	if relaxPolicyForUserNamespacePod(podSpec) { | ||||
| 		return CheckResult{Allowed: true} | ||||
| 	} | ||||
|  | ||||
| 	var badContainers []string | ||||
| 	forbiddenProcMountTypes := sets.NewString() | ||||
| 	visitContainers(podSpec, func(container *corev1.Container) { | ||||
|   | ||||
| @@ -33,6 +33,8 @@ func TestProcMount(t *testing.T) { | ||||
| 		pod            *corev1.Pod | ||||
| 		expectReason   string | ||||
| 		expectDetail   string | ||||
| 		expectAllowed  bool | ||||
| 		relaxForUserNS bool | ||||
| 	}{ | ||||
| 		{ | ||||
| 			name: "procMount", | ||||
| @@ -47,15 +49,39 @@ func TestProcMount(t *testing.T) { | ||||
| 				HostUsers: &hostUsers, | ||||
| 			}}, | ||||
| 			expectReason:  `procMount`, | ||||
| 			expectAllowed: false, | ||||
| 			expectDetail:  `containers "d", "e" must not set securityContext.procMount to "Unmasked", "other"`, | ||||
| 		}, | ||||
| 		{ | ||||
| 			name: "procMount", | ||||
| 			pod: &corev1.Pod{Spec: corev1.PodSpec{ | ||||
| 				Containers: []corev1.Container{ | ||||
| 					{Name: "a", SecurityContext: nil}, | ||||
| 					{Name: "b", SecurityContext: &corev1.SecurityContext{}}, | ||||
| 					{Name: "c", SecurityContext: &corev1.SecurityContext{ProcMount: &defaultValue}}, | ||||
| 					{Name: "d", SecurityContext: &corev1.SecurityContext{ProcMount: &unmaskedValue}}, | ||||
| 					{Name: "e", SecurityContext: &corev1.SecurityContext{ProcMount: &otherValue}}, | ||||
| 				}, | ||||
| 				HostUsers: &hostUsers, | ||||
| 			}}, | ||||
| 			expectReason:   "", | ||||
| 			expectDetail:   "", | ||||
| 			expectAllowed:  true, | ||||
| 			relaxForUserNS: true, | ||||
| 		}, | ||||
| 	} | ||||
|  | ||||
| 	for _, tc := range tests { | ||||
| 		t.Run(tc.name, func(t *testing.T) { | ||||
| 			if tc.relaxForUserNS { | ||||
| 				RelaxPolicyForUserNamespacePods(true) | ||||
| 				t.Cleanup(func() { | ||||
| 					RelaxPolicyForUserNamespacePods(false) | ||||
| 				}) | ||||
| 			} | ||||
| 			result := procMount_1_0(&tc.pod.ObjectMeta, &tc.pod.Spec) | ||||
| 			if result.Allowed { | ||||
| 				t.Fatal("expected disallowed") | ||||
| 			if result.Allowed != tc.expectAllowed { | ||||
| 				t.Fatalf("expected Allowed to be %v was %v", tc.expectAllowed, result.Allowed) | ||||
| 			} | ||||
| 			if e, a := tc.expectReason, result.ForbiddenReason; e != a { | ||||
| 				t.Errorf("expected\n%s\ngot\n%s", e, a) | ||||
|   | ||||
| @@ -29,8 +29,8 @@ func TestRunAsNonRoot(t *testing.T) { | ||||
| 		pod            *corev1.Pod | ||||
| 		expectReason   string | ||||
| 		expectDetail   string | ||||
| 		allowed                                  bool | ||||
| 		enableUserNamespacesPodSecurityStandards bool | ||||
| 		expectAllowed  bool | ||||
| 		relaxForUserNS bool | ||||
| 	}{ | ||||
| 		{ | ||||
| 			name: "no explicit runAsNonRoot", | ||||
| @@ -87,8 +87,8 @@ func TestRunAsNonRoot(t *testing.T) { | ||||
| 			pod: &corev1.Pod{Spec: corev1.PodSpec{ | ||||
| 				HostUsers: utilpointer.Bool(false), | ||||
| 			}}, | ||||
| 			allowed:                                  true, | ||||
| 			enableUserNamespacesPodSecurityStandards: true, | ||||
| 			expectAllowed:  true, | ||||
| 			relaxForUserNS: true, | ||||
| 		}, | ||||
| 		{ | ||||
| 			name: "UserNamespacesPodSecurityStandards enabled with HostUsers", | ||||
| @@ -100,19 +100,22 @@ func TestRunAsNonRoot(t *testing.T) { | ||||
| 			}}, | ||||
| 			expectReason:   `runAsNonRoot != true`, | ||||
| 			expectDetail:   `pod or container "a" must set securityContext.runAsNonRoot=true`, | ||||
| 			allowed:                                  false, | ||||
| 			enableUserNamespacesPodSecurityStandards: true, | ||||
| 			expectAllowed:  false, | ||||
| 			relaxForUserNS: true, | ||||
| 		}, | ||||
| 	} | ||||
|  | ||||
| 	for _, tc := range tests { | ||||
| 		t.Run(tc.name, func(t *testing.T) { | ||||
| 			if tc.enableUserNamespacesPodSecurityStandards { | ||||
| 			if tc.relaxForUserNS { | ||||
| 				RelaxPolicyForUserNamespacePods(true) | ||||
| 				t.Cleanup(func() { | ||||
| 					RelaxPolicyForUserNamespacePods(false) | ||||
| 				}) | ||||
| 			} | ||||
| 			result := runAsNonRoot_1_0(&tc.pod.ObjectMeta, &tc.pod.Spec) | ||||
| 			if result.Allowed && !tc.allowed { | ||||
| 				t.Fatal("expected disallowed") | ||||
| 			if result.Allowed != tc.expectAllowed { | ||||
| 				t.Fatalf("expected Allowed to be %v was %v", tc.expectAllowed, result.Allowed) | ||||
| 			} | ||||
| 			if e, a := tc.expectReason, result.ForbiddenReason; e != a { | ||||
| 				t.Errorf("expected\n%s\ngot\n%s", e, a) | ||||
|   | ||||
| @@ -27,10 +27,10 @@ func TestRunAsUser(t *testing.T) { | ||||
| 	tests := []struct { | ||||
| 		name           string | ||||
| 		pod            *corev1.Pod | ||||
| 		expectAllow                              bool | ||||
| 		expectAllowed  bool | ||||
| 		expectReason   string | ||||
| 		expectDetail   string | ||||
| 		enableUserNamespacesPodSecurityStandards bool | ||||
| 		relaxForUserNS bool | ||||
| 	}{ | ||||
| 		{ | ||||
| 			name: "pod runAsUser=0", | ||||
| @@ -51,7 +51,7 @@ func TestRunAsUser(t *testing.T) { | ||||
| 					{Name: "a", SecurityContext: nil}, | ||||
| 				}, | ||||
| 			}}, | ||||
| 			expectAllow: true, | ||||
| 			expectAllowed: true, | ||||
| 		}, | ||||
| 		{ | ||||
| 			name: "pod runAsUser=nil", | ||||
| @@ -61,7 +61,7 @@ func TestRunAsUser(t *testing.T) { | ||||
| 					{Name: "a", SecurityContext: nil}, | ||||
| 				}, | ||||
| 			}}, | ||||
| 			expectAllow: true, | ||||
| 			expectAllowed: true, | ||||
| 		}, | ||||
| 		{ | ||||
| 			name: "containers runAsUser=0", | ||||
| @@ -89,15 +89,15 @@ func TestRunAsUser(t *testing.T) { | ||||
| 					{Name: "f", SecurityContext: &corev1.SecurityContext{RunAsUser: utilpointer.Int64(4)}}, | ||||
| 				}, | ||||
| 			}}, | ||||
| 			expectAllow: true, | ||||
| 			expectAllowed: true, | ||||
| 		}, | ||||
| 		{ | ||||
| 			name: "UserNamespacesPodSecurityStandards enabled without HostUsers", | ||||
| 			pod: &corev1.Pod{Spec: corev1.PodSpec{ | ||||
| 				HostUsers: utilpointer.Bool(false), | ||||
| 			}}, | ||||
| 			expectAllow:                              true, | ||||
| 			enableUserNamespacesPodSecurityStandards: true, | ||||
| 			expectAllowed:  true, | ||||
| 			relaxForUserNS: true, | ||||
| 		}, | ||||
| 		{ | ||||
| 			name: "UserNamespacesPodSecurityStandards enabled with HostUsers", | ||||
| @@ -108,27 +108,24 @@ func TestRunAsUser(t *testing.T) { | ||||
| 				}, | ||||
| 				HostUsers: utilpointer.Bool(true), | ||||
| 			}}, | ||||
| 			expectAllow:                              false, | ||||
| 			expectAllowed:  false, | ||||
| 			expectReason:   `runAsUser=0`, | ||||
| 			expectDetail:   `pod must not set runAsUser=0`, | ||||
| 			enableUserNamespacesPodSecurityStandards: true, | ||||
| 			relaxForUserNS: true, | ||||
| 		}, | ||||
| 	} | ||||
|  | ||||
| 	for _, tc := range tests { | ||||
| 		t.Run(tc.name, func(t *testing.T) { | ||||
| 			if tc.enableUserNamespacesPodSecurityStandards { | ||||
| 			if tc.relaxForUserNS { | ||||
| 				RelaxPolicyForUserNamespacePods(true) | ||||
| 				t.Cleanup(func() { | ||||
| 					RelaxPolicyForUserNamespacePods(false) | ||||
| 				}) | ||||
| 			} | ||||
| 			result := runAsUser_1_23(&tc.pod.ObjectMeta, &tc.pod.Spec) | ||||
| 			if tc.expectAllow { | ||||
| 				if !result.Allowed { | ||||
| 					t.Fatalf("expected to be allowed, disallowed: %s, %s", result.ForbiddenReason, result.ForbiddenDetail) | ||||
| 				} | ||||
| 				return | ||||
| 			} | ||||
| 			if result.Allowed { | ||||
| 				t.Fatal("expected disallowed") | ||||
| 			if result.Allowed != tc.expectAllowed { | ||||
| 				t.Fatalf("expected Allowed to be %v was %v", tc.expectAllowed, result.Allowed) | ||||
| 			} | ||||
| 			if e, a := tc.expectReason, result.ForbiddenReason; e != a { | ||||
| 				t.Errorf("expected\n%s\ngot\n%s", e, a) | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Kubernetes Prow Robot
					Kubernetes Prow Robot