Pod Security Standards & admission
Baseline, restricted, and OPA/Gatekeeper.
Pod Security Admission is the built-in admission controller (it replaced the deprecated PodSecurityPolicy) that enforces the three Pod Security Standards: privileged (no restrictions), baseline (blocks the known escalation vectors — hostPath, hostNetwork, privileged, added dangerous capabilities), and restricted (the hardened profile: non-root, no privilege escalation, all capabilities dropped, seccomp on, no host namespaces). It is configured entirely with namespace labels, so there is no CRD or webhook to install.
Each namespace can carry three independent modes: enforce (reject violating pods), audit (allow but record in the audit log), and warn (allow but return a warning to the client). You also pin the standard to a Kubernetes version so a future relaxation of a rule does not silently change your posture. The independence of the modes is the key to a safe rollout.
$ kubectl label ns payments \pod-security.kubernetes.io/enforce=restricted \pod-security.kubernetes.io/enforce-version=v1.30 \pod-security.kubernetes.io/warn=restricted \pod-security.kubernetes.io/audit=restricted
What restricted actually requires
A pod that passes restricted is the security context lesson made mandatory: runAsNonRoot, allowPrivilegeEscalation false, all capabilities dropped, a seccomp profile set, no host namespaces, and only the safe volume types. It is worth being able to write one from memory, because the fastest way to fix a rejected pod is to know exactly which field it is missing.
spec:securityContext:runAsNonRoot: trueseccompProfile: { type: RuntimeDefault }containers:- name: appimage: registry.internal/app:1.4.2securityContext:allowPrivilegeEscalation: falsecapabilities: { drop: ["ALL"] }
When three profiles are not enough
PSA only knows those three profiles; it cannot express “images must come from our registry,” “every pod needs a team label,” or “no :latest tags.” For rules specific to your org you add a policy engine — OPA/Gatekeeper (constraints written in Rego via ConstraintTemplates) or Kyverno (policies written in plain YAML). Both run as admission webhooks and can validate or even mutate. PSA for the standard baseline, a policy engine for everything bespoke.
apiVersion: kyverno.io/v1kind: ClusterPolicymetadata: { name: disallow-latest-tag }spec:validationFailureAction: Enforcerules:- name: require-explicit-tagmatch: { any: [{ resources: { kinds: [Pod] } }] }validate:message: "images must use a specific, non-latest tag"pattern:spec:containers:- image: "!*:latest"