Admission policies

Admission policies

PSA covers Pod security only. Organisation rules - “every Deployment has an owner label”, “images only from our registry”, “no latest” - need a policy engine in the admission chain.

graph LR R[request, authorized] --> M[mutating admission<br/>add defaults, sidecars] M --> S[schema validation] S --> V[validating admission<br/>PSA, VAP, Kyverno, Gatekeeper] V -->|allowed| E[(etcd)] V -->|denied| X[error to the user]

ValidatingAdmissionPolicy (built in)

Rules written in CEL, evaluated inside the API server - no extra component. GA since Kubernetes 1.30.

apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingAdmissionPolicy
metadata: { name: no-latest-tag }
spec:
  failurePolicy: Fail
  matchConstraints:
    resourceRules:
      - apiGroups: ["apps"]
        apiVersions: ["v1"]
        operations: ["CREATE", "UPDATE"]
        resources: ["deployments"]
  validations:
    - expression: >-
        object.spec.template.spec.containers.all(c,
          c.image.contains(':') && !c.image.endsWith(':latest'))
      message: "images must have an explicit tag other than latest"
---
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingAdmissionPolicyBinding
metadata: { name: no-latest-tag }
spec:
  policyName: no-latest-tag
  validationActions: ["Deny"]          # or Warn, Audit
  matchResources:
    namespaceSelector:
      matchLabels: { policy: enforced }

Policy = what, binding = where and how strictly.

Policy engines compared

VAP (built in)KyvernoOPA Gatekeeper
LanguageCELYAML (+ CEL)Rego
Validateyesyesyes
Mutate / generateMutatingAdmissionPolicy (newer)yesmutate only
Reports on existing objectsnoPolicyReportsaudit
Extra componentnoneyesyes

Start with VAP for simple rules; take Kyverno when you need mutation, generation or reports.

References