CertGrid CertGrid
Hands-on Lab·Kubernetes and Cloud Native Security Associate

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

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.

The cka5001 cluster: one control plane and 3 schedulable workers, on Cilium.
Server NameIP AddressOSRolesCPURAMHDD
CKA5001192.168.0.41Ubuntu 26.04 LTSControl Plane Node (tainted NoSchedule)2 Core4 GB50 GB
CKA5001-NODE01192.168.0.42Ubuntu 26.04 LTSWorker Node2 Core4 GB50 GB
CKA5001-NODE02192.168.0.43Ubuntu 26.04 LTSWorker Node2 Core4 GB50 GB
CKA5001-NODE03192.168.0.44Ubuntu 26.04 LTSWorker Node2 Core4 GB50 GB

Before you start

  1. 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   restricted

    Expected resultkcsa-open with ENFORCE <none>, kcsa-strict with ENFORCE restricted.

    Success conditionYou have a controlled namespace and an uncontrolled one to compare.

  2. 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 broke

    Expected resultpod/plain created and condition met in kcsa-open. In kcsa-strict: Error from server (Forbidden): pods "plain" is forbidden: violates PodSecurity "restricted".

    Success conditionYou have seen the control refuse something.

Troubleshooting

Official sources