func()

in admission/admission.go [442:515]


func (a *Admission) EvaluatePod(ctx context.Context, nsPolicy api.Policy, nsPolicyErr error, podMetadata *metav1.ObjectMeta, podSpec *corev1.PodSpec, attrs api.Attributes, enforce bool) *admissionv1.AdmissionResponse {
	// short-circuit on exempt runtimeclass
	if a.exemptRuntimeClass(podSpec.RuntimeClassName) {
		a.Metrics.RecordExemption(attrs)
		return sharedAllowedByRuntimeClassExemptionResponse
	}

	auditAnnotations := map[string]string{}
	if nsPolicyErr != nil {
		klog.V(2).InfoS("failed to parse PodSecurity namespace labels", "err", nsPolicyErr)
		auditAnnotations["error"] = fmt.Sprintf("Failed to parse policy: %v", nsPolicyErr)
		a.Metrics.RecordError(false, attrs)
	}

	klogV := klog.V(5)
	if klogV.Enabled() {
		klogV.InfoS("PodSecurity evaluation", "policy", fmt.Sprintf("%v", nsPolicy), "op", attrs.GetOperation(), "resource", attrs.GetResource(), "namespace", attrs.GetNamespace(), "name", attrs.GetName())
	}
	cachedResults := make(map[api.LevelVersion]policy.AggregateCheckResult)
	response := allowedResponse()
	if enforce {
		auditAnnotations[api.EnforcedPolicyAnnotationKey] = nsPolicy.Enforce.String()

		result := policy.AggregateCheckResults(a.Evaluator.EvaluatePod(nsPolicy.Enforce, podMetadata, podSpec))
		if !result.Allowed {
			response = forbiddenResponse(attrs, fmt.Errorf(
				"violates PodSecurity %q: %s",
				nsPolicy.Enforce.String(),
				result.ForbiddenDetail(),
			))
			a.Metrics.RecordEvaluation(metrics.DecisionDeny, nsPolicy.Enforce, metrics.ModeEnforce, attrs)
		} else {
			a.Metrics.RecordEvaluation(metrics.DecisionAllow, nsPolicy.Enforce, metrics.ModeEnforce, attrs)
		}
		cachedResults[nsPolicy.Enforce] = result
	}

	// reuse previous evaluation if audit level+version is the same as enforce level+version

	auditResult, ok := cachedResults[nsPolicy.Audit]
	if !ok {
		auditResult = policy.AggregateCheckResults(a.Evaluator.EvaluatePod(nsPolicy.Audit, podMetadata, podSpec))
		cachedResults[nsPolicy.Audit] = auditResult
	}
	if !auditResult.Allowed {
		auditAnnotations[api.AuditViolationsAnnotationKey] = fmt.Sprintf(
			"would violate PodSecurity %q: %s",
			nsPolicy.Audit.String(),
			auditResult.ForbiddenDetail(),
		)
		a.Metrics.RecordEvaluation(metrics.DecisionDeny, nsPolicy.Audit, metrics.ModeAudit, attrs)
	}

	// avoid adding warnings to a request we're already going to reject with an error
	if response.Allowed {
		// reuse previous evaluation if warn level+version is the same as audit or enforce level+version
		warnResult, ok := cachedResults[nsPolicy.Warn]
		if !ok {
			warnResult = policy.AggregateCheckResults(a.Evaluator.EvaluatePod(nsPolicy.Warn, podMetadata, podSpec))
		}
		if !warnResult.Allowed {
			// TODO: Craft a better user-facing warning message
			response.Warnings = append(response.Warnings, fmt.Sprintf(
				"would violate PodSecurity %q: %s",
				nsPolicy.Warn.String(),
				warnResult.ForbiddenDetail(),
			))
			a.Metrics.RecordEvaluation(metrics.DecisionDeny, nsPolicy.Warn, metrics.ModeWarn, attrs)
		}
	}

	response.AuditAnnotations = auditAnnotations
	return response
}