Pod Security Admission Levels
Pod Security Admission is the control a KCSA candidate is most likely to be asked about and least likely to have seen refuse anything. This guide labels a namespace `restricted`, submits an ordinary Pod, and reads the rejection.
Cloud Native Security Guide 6 of 42 Beginner
- Kubernetesapiserver v1.36.4, kubelet v1.36.3
- Runtimecontainerd 2.2.6
- CNICilium 1.18.1 - tunnel/VXLAN, with Hubble relay and UI
- Host OSUbuntu 26.04 LTS, kernel 7.0.0-29
- Built withkubeadm v1.36.3 - podSubnet 10.244.0.0/16, serviceSubnet 10.96.0.0/12
- TimeAbout 14 min
- Reviewed25 August 2026
Written against the versions above. PSA is built into the apiserver and needs nothing installed - which is why it works on this cluster where no admission webhook exists at all. The three levels (`privileged`, `baseline`, `restricted`) and three modes (`enforce`, `audit`, `warn`) are stable API.
| Server Name | IP Address | OS | Roles | CPU | RAM | HDD |
|---|---|---|---|---|---|---|
| CKA5001 | 192.168.0.41 | Ubuntu 26.04 LTS | Control Plane Node (tainted NoSchedule) | 2 Core | 4 GB | 50 GB |
| CKA5001-NODE01 | 192.168.0.42 | Ubuntu 26.04 LTS | Worker Node | 2 Core | 4 GB | 50 GB |
| CKA5001-NODE02 | 192.168.0.43 | Ubuntu 26.04 LTS | Worker Node | 2 Core | 4 GB | 50 GB |
| CKA5001-NODE03 | 192.168.0.44 | Ubuntu 26.04 LTS | Worker Node | 2 Core | 4 GB | 50 GB |
Before you start
- guide 3 - which showed 5 of 5 namespaces with no PSA label at all.
-
Two namespaces, one of them labelled
The label is the entire configuration. There is nothing to install.
bash Example session kubectl create ns kcsa-open >/dev/null && kubectl create ns kcsa-strict >/dev/null && kubectl label ns kcsa-strict pod-security.kubernetes.io/enforce=restricted pod-security.kubernetes.io/warn=restricted >/dev/null && kubectl get ns kcsa-open kcsa-strict -o custom-columns='NAME:.metadata.name,ENFORCE:.metadata.labels.pod-security\.kubernetes\.io/enforce'NAME ENFORCEkcsa-open <none>kcsa-strict restrictedExpected result
kcsa-openwithENFORCE <none>,kcsa-strictwithENFORCE restricted.Success conditionYou have a controlled namespace and an uncontrolled one to compare.
-
The same Pod, twice
Identical spec. One namespace takes it, the other does not.
bash Example session kubectl -n kcsa-open run plain --image=docker.io/library/busybox:1.37 --restart=Never --command -- sh -c 'sleep 600' 2>&1 | tail -1; kubectl -n kcsa-open wait --for=condition=Ready pod/plain --timeout=120spod/plain createdpod/plain condition metkubectl -n kcsa-strict run plain --image=docker.io/library/busybox:1.37 --restart=Never --command -- sh -c 'sleep 600' 2>&1 | head -4; echo "--- the SAME Pod spec, refused. Pod Security Admission names every rule it broke"Error from server (Forbidden): pods "plain" is forbidden: violates PodSecurity "restricted:latest": allowPrivilegeEscalation != false (container "plain" must set securityContext.allowPrivilegeEscalation=false), unrestricted capabilities (container "plain" must set securityContext.capabilities.drop=["ALL"]), runAsNonRoot != true (pod or container "plain" must set securityContext.runAsNonRoot=true), seccompProfile (pod or container "plain" must set securityContext.seccompProfile.type to "RuntimeDefault" or "Localhost")--- the SAME Pod spec, refused. Pod Security Admission names every rule it brokeExpected result
pod/plain createdandcondition metinkcsa-open. Inkcsa-strict:Error from server (Forbidden): pods "plain" is forbidden: violates PodSecurity "restricted".Success conditionYou have seen the control refuse something.
Troubleshooting
PSA is not restricting anything.
Why: No namespace carries a
pod-security.kubernetes.io/enforcelabel.Fix:It is opt-in per namespace. Label it, or nothing happens.
A Deployment reports no error but no Pods appear.
Why: The Deployment was accepted; its ReplicaSet cannot create Pods.
Fix:
kubectl describe replicaset- the PSA rejection is on the ReplicaSet's events.Existing Pods keep running after a namespace is labelled.
Why: Admission judges submissions, not existing objects.
Fix:Expected. Recreate them, or use
warn/auditfirst to find what would break.A level's meaning changed after a cluster upgrade.
Why: No
enforce-versionlabel, so the level tracks the apiserver.Fix:Pin it:
pod-security.kubernetes.io/enforce-version: v1.31.Forbiddenand it is not clear whether RBAC or PSA.Why: Both use the word.
Fix:Read the body.
violates PodSecurityis admission;cannot <verb>is RBAC.