Kubernetes Pod Security Standards define, across three levels, Privileged, Baseline and Restricted, which security settings a pod must have before Kubernetes admits it into a namespace at all. These levels are enforced through Pod Security Admission, which checks every request as soon as a matching label sits on the namespace. Without that control, a single misconfigured pod can gain far-reaching access to its node, completely independent of what RBAC allows it to do at the level of the Kubernetes API.
I run production Kubernetes clusters and covered security context and admission in detail in my Kubernetes Practical Guide for Rheinwerk Computing (2024). You can find this article together with all my other Kubernetes topics on my Kubernetes page.
What Kubernetes Pod Security Standards define: the three levels
The three Pod Security Standards levels differ in how much freedom they leave a pod. Privileged is the least restrictive level, it allows practically everything and only suits system and infrastructure workloads that genuinely need deep access to the node, for example certain networking or storage components. Baseline blocks known ways of escalating privileges, such as privileged containers or changing host namespaces, but still leaves enough room for most ordinary applications. Restricted goes the furthest and requires, among other things, that a pod does not run as root and claims no additional Linux capabilities, aligned with established practice for hardening pods.
The levels build on each other: every stricter level includes all the rules of the looser ones. A pod that satisfies Restricted automatically satisfies Baseline too. For you as an operator that means: you choose one level per namespace, and every pod inside it must meet that level, no matter how carefully its team wrote the application itself.
Security context: the settings at pod and container level
Pod Security Standards are technically enforced through the security context you set in every pod manifest. At pod level you control, among others, runAsNonRoot, which forbids starting as the root user, runAsUser and runAsGroup for a fixed user and group ID, and fsGroup for file permissions on mounted volumes. At container level you add privileged for privileged mode, readOnlyRootFilesystem for a read-only root file system, allowPrivilegeEscalation against gaining extra privileges after startup, and capabilities, which let you add or drop individual Linux capabilities.
A pod that meets the Restricted level in practice often looks like this:
apiVersion: v1
kind: Pod
metadata:
name: web-restricted
namespace: team-shop
spec:
securityContext:
runAsNonRoot: true
runAsUser: 10001
runAsGroup: 10001
seccompProfile:
type: RuntimeDefault
containers:
- name: web
image: nginxinc/nginx-unprivileged
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop: ["ALL"]
volumeMounts:
- name: tmp
mountPath: /tmp
- name: cache
mountPath: /var/cache/nginx
volumes:
- name: tmp
emptyDir: {}
- name: cache
emptyDir: {}
The pod runs with a fixed, unprivileged user ID, its root file system is read-only, privilege escalation is forbidden, and every Linux capability has been dropped. This exact combination is what the Restricted level of Pod Security Admission checks for. Two honest caveats: the image has to work without root in the first place, which is why the example uses the unprivileged Nginx variant instead of the standard one. And a read-only root file system crashes applications that write into their own directory at runtime. That is why the manifest carries two emptyDir volumes: Nginx puts temporary files under /tmp and its cache under /var/cache/nginx and would fail on startup without those two mounts. The fastest way to find out which paths your own application needs is to start it once with a read-only root and read the error.
Pod Security Admission: enforcing standards on namespaces
Pod Security Admission replaced the earlier Pod Security Policy, which lived in the cluster as a resource of its own; you will only find that name in older documentation. Instead of a separate, complex policy resource, a single label on the namespace is now enough to turn on one of the three levels:
apiVersion: v1
kind: Namespace
metadata:
name: team-shop
labels:
pod-security.kubernetes.io/enforce: baseline
pod-security.kubernetes.io/audit: restricted
pod-security.kubernetes.io/warn: restricted
The three modes can be set independently of each other. enforce rejects pods that violate the given level, it is the only setting with real teeth. audit logs violations of a stricter level in the audit log without blocking the pod. warn prints a warning on the console during kubectl apply but still lets the pod run. This combination, an enforced Baseline together with an observing audit or warn on Restricted, is my default approach for seeing which pods could already run more restrictively today, without risking anything right away. How this relates to admission controllers in general, which can enforce rules beyond pure pod security, is covered in Kubernetes Admission Controllers Explained.
Moving from Baseline to Restricted without an outage
Tightening an existing level after the fact is where most Pod Security outages happen, not the initial rollout into an empty namespace. A pod that used to run as root or needed a writable root file system simply stops starting under Restricted, and enforce blocks it right at kubectl apply.
My approach for real clusters: set audit and warn to the target level first and watch the audit log and the developers' warnings for a few days. Only once nothing turns up there anymore does the same level also move into enforce. Worth knowing: the level always applies to the whole namespace, a single pod cannot lower it for itself. If a workload demonstrably needs more privileges, it gets its own namespace at a lower level, or you add an exemption to the API server's admission configuration. Either should stay the exception and be documented, otherwise the exception ends up watering down the whole rule.
Pod security is not RBAC: where the line runs
Pod Security Standards and RBAC solve different problems, even though both fall under security governance. RBAC decides who can perform which action on which resource through the Kubernetes API, in other words whether a person or a service account is allowed to create, change or delete a pod at all. What that pod is then allowed to do once it is running is governed by the security context, and with it the Pod Security Standards. More on the permission model for people and service accounts is in Kubernetes RBAC: Roles and Permissions.
In practice the two layers complement each other: even a service account with very narrow RBAC permissions can reach beyond its container onto the node if its pod is allowed to run privileged. And a pod with a strict security context does not help much if its service account has cluster-wide read access to every secret. Securing only one of the two layers gets you only half the job done.
Frequently asked questions
What is the difference between Baseline and Restricted?
Baseline blocks known ways of escalating privileges, such as privileged containers, but otherwise leaves plenty of room for ordinary applications. Restricted additionally requires, among other things, starting without root privileges and giving up extra Linux capabilities, which suits workloads that need no special access to the node.
How do I turn on Pod Security Standards for a namespace?
With a label on the namespace, for example pod-security.kubernetes.io/enforce: baseline. You can additionally set audit and warn to a stricter level to make violations of a target level visible before you actually enforce it.
What happened to the Pod Security Policy?
The Pod Security Policy is deprecated and has been replaced by the simpler Pod Security Standards together with Pod Security Admission. Instead of a dedicated policy resource, a namespace label is now enough to turn on one of the three levels, which is considerably less error prone than the old policy resource.
Is Pod Security Admission enough to secure my pods on its own?
No, Pod Security Admission only checks a fixed set of security context fields against one of the three levels. For finer rules, such as allowed image registries or mandatory fields like resource limits, you need additional admission controllers, and for the question of who is allowed to create a pod at all, you still need RBAC.
Where to go next
Once pods are locked down, the next thing to control is who they are even allowed to talk to over the network, more on that in Kubernetes Network Policy Explained. My suggestion for today: set audit and warn to Restricted in a non-critical namespace and check after a few days which of your pods would already pass. The full overview of levels and checks is in the Kubernetes documentation on Pod Security Standards, and details on the individual fields are in the documentation on the security context.
In full detail with all examples, this is covered in chapter 7 of my Kubernetes Practical Guide (Rheinwerk Computing).