diff --git a/staging/src/k8s.io/pod-security-admission/admission/admission.go b/staging/src/k8s.io/pod-security-admission/admission/admission.go index e96c1a0bbd7..8f7e9751379 100644 --- a/staging/src/k8s.io/pod-security-admission/admission/admission.go +++ b/staging/src/k8s.io/pod-security-admission/admission/admission.go @@ -228,7 +228,7 @@ func (a *Admission) Validate(ctx context.Context, attrs api.Attributes) *admissi func (a *Admission) ValidateNamespace(ctx context.Context, attrs api.Attributes) *admissionv1.AdmissionResponse { // short-circuit on subresources if attrs.GetSubresource() != "" { - return sharedAllowedResponse() + return sharedAllowedResponse } obj, err := attrs.GetObject() if err != nil { @@ -249,7 +249,7 @@ func (a *Admission) ValidateNamespace(ctx context.Context, attrs api.Attributes) if len(newErrs) > 0 { return invalidResponse(attrs, newErrs) } - return sharedAllowedResponse() + return sharedAllowedResponse case admissionv1.Update: // if update, check if policy labels changed @@ -276,24 +276,24 @@ func (a *Admission) ValidateNamespace(ctx context.Context, attrs api.Attributes) // * if the new enforce is the same version and level was relaxed // * for exempt namespaces if newPolicy.Enforce == oldPolicy.Enforce { - return sharedAllowedResponse() + return sharedAllowedResponse } if newPolicy.Enforce.Level == api.LevelPrivileged { - return sharedAllowedResponse() + return sharedAllowedResponse } if newPolicy.Enforce.Version == oldPolicy.Enforce.Version && api.CompareLevels(newPolicy.Enforce.Level, oldPolicy.Enforce.Level) < 1 { - return sharedAllowedResponse() + return sharedAllowedResponse } if a.exemptNamespace(attrs.GetNamespace()) { - return sharedAllowedByNamespaceExemptionResponse() + return sharedAllowedByNamespaceExemptionResponse } response := allowedResponse() response.Warnings = a.EvaluatePodsInNamespace(ctx, namespace.Name, newPolicy.Enforce) return response default: - return sharedAllowedResponse() + return sharedAllowedResponse } } @@ -316,17 +316,17 @@ var ignoredPodSubresources = map[string]bool{ func (a *Admission) ValidatePod(ctx context.Context, attrs api.Attributes) *admissionv1.AdmissionResponse { // short-circuit on ignored subresources if ignoredPodSubresources[attrs.GetSubresource()] { - return sharedAllowedResponse() + return sharedAllowedResponse } // short-circuit on exempt namespaces and users if a.exemptNamespace(attrs.GetNamespace()) { a.Metrics.RecordExemption(attrs) - return sharedAllowedByNamespaceExemptionResponse() + return sharedAllowedByNamespaceExemptionResponse } if a.exemptUser(attrs.GetUserName()) { a.Metrics.RecordExemption(attrs) - return sharedAllowedByUserExemptionResponse() + return sharedAllowedByUserExemptionResponse } // short-circuit on privileged enforce+audit+warn namespaces @@ -339,7 +339,7 @@ func (a *Admission) ValidatePod(ctx context.Context, attrs api.Attributes) *admi nsPolicy, nsPolicyErrs := a.PolicyToEvaluate(namespace.Labels) if len(nsPolicyErrs) == 0 && nsPolicy.Enforce.Level == api.LevelPrivileged && nsPolicy.Warn.Level == api.LevelPrivileged && nsPolicy.Audit.Level == api.LevelPrivileged { a.Metrics.RecordEvaluation(metrics.DecisionAllow, nsPolicy.Enforce, metrics.ModeEnforce, attrs) - return sharedAllowedResponse() + return sharedAllowedPrivilegedResponse } obj, err := attrs.GetObject() @@ -369,7 +369,7 @@ func (a *Admission) ValidatePod(ctx context.Context, attrs api.Attributes) *admi } if !isSignificantPodUpdate(pod, oldPod) { // Nothing we care about changed, so always allow the update. - return sharedAllowedResponse() + return sharedAllowedResponse } } return a.EvaluatePod(ctx, nsPolicy, nsPolicyErrs.ToAggregate(), &pod.ObjectMeta, &pod.Spec, attrs, true) @@ -380,17 +380,17 @@ func (a *Admission) ValidatePod(ctx context.Context, attrs api.Attributes) *admi func (a *Admission) ValidatePodController(ctx context.Context, attrs api.Attributes) *admissionv1.AdmissionResponse { // short-circuit on subresources if attrs.GetSubresource() != "" { - return sharedAllowedResponse() + return sharedAllowedResponse } // short-circuit on exempt namespaces and users if a.exemptNamespace(attrs.GetNamespace()) { a.Metrics.RecordExemption(attrs) - return sharedAllowedByNamespaceExemptionResponse() + return sharedAllowedByNamespaceExemptionResponse } if a.exemptUser(attrs.GetUserName()) { a.Metrics.RecordExemption(attrs) - return sharedAllowedByUserExemptionResponse() + return sharedAllowedByUserExemptionResponse } // short-circuit on privileged audit+warn namespaces @@ -406,7 +406,7 @@ func (a *Admission) ValidatePodController(ctx context.Context, attrs api.Attribu } nsPolicy, nsPolicyErrs := a.PolicyToEvaluate(namespace.Labels) if len(nsPolicyErrs) == 0 && nsPolicy.Warn.Level == api.LevelPrivileged && nsPolicy.Audit.Level == api.LevelPrivileged { - return sharedAllowedResponse() + return sharedAllowedResponse } obj, err := attrs.GetObject() @@ -431,7 +431,7 @@ func (a *Admission) ValidatePodController(ctx context.Context, attrs api.Attribu } if podMetadata == nil && podSpec == nil { // if a controller with an optional pod spec does not contain a pod spec, skip validation - return sharedAllowedResponse() + return sharedAllowedResponse } return a.EvaluatePod(ctx, nsPolicy, nsPolicyErrs.ToAggregate(), podMetadata, podSpec, attrs, false) } @@ -443,7 +443,7 @@ func (a *Admission) EvaluatePod(ctx context.Context, nsPolicy api.Policy, nsPoli // short-circuit on exempt runtimeclass if a.exemptRuntimeClass(podSpec.RuntimeClassName) { a.Metrics.RecordExemption(attrs) - return sharedAllowedByRuntimeClassExemptionResponse() + return sharedAllowedByRuntimeClassExemptionResponse } auditAnnotations := map[string]string{} diff --git a/staging/src/k8s.io/pod-security-admission/admission/admission_test.go b/staging/src/k8s.io/pod-security-admission/admission/admission_test.go index f140347c29c..11459ca1a0e 100644 --- a/staging/src/k8s.io/pod-security-admission/admission/admission_test.go +++ b/staging/src/k8s.io/pod-security-admission/admission/admission_test.go @@ -602,9 +602,11 @@ func TestValidatePodAndController(t *testing.T) { exemptUser = "exempt-user" exemptRuntimeClass = "exempt-runtimeclass" + + podName = "test-pod" ) - objMetadata := metav1.ObjectMeta{Name: "test-pod", Labels: map[string]string{"foo": "bar"}} + objMetadata := metav1.ObjectMeta{Name: podName, Labels: map[string]string{"foo": "bar"}} restrictedPod, err := test.GetMinimalValidPod(api.LevelRestricted, api.MajorMinorVersion(1, 23)) require.NoError(t, err) @@ -662,7 +664,7 @@ func TestValidatePodAndController(t *testing.T) { baselineNs: makeNs(api.LevelBaseline, api.LevelBaseline, api.LevelBaseline), baselineWarnNs: makeNs("", api.LevelBaseline, ""), baselineAuditNs: makeNs("", "", api.LevelBaseline), - restrictedNs: makeNs(api.LevelRestricted, "", api.LevelRestricted), + restrictedNs: makeNs(api.LevelRestricted, api.LevelRestricted, api.LevelRestricted), invalidNs: makeNs("not-a-valid-level", "", ""), } @@ -675,16 +677,6 @@ func TestValidatePodAndController(t *testing.T) { evaluator, err := policy.NewEvaluator(policy.DefaultChecks()) assert.NoError(t, err) - a := &Admission{ - PodLister: &testPodLister{}, - Evaluator: evaluator, - Configuration: config, - Metrics: &FakeRecorder{}, - NamespaceGetter: nsGetter, - } - require.NoError(t, a.CompleteConfiguration(), "CompleteConfiguration()") - require.NoError(t, a.ValidateConfiguration(), "ValidateConfiguration()") - type testCase struct { desc string @@ -707,11 +699,14 @@ func TestValidatePodAndController(t *testing.T) { skipPod bool // Whether to skip the ValidatePod test case. skipDeployment bool // Whteher to skip the ValidatePodController test case. - expectAllowed bool - expectReason metav1.StatusReason - expectWarning bool - expectEnforce bool // Whether to expect an enforcing evaluation (metric+annotation) - expectedAuditAnnotationKeys []string + expectAllowed bool + expectReason metav1.StatusReason + expectExempt bool + expectError bool + + expectEnforce api.Level + expectWarning api.Level + expectAudit api.Level } podCases := []testCase{ { @@ -722,85 +717,87 @@ func TestValidatePodAndController(t *testing.T) { expectAllowed: true, }, { - desc: "exempt namespace", - namespace: exemptNs, - pod: privilegedPod.DeepCopy(), - expectAllowed: true, - expectedAuditAnnotationKeys: []string{"exempt"}, + desc: "exempt namespace", + namespace: exemptNs, + pod: privilegedPod.DeepCopy(), + expectAllowed: true, + expectExempt: true, }, { - desc: "exempt user", - namespace: restrictedNs, - username: exemptUser, - pod: privilegedPod.DeepCopy(), - expectAllowed: true, - expectedAuditAnnotationKeys: []string{"exempt"}, + desc: "exempt user", + namespace: restrictedNs, + username: exemptUser, + pod: privilegedPod.DeepCopy(), + expectAllowed: true, + expectExempt: true, }, { - desc: "exempt runtimeClass", - namespace: restrictedNs, - pod: exemptRCPod.DeepCopy(), - expectAllowed: true, - expectedAuditAnnotationKeys: []string{"exempt"}, + desc: "exempt runtimeClass", + namespace: restrictedNs, + pod: exemptRCPod.DeepCopy(), + expectAllowed: true, + expectExempt: true, }, { - desc: "namespace not found", - namespace: "missing-ns", - pod: restrictedPod.DeepCopy(), - expectAllowed: false, - expectReason: metav1.StatusReasonInternalError, - expectedAuditAnnotationKeys: []string{"error"}, + desc: "namespace not found", + namespace: "missing-ns", + pod: restrictedPod.DeepCopy(), + expectAllowed: false, + expectReason: metav1.StatusReasonInternalError, + expectError: true, }, { desc: "short-circuit privileged:latest (implicit)", namespace: implicitNs, pod: privilegedPod.DeepCopy(), expectAllowed: true, + expectEnforce: api.LevelPrivileged, }, { desc: "short-circuit privileged:latest (explicit)", namespace: privilegedNs, pod: privilegedPod.DeepCopy(), expectAllowed: true, + expectEnforce: api.LevelPrivileged, }, { - desc: "failed decode", - namespace: baselineNs, - objErr: fmt.Errorf("expected (failed decode)"), - expectAllowed: false, - expectReason: metav1.StatusReasonBadRequest, - expectedAuditAnnotationKeys: []string{"error"}, + desc: "failed decode", + namespace: baselineNs, + objErr: fmt.Errorf("expected (failed decode)"), + expectAllowed: false, + expectReason: metav1.StatusReasonBadRequest, + expectError: true, }, { - desc: "invalid object", - namespace: baselineNs, - operation: admissionv1.Update, - obj: &corev1.Namespace{}, - expectAllowed: false, - expectReason: metav1.StatusReasonBadRequest, - expectedAuditAnnotationKeys: []string{"error"}, + desc: "invalid object", + namespace: baselineNs, + operation: admissionv1.Update, + obj: &corev1.Namespace{}, + expectAllowed: false, + expectReason: metav1.StatusReasonBadRequest, + expectError: true, }, { - desc: "failed decode old object", - namespace: baselineNs, - operation: admissionv1.Update, - pod: restrictedPod.DeepCopy(), - oldObjErr: fmt.Errorf("expected (failed decode)"), - expectAllowed: false, - expectReason: metav1.StatusReasonBadRequest, - expectedAuditAnnotationKeys: []string{"error"}, - skipDeployment: true, // Updates aren't special cased for controller resources. + desc: "failed decode old object", + namespace: baselineNs, + operation: admissionv1.Update, + pod: restrictedPod.DeepCopy(), + oldObjErr: fmt.Errorf("expected (failed decode)"), + expectAllowed: false, + expectReason: metav1.StatusReasonBadRequest, + expectError: true, + skipDeployment: true, // Updates aren't special cased for controller resources. }, { - desc: "invalid old object", - namespace: baselineNs, - operation: admissionv1.Update, - pod: restrictedPod.DeepCopy(), - oldObj: &corev1.Namespace{}, - expectAllowed: false, - expectReason: metav1.StatusReasonBadRequest, - expectedAuditAnnotationKeys: []string{"error"}, - skipDeployment: true, // Updates aren't special cased for controller resources. + desc: "invalid old object", + namespace: baselineNs, + operation: admissionv1.Update, + pod: restrictedPod.DeepCopy(), + oldObj: &corev1.Namespace{}, + expectAllowed: false, + expectReason: metav1.StatusReasonBadRequest, + expectError: true, + skipDeployment: true, // Updates aren't special cased for controller resources. }, { desc: "insignificant update", @@ -812,15 +809,16 @@ func TestValidatePodAndController(t *testing.T) { skipDeployment: true, // Updates aren't special cased for controller resources. }, { - desc: "significant update denied", - namespace: restrictedNs, - operation: admissionv1.Update, - pod: differentPrivilegedPod.DeepCopy(), - oldPod: privilegedPod.DeepCopy(), - expectAllowed: false, - expectReason: metav1.StatusReasonForbidden, - expectEnforce: true, - expectedAuditAnnotationKeys: []string{"audit-violations"}, + desc: "significant update denied", + namespace: restrictedNs, + operation: admissionv1.Update, + pod: differentPrivilegedPod.DeepCopy(), + oldPod: privilegedPod.DeepCopy(), + expectAllowed: false, + expectReason: metav1.StatusReasonForbidden, + expectEnforce: api.LevelRestricted, + expectWarning: api.LevelRestricted, + expectAudit: api.LevelRestricted, }, { desc: "significant update allowed", @@ -829,55 +827,56 @@ func TestValidatePodAndController(t *testing.T) { pod: differentRestrictedPod.DeepCopy(), oldPod: restrictedPod, expectAllowed: true, - expectEnforce: true, + expectEnforce: api.LevelRestricted, }, { - desc: "invalid namespace labels", - namespace: invalidNs, - pod: baselinePod.DeepCopy(), - expectAllowed: false, - expectReason: metav1.StatusReasonForbidden, - expectEnforce: true, - expectedAuditAnnotationKeys: []string{"error"}, + desc: "invalid namespace labels", + namespace: invalidNs, + pod: baselinePod.DeepCopy(), + expectAllowed: false, + expectReason: metav1.StatusReasonForbidden, + expectEnforce: api.LevelRestricted, + expectError: true, }, { - desc: "enforce deny", - namespace: restrictedNs, - pod: privilegedPod.DeepCopy(), - expectAllowed: false, - expectReason: metav1.StatusReasonForbidden, - expectEnforce: true, - expectedAuditAnnotationKeys: []string{"audit-violations"}, + desc: "enforce deny", + namespace: restrictedNs, + pod: privilegedPod.DeepCopy(), + expectAllowed: false, + expectReason: metav1.StatusReasonForbidden, + expectEnforce: api.LevelRestricted, + expectWarning: api.LevelRestricted, + expectAudit: api.LevelRestricted, }, { desc: "enforce allow", namespace: baselineNs, pod: baselinePod.DeepCopy(), expectAllowed: true, - expectEnforce: true, + expectEnforce: api.LevelBaseline, }, { desc: "warn deny", namespace: baselineWarnNs, pod: privilegedPod.DeepCopy(), expectAllowed: true, - expectWarning: true, - expectEnforce: true, + expectEnforce: api.LevelPrivileged, + expectWarning: api.LevelBaseline, }, { - desc: "audit deny", - namespace: baselineAuditNs, - pod: privilegedPod.DeepCopy(), - expectAllowed: true, - expectEnforce: true, - expectedAuditAnnotationKeys: []string{"audit-violations"}, + desc: "audit deny", + namespace: baselineAuditNs, + pod: privilegedPod.DeepCopy(), + expectAllowed: true, + expectEnforce: api.LevelPrivileged, + expectAudit: api.LevelBaseline, }, { desc: "no pod template", namespace: restrictedNs, obj: emptyDeployment.DeepCopy(), expectAllowed: true, - expectWarning: false, // No pod template skips validation. + expectWarning: "", // No pod template skips validation. skipPod: true, }, } @@ -904,15 +903,17 @@ func TestValidatePodAndController(t *testing.T) { podTest.desc = "pod:" + tc.desc podTest.resource = schema.GroupVersionResource{Version: "v1", Resource: "pods"} podTest.kind = schema.GroupVersionKind{Version: "v1", Kind: "Pod"} - if tc.expectEnforce { - podTest.expectedAuditAnnotationKeys = append(podTest.expectedAuditAnnotationKeys, "enforce-policy") + if !tc.expectAllowed { + podTest.expectWarning = "" // Warnings should only be returned when the request is allowed. } deploymentTest := tc deploymentTest.desc = "deployment:" + tc.desc deploymentTest.resource = schema.GroupVersionResource{Group: "apps", Version: "v1", Resource: "deployments"} deploymentTest.kind = schema.GroupVersionKind{Group: "apps", Version: "v1", Kind: "Deployment"} - deploymentTest.expectAllowed = true // PodController validation is always non-enforcing. + // PodController validation is always non-enforcing. + deploymentTest.expectAllowed = true + deploymentTest.expectEnforce = "" deploymentTest.expectReason = "" if tc.pod != nil { @@ -961,8 +962,21 @@ func TestValidatePodAndController(t *testing.T) { attrs.Username = tc.username } + recorder := &FakeRecorder{} + a := &Admission{ + PodLister: &testPodLister{}, + Evaluator: evaluator, + Configuration: config, + Metrics: recorder, + NamespaceGetter: nsGetter, + } + require.NoError(t, a.CompleteConfiguration(), "CompleteConfiguration()") + require.NoError(t, a.ValidateConfiguration(), "ValidateConfiguration()") + response := a.Validate(context.TODO(), attrs) + var expectedEvaluations []MetricsRecord + var expectedAuditAnnotationKeys []string if tc.expectAllowed { assert.True(t, response.Allowed, "Allowed") assert.Nil(t, response.Result) @@ -973,42 +987,72 @@ func TestValidatePodAndController(t *testing.T) { } } - if tc.expectWarning { + if tc.expectWarning != "" { assert.NotEmpty(t, response.Warnings, "Warnings") } else { assert.Empty(t, response.Warnings, "Warnings") } - assert.Len(t, response.AuditAnnotations, len(tc.expectedAuditAnnotationKeys), "AuditAnnotations") - for _, key := range tc.expectedAuditAnnotationKeys { + if tc.expectEnforce != "" { + expectedAuditAnnotationKeys = append(expectedAuditAnnotationKeys, "enforce-policy") + record := MetricsRecord{podName, metrics.DecisionAllow, tc.expectEnforce, metrics.ModeEnforce} + if !tc.expectAllowed { + record.EvalDecision = metrics.DecisionDeny + } + expectedEvaluations = append(expectedEvaluations, record) + } + if tc.expectWarning != "" { + expectedEvaluations = append(expectedEvaluations, MetricsRecord{podName, metrics.DecisionDeny, tc.expectWarning, metrics.ModeWarn}) + } + if tc.expectAudit != "" { + expectedEvaluations = append(expectedEvaluations, MetricsRecord{podName, metrics.DecisionDeny, tc.expectAudit, metrics.ModeAudit}) + expectedAuditAnnotationKeys = append(expectedAuditAnnotationKeys, "audit-violations") + } + if tc.expectError { + expectedAuditAnnotationKeys = append(expectedAuditAnnotationKeys, "error") + assert.ElementsMatch(t, []MetricsRecord{{ObjectName: podName}}, recorder.errors, "expected RecordError() calls") + } else { + assert.Empty(t, recorder.errors, "expected RecordError() calls") + } + if tc.expectExempt { + expectedAuditAnnotationKeys = append(expectedAuditAnnotationKeys, "exempt") + assert.ElementsMatch(t, []MetricsRecord{{ObjectName: podName}}, recorder.exemptions, "expected RecordExemption() calls") + } else { + assert.Empty(t, recorder.exemptions, "expected RecordExemption() calls") + } + + assert.Len(t, response.AuditAnnotations, len(expectedAuditAnnotationKeys), "AuditAnnotations") + for _, key := range expectedAuditAnnotationKeys { assert.Contains(t, response.AuditAnnotations, key, "AuditAnnotations") } + + assert.ElementsMatch(t, expectedEvaluations, recorder.evaluations, "expected RecordEvaluation() calls") }) } } type FakeRecorder struct { - evaluations []EvaluationRecord + evaluations []MetricsRecord + exemptions []MetricsRecord + errors []MetricsRecord } -type EvaluationRecord struct { - ObjectName string - Decision metrics.Decision - Policy api.LevelVersion - Mode metrics.Mode +type MetricsRecord struct { + ObjectName string + EvalDecision metrics.Decision + EvalPolicy api.Level + EvalMode metrics.Mode } func (r *FakeRecorder) RecordEvaluation(decision metrics.Decision, policy api.LevelVersion, evalMode metrics.Mode, attrs api.Attributes) { - r.evaluations = append(r.evaluations, EvaluationRecord{attrs.GetName(), decision, policy, evalMode}) + r.evaluations = append(r.evaluations, MetricsRecord{attrs.GetName(), decision, policy.Level, evalMode}) } -func (r *FakeRecorder) RecordExemption(api.Attributes) {} -func (r *FakeRecorder) RecordError(bool, api.Attributes) {} - -// ExpectEvaluation asserts that the evaluation was recorded, and clears the record. -func (r *FakeRecorder) ExpectEvaluations(t *testing.T, expected []EvaluationRecord) { - t.Helper() - assert.ElementsMatch(t, expected, r.evaluations) +func (r *FakeRecorder) RecordExemption(attrs api.Attributes) { + r.exemptions = append(r.exemptions, MetricsRecord{ObjectName: attrs.GetName()}) +} +func (r *FakeRecorder) RecordError(_ bool, attrs api.Attributes) { + r.errors = append(r.errors, MetricsRecord{ObjectName: attrs.GetName()}) } func TestPrioritizePods(t *testing.T) { diff --git a/staging/src/k8s.io/pod-security-admission/admission/main_test.go b/staging/src/k8s.io/pod-security-admission/admission/main_test.go index 4d0e5851bf2..7448ccf92aa 100644 --- a/staging/src/k8s.io/pod-security-admission/admission/main_test.go +++ b/staging/src/k8s.io/pod-security-admission/admission/main_test.go @@ -21,15 +21,30 @@ import ( "os" "reflect" "testing" + + admissionv1 "k8s.io/api/admission/v1" ) func TestMain(m *testing.M) { - sharedCopy := sharedAllowedResponse().DeepCopy() + sharedResponses := map[string]*admissionv1.AdmissionResponse{ + "sharedAllowedResponse": sharedAllowedResponse, + "sharedAllowedPrivilegedResponse": sharedAllowedPrivilegedResponse, + "sharedAllowedByUserExemptionResponse": sharedAllowedByUserExemptionResponse, + "sharedAllowedByNamespaceExemptionResponse": sharedAllowedByNamespaceExemptionResponse, + "sharedAllowedByRuntimeClassExemptionResponse": sharedAllowedByRuntimeClassExemptionResponse, + } + sharedResponseCopies := map[string]*admissionv1.AdmissionResponse{} + for name, response := range sharedResponses { + sharedResponseCopies[name] = response.DeepCopy() + } + rc := m.Run() - if !reflect.DeepEqual(sharedCopy, sharedAllowedResponse()) { - fmt.Println("sharedAllowedReponse mutated") - rc = 1 + for name := range sharedResponses { + if !reflect.DeepEqual(sharedResponseCopies[name], sharedResponses[name]) { + fmt.Fprintf(os.Stderr, "%s mutated\n", name) + rc = 1 + } } os.Exit(rc) diff --git a/staging/src/k8s.io/pod-security-admission/admission/response.go b/staging/src/k8s.io/pod-security-admission/admission/response.go index b121f5dd2a9..abbf1a7a9f0 100644 --- a/staging/src/k8s.io/pod-security-admission/admission/response.go +++ b/staging/src/k8s.io/pod-security-admission/admission/response.go @@ -27,26 +27,20 @@ import ( ) var ( - _sharedAllowedResponse = allowedResponse() - _sharedAllowedByUserExemptionResponse = allowedByExemptResponse("user") - _sharedAllowedByNamespaceExemptionResponse = allowedByExemptResponse("namespace") - _sharedAllowedByRuntimeClassExemptionResponse = allowedByExemptResponse("runtimeClass") + sharedAllowedResponse = allowedResponse() + sharedAllowedPrivilegedResponse = allowedResponse() + sharedAllowedByUserExemptionResponse = allowedResponse() + sharedAllowedByNamespaceExemptionResponse = allowedResponse() + sharedAllowedByRuntimeClassExemptionResponse = allowedResponse() ) -func sharedAllowedResponse() *admissionv1.AdmissionResponse { - return _sharedAllowedResponse -} - -func sharedAllowedByUserExemptionResponse() *admissionv1.AdmissionResponse { - return _sharedAllowedByUserExemptionResponse -} - -func sharedAllowedByNamespaceExemptionResponse() *admissionv1.AdmissionResponse { - return _sharedAllowedByNamespaceExemptionResponse -} - -func sharedAllowedByRuntimeClassExemptionResponse() *admissionv1.AdmissionResponse { - return _sharedAllowedByRuntimeClassExemptionResponse +func init() { + sharedAllowedPrivilegedResponse.AuditAnnotations = map[string]string{ + api.EnforcedPolicyAnnotationKey: api.LevelVersion{Level: api.LevelPrivileged, Version: api.LatestVersion()}.String(), + } + sharedAllowedByUserExemptionResponse.AuditAnnotations = map[string]string{api.ExemptionReasonAnnotationKey: "user"} + sharedAllowedByNamespaceExemptionResponse.AuditAnnotations = map[string]string{api.ExemptionReasonAnnotationKey: "namespace"} + sharedAllowedByRuntimeClassExemptionResponse.AuditAnnotations = map[string]string{api.ExemptionReasonAnnotationKey: "runtimeClass"} } // allowedResponse is the response used when the admission decision is allow. @@ -54,13 +48,6 @@ func allowedResponse() *admissionv1.AdmissionResponse { return &admissionv1.AdmissionResponse{Allowed: true} } -func allowedByExemptResponse(exemptionReason string) *admissionv1.AdmissionResponse { - return &admissionv1.AdmissionResponse{ - Allowed: true, - AuditAnnotations: map[string]string{api.ExemptionReasonAnnotationKey: exemptionReason}, - } -} - // forbiddenResponse is the response used when the admission decision is deny for policy violations. func forbiddenResponse(attrs api.Attributes, err error) *admissionv1.AdmissionResponse { return &admissionv1.AdmissionResponse{