Kubernetes defines three Pod Security Standards — privileged, baseline and restricted — enforced by the built-in Pod Security Admission controller through namespace labels. Explain what each level allows and how the enforce, audit and warn modes differ.
answer
- privileged / baseline / restricted, cumulative
- baseline = no privileged, no host namespaces, no hostPath
- restricted = + non-root, drop ALL, no escalation, seccomp
- labels: pod-security.kubernetes.io/{enforce,audit,warn}
- enforce hits pods not Deployments; warn does check Deployments
basics
~20 sprivileged allows everything; baseline blocks known escalations (privileged mode, host namespaces, hostPath, extra capabilities); restricted additionally requires non-root, drop ALL capabilities, no privilege escalation and a seccomp profile. You opt a namespace in with labels: enforce rejects violating pods, audit records them in the audit log, warn returns a client warning.
solid answer
~50 s**The standards** are three cumulative profiles: - **privileged** — no restrictions; for infrastructure workloads like CNI and CSI agents. - **baseline** — blocks the known-dangerous knobs: `privileged: true`, host namespaces (`hostNetwork`/`hostPID`/`hostIPC`), `hostPath` volumes, host ports, adding capabilities beyond a small allowed set, unconfined AppArmor/seccomp/SELinux options. - **restricted** — baseline plus hardening: `runAsNonRoot`, `allowPrivilegeEscalation: false`, `capabilities.drop: ["ALL"]` (only `NET_BIND_SERVICE` addable), a `RuntimeDefault` or localhost seccomp profile, and only safe volume types. **Pod Security Admission** is the in-tree admission controller that applies them per namespace via labels: ``` pod-security.kubernetes.io/enforce: restricted pod-security.kubernetes.io/audit: restricted pod-security.kubernetes.io/warn: restricted ``` `enforce` rejects the pod at the API server. `audit` lets it through but annotates the audit-log entry. `warn` lets it through and returns a warning to `kubectl`. Each mode takes an optional `-version` pin. The standard rollout is warn+audit first, read the signal, then enforce.
code
bash · 13 lines# stage 1: observe only
kubectl label ns payments \
pod-security.kubernetes.io/warn=restricted \
pod-security.kubernetes.io/audit=restricted
# dry-run to see which existing pods would be rejected
kubectl label --dry-run=server --overwrite ns payments \
pod-security.kubernetes.io/enforce=restricted
# stage 2: enforce, pinned so a cluster upgrade cannot tighten it silently
kubectl label --overwrite ns payments \
pod-security.kubernetes.io/enforce=restricted \
pod-security.kubernetes.io/enforce-version=v1.31go deeper
Name the three levels in order of strictness and know that PSA is switched on with namespace labels for enforce, audit and warn.
Say precisely what baseline forbids versus what restricted additionally requires, and explain the three modes including that enforce evaluates pods while warn evaluates Deployments.
Own the rollout: warn+audit first, measure with the audit log and server-side dry-run, fix manifests, then enforce per namespace with a pinned version, plus an explicit home for privileged infrastructure.
Position PSA as the built-in floor and articulate where it stops — no registry, resource or cross-object rules — and how that shapes whether you also run a general policy layer, plus the governance around exemptions.
## Two things with similar names **Pod Security Standards (PSS)** are a specification: three named profiles describing what a pod spec may contain. **Pod Security Admission (PSA)** is the built-in admission controller, GA since Kubernetes 1.25, that evaluates pods against those profiles. PSA replaced PodSecurityPolicy, which was deprecated in 1.21 and removed in 1.25. If someone talks about PSP, that is the dead predecessor. ## The three levels **privileged** — entirely unrestricted. It exists so infrastructure that genuinely needs host access (CNI plugins, CSI node drivers, log shippers, node-problem-detector) has a named home rather than an implicit exception. **baseline** — the "do not do anything obviously dangerous" bar, designed to be adoptable by common applications with no manifest changes. It forbids: - `privileged: true` - host namespaces: `hostNetwork`, `hostPID`, `hostIPC` - `hostPath` volumes and host ports - adding capabilities beyond a short allowed list (`NET_BIND_SERVICE`) - unconfined seccomp, and AppArmor/SELinux options that weaken confinement - `/proc` mount type other than the default **restricted** — everything in baseline plus a positive obligation to harden. The pod must set `runAsNonRoot: true`, `allowPrivilegeEscalation: false`, `capabilities.drop: ["ALL"]`, and a `seccompProfile` of `RuntimeDefault` or `Localhost`; volumes are limited to a safe list (configMap, secret, emptyDir, PVC, projected, downwardAPI, ephemeral). Note the asymmetry: baseline is about *absent* dangerous fields, restricted is about *present* hardening fields — which is why many pods pass baseline untouched and fail restricted until edited. The levels are cumulative: everything restricted forbids, baseline forbids too, unless it is a field restricted newly requires. ## How PSA applies them PSA is configured with **namespace labels**, one per mode: ``` pod-security.kubernetes.io/<mode>: <level> pod-security.kubernetes.io/<mode>-version: v1.31 # optional pin, default "latest" ``` where `<mode>` ∈ {`enforce`, `audit`, `warn`} and `<level>` ∈ {`privileged`, `baseline`, `restricted`}. - **enforce** — a violating pod is **rejected** by the API server. Critically, enforcement acts on *pods*, not on the controllers that create them. If you enforce restricted and a Deployment's template violates it, the Deployment object is accepted; the ReplicaSet then fails to create pods, and the failure shows up in the ReplicaSet's events, not as an error on `kubectl apply`. That surprise is the single most common PSA support ticket. - **audit** — the pod is allowed, and an annotation naming the violated policy is added to the API server audit log entry. Zero user-visible effect; ideal for measuring blast radius. - **warn** — the pod is allowed and a warning is returned to the client. Unlike enforce, warn *does* evaluate workload resources like Deployments, so `kubectl apply -f deploy.yaml` prints the warning at apply time. That is why warn is the mode that actually reaches developers. The `-version` suffix pins the policy to a Kubernetes minor version so that upgrading the cluster does not silently tighten the rules; `latest` is the default and moves with the cluster. Exemptions exist in the PSA configuration file (by username, RuntimeClass, or namespace) but are cluster-level configuration, not something a namespace owner can grant themselves. ## A workable rollout 1. Label every namespace `warn` and `audit` at the target level; leave `enforce` unset or at `privileged`. 2. Query the audit log / collect the warnings for a full deployment cycle, including CronJobs and rarely-restarted workloads. 3. Fix manifests — usually adding the four restricted fields and an emptyDir or two. 4. Set `enforce` namespace by namespace, starting with the least critical. 5. Give genuine infrastructure namespaces `enforce: privileged` or `baseline` explicitly, with an owner recorded, rather than leaving them unlabelled. Set a cluster-wide default in the PSA admission configuration so that a brand-new namespace is not silently unrestricted. `kubectl label --dry-run=server` is the fast way to test a namespace: applying the label with `--dry-run=server` reports which existing pods would violate it. ## Limits worth naming PSA only inspects pod-spec fields it knows about. It cannot express "images must come from our registry", "every pod needs resource limits", or anything conditional on other objects. Those need a policy engine at the validating-admission layer. PSA's value is that it is built in, needs no extra component, and covers the escalation-relevant fields precisely.
- You set enforce: restricted on a namespace and kubectl apply of a Deployment succeeds, yet no pods appear. Why?PSA's enforce mode evaluates Pod objects, not the workload controllers that create them. The Deployment and its ReplicaSet are admitted; the ReplicaSet controller then tries to create pods and each creation is rejected. You see it via kubectl describe replicaset or kubectl get events, where the failure message names the violated policy fields. The warn mode is the one that evaluates Deployments and surfaces the problem at apply time, which is why you enable warn alongside enforce.
- What is the practical difference between audit and warn?Both allow the pod. Audit writes an annotation into the API server audit log, so it is a fleet-wide measurement channel for platform teams and invisible to developers. Warn returns a warning over the API response, so the developer running kubectl sees it immediately, and warn also evaluates workload resources such as Deployments and CronJobs. Use audit to size the problem and warn to distribute the fix.
- Which pods legitimately need the privileged level, and how do you keep that from spreading?Node-level infrastructure: CNI plugins, CSI node drivers, storage and log agents, node monitoring that reads host paths. Keep them in dedicated namespaces labelled enforce: privileged, with a recorded owner and justification, so the exception is a small, named, auditable set rather than an unlabelled namespace that defaults to unrestricted. Set a cluster-wide PSA default of baseline or restricted so new namespaces are never accidentally open.
Baseline is a bouncer refusing weapons at the door; restricted also requires everyone to show ID and check their coat. Warn and audit are the same bouncer taking notes instead of turning people away.
saying these in an interview costs you the question
- Confusing Pod Security Admission with the removed PodSecurityPolicy
- Believing enforce mode rejects the Deployment rather than the pods it creates
- Thinking baseline requires non-root or dropping capabilities — those are restricted
- Expecting PSA to enforce arbitrary rules like allowed registries or required resource limits
- Leaving namespaces unlabelled and assuming they inherit the strictest level