Pod Security Standards in Kubernetes
Learn what a pod is allowed to do inside your cluster, how the three security levels called Privileged, Baseline, and Restricted work, and how Pod Security Admission enforces them, from first principles to safe production rollout.
Imagine an apartment building with a hundred flats. Most tenants only want a quiet home. But a few might want to knock down a wall, copy the master key, or run a noisy workshop that shakes the whole building. If the landlord lets anyone do anything, one careless or dishonest tenant can harm everybody. So the building has house rules: tenants may paint and decorate, but they may not touch the structure, the pipes that serve everyone, or the master key.
A Kubernetes cluster is a shared building, and pods are the tenants. Pod Security Standards are the house rules that say how much power a pod may have. Some pods, like the building’s own plumbing, need special access. Most do not. This tutorial explains, from the ground up, what those rules are, how Kubernetes enforces them, and how to apply them to a real cluster without breaking the applications that live in it.
1Why Pod Security Matters
A container looks like a sealed box, but the walls are only as strong as the settings you give it. A pod with the wrong settings can reach out and touch the machine underneath.
Containers are not tiny computers
A container is a package that holds a program and everything it needs. Many people imagine a container as a small, sealed computer. In truth, containers on the same machine share one core piece of software, called the kernel, which is the part of the operating system that controls memory, files, and devices. The container’s walls are built by asking the kernel to hide things from the program inside.
This means that the strength of the walls depends on how the container is configured. A container started with normal settings sees only its own files and processes. A container started with special power can see the machine’s files, look at other programs, and even take control of the machine. Once an attacker controls the machine, every other pod on it is in danger, and often the whole cluster.
Think of a hotel room. Guests get a key to their own room and cannot open other doors. But if the hotel hands one guest the master key, that guest can walk into every room. Giving a pod extra power is like handing over the master key: sometimes necessary for staff, but dangerous for ordinary guests.
What can go wrong
Most break-ins do not start with clever tricks. They start with a small mistake, such as a program with a flaw that lets an attacker run their own commands inside the container. If that container has few powers, the attacker is stuck in a small box. If it has many powers, the attacker can escape the box. Typical dangerous settings include running as the all-powerful root user, running in privileged mode, sharing the machine’s network or process space, and mounting the machine’s own folders into the pod.
The problem of doing it by hand
Teams may write security rules in a document and hope every developer follows them. But hundreds of pods are created by many people, and mistakes will happen. What is needed is a gatekeeper built into Kubernetes that checks every new pod against agreed rules and refuses the ones that break them. Pod Security Standards define the rules, and Pod Security Admission is that gatekeeper.
A good rule of life for pods: give each pod only the power it truly needs, and no more. This idea is called the principle of least privilege, and everything in this tutorial is a way to apply it.
2The Core Idea: Standards, Levels, and a Gatekeeper
There are two separate things to learn. The standards say what is allowed. The admission controller decides whether a pod that arrives follows them.
Pod Security Standards
Pod Security Standards, often shortened to PSS, are a set of three ready-made policies maintained by the Kubernetes project. Each policy is a list of things a pod may or may not do. The three policies are cumulative in strength, from wide open to tightly locked.
Privileged
Completely open. No restrictions at all. Meant for trusted system components such as storage drivers and network plugins that truly need deep access to the machine.
Baseline
Minimally restrictive. Blocks the well-known dangerous settings that allow easy escapes, while still letting most ordinary applications run without changes.
Restricted
Heavily restricted. Follows current good practice for hardening pods. Some applications need changes to run under it.
Pod Security Admission
An admission controller is a step inside the Kubernetes API server that looks at every request to create or change an object, after the person is identified and allowed, but before the object is saved. It can accept, change, or reject the request. Pod Security Admission, or PSA, is an admission controller built into Kubernetes that checks pods against the standards. You turn it on for a namespace by adding labels. A namespace is a named area inside the cluster that groups related things.
flowchart LR
U["Person or program creates a pod"] --> API["API server"]
API --> AUTH["Who are you, and may you do this?"]
AUTH --> PSA["Pod Security Admission checks the namespace level"]
PSA -->|"Follows the level"| SAVE["Pod saved and started"]
PSA -->|"Breaks the level"| NO["Request refused with a clear reason"]
Read the figure from left to right. A request to create a pod reaches the API server. The server first checks who the caller is and whether they may do this. Then Pod Security Admission looks at the level chosen for that namespace. If the pod follows the level, it is saved and started. If not, the request is refused and the reason is shown.
Think of an airport security gate. The rulebook lists what may not be carried onto a plane, and there may be different rulebooks for different areas. The gate officer checks each bag against the rulebook of that area. The rulebook is the Pod Security Standard, and the officer is Pod Security Admission.
What replaced what
Older clusters used a feature called PodSecurityPolicy for this purpose. It was powerful but confusing, and it was removed from Kubernetes in version 1.25. Pod Security Admission is its simpler replacement. It has fewer options, but it is easy to understand and comes built in, with no extra software to install.
Kubernetes only checks pods against a level if the namespace has been labelled for it, or if a cluster-wide default has been set. A brand-new namespace with no labels may allow everything, depending on how your cluster was set up. Always check.
3Background You Need First
A few ideas from Linux and Kubernetes appear everywhere in pod security. Learn them once and the rest becomes easy.
Pods, containers, and namespaces
A pod is the smallest thing Kubernetes runs. It holds one or more containers that share a network and storage. A Deployment is an object that keeps a chosen number of identical pods running. A namespace groups objects and lets you apply rules to the whole group. Pod Security Admission works at the namespace level: one namespace, one set of rules.
The root user
On Linux, every program runs as some user. The user called root is all-powerful: it can read any file, change any setting, and start or stop anything. Ordinary users have limited power. If a container runs as root, and an attacker takes control of the program inside, the attacker also acts as root inside that container, which makes escaping far easier. Running as a normal user is one of the simplest and most effective protections.
Root is like the building’s caretaker who has keys to every door. A visitor who tricks the caretaker gets every key. A visitor who tricks a normal tenant gets only one flat.
Capabilities
Linux splits the power of root into many small pieces called capabilities. One capability lets a program change the system clock. Another lets it open network ports below a certain number. Another lets it change file owners. A program can hold only the pieces it needs. Containers start with a modest default set, and pod security rules often say to drop all of them and add back only a few.
Privileged mode and host sharing
A privileged container is one that has nearly all the power of the machine itself. It can see the machine’s devices and change its settings. Separately, a pod can ask to share parts of the machine: its network, its process list, or its inter-process communication area. Each of these breaks a wall that is normally kept in place.
Seccomp, AppArmor, and SELinux
Programs ask the kernel to do things through a menu of requests called system calls. Seccomp is a filter that lets a container use only a safe part of that menu, blocking rare and dangerous requests. AppArmor and SELinux are two other systems that limit what a program may touch, based on rules. Together they act as extra locks on the container’s doors.
Root user
The all-powerful account. Avoid running containers as root.
Capability
One small slice of root’s power. Give only what is needed.
Privileged container
A container with near-full machine power. Almost never needed for normal applications.
Seccomp
A filter that blocks dangerous requests to the kernel.
Host sharing
Letting a pod use the machine’s own network, processes, or folders. Removes walls.
Admission controller
A checkpoint in the API server that can accept or refuse requests.
The security context
In Kubernetes, the settings that control these powers live in a part of the pod description called the security context. It can be set for the whole pod and also for each container. It says which user to run as, whether to allow gaining extra power, which capabilities to keep, and which seccomp filter to use. Pod Security Standards are, in effect, rules about what the security context and a few other fields may contain.
4The Three Levels in Detail
Each level has a clear purpose. Choosing the right one for each namespace is the most important decision in the whole subject.
Privileged: no fences
The Privileged level allows everything. It exists because some parts of a cluster genuinely need deep access. A network plugin must change the machine’s network. A storage driver must mount disks. A monitoring agent may need to read machine-level information. These are trusted components installed by administrators, and they typically live in system namespaces. Nothing else should use this level.
Baseline: stop the obvious dangers
The Baseline level blocks known ways for a pod to escalate its power, while allowing most applications to run with no changes. It forbids privileged containers, sharing the host’s network, process, or communication areas, mounting the machine’s folders, using host ports, and adding risky capabilities. It also blocks unsafe kernel settings and unconfined system-call filters, and restricts certain access-control settings. An application that runs as root can still pass Baseline, because the aim here is to be easy to adopt.
Restricted: current good practice
The Restricted level includes everything in Baseline and adds hardening. Containers must run as a non-root user, must not be able to gain extra power, must drop all capabilities, except that one for binding low network ports may be added, and must use a safe system-call filter. Only a limited list of volume types is allowed. Many modern applications can meet these rules with small changes, but some old ones cannot without work.
flowchart TD
P["Privileged: everything allowed"] --> B["Baseline: blocks known escalations"]
B --> R["Restricted: hardened good practice"]
P -.->|"for trusted system parts"| S1["Network plugins, storage drivers"]
B -.->|"for most ordinary applications"| S2["Typical web apps and services"]
R -.->|"for sensitive or public-facing workloads"| S3["Payments, identity, internet-facing apps"]
Compare three kinds of buildings. A construction site lets workers go almost anywhere, which is Privileged. An office building blocks the roof, the boiler room, and the server closet, but lets staff move freely otherwise, which is Baseline. A bank vault area allows only named people through many locked doors, which is Restricted.
| Question | Privileged | Baseline | Restricted |
|---|---|---|---|
| Privileged containers allowed? | Yes | No | No |
| Share host network, processes, or communication areas? | Yes | No | No |
| Mount the machine’s own folders? | Yes | No | No |
| Extra capabilities beyond the default set? | Yes | No | No, and all must be dropped |
| May run as root? | Yes | Yes | No, must run as non-root |
| May gain extra power while running? | Yes | Yes | No |
| System-call filter required? | No | Must not be turned off | Must be set to a safe choice |
| All volume types allowed? | Yes | Most, but not host folders | Only a short safe list |
If you are unsure, start ordinary application namespaces at Baseline, and aim to move important ones to Restricted over time. Baseline gives a large gain for very little effort.
Why only three
The Kubernetes project chose to keep the standards few and simple, because too many choices make security confusing and easy to get wrong. If you need finer control, such as allowing one specific capability for one specific application, you can add another policy tool alongside. We discuss those later.
5The Controls Explained in Plain Words
The standards are made of individual controls. Here is what each one protects against, using everyday language.
| Control | What it means | Why it matters | Level |
|---|---|---|---|
| Privileged containers | The container gets nearly all the machine’s power | Easy escape to the machine | Blocked from Baseline |
| Host namespaces | The pod shares the machine’s network, process list, or communication area | Can spy on or attack other programs | Blocked from Baseline |
| Host ports | The pod opens a port on the machine itself | Bypasses normal network rules | Blocked from Baseline |
| Host path volumes | The pod mounts a folder from the machine | Can read or change the machine’s files | Blocked from Baseline |
| Capabilities | Slices of root’s power added to the container | Small extra powers can be combined for an attack | Limited in Baseline, all dropped in Restricted |
| Unsafe kernel settings | Changing kernel behaviour from inside the pod | Can affect the whole machine | Only a safe list is allowed from Baseline |
| System-call filter | A filter on requests to the kernel | Blocks rare dangerous calls | Cannot be disabled in Baseline, required in Restricted |
| Running as non-root | The program runs as an ordinary user | Limits damage if the program is hacked | Restricted |
| Privilege escalation | A program gaining more power than it started with | A common step in attacks | Blocked in Restricted |
| Volume types | Which kinds of storage a pod may attach | Some kinds reach into the machine | Limited in Restricted |
Sharing the host
Normally, each pod sees only its own network, its own processes, and its own files. Sharing the host’s network means the pod can see all traffic on the machine and reach services that were meant to be private. Sharing the host’s process list means the pod can see, and sometimes interfere with, every program on the machine. These options exist for tools such as monitoring agents, but they should never be given to ordinary applications.
Sharing the host is like letting a guest in your flat listen to the whole building’s phone lines and read the list of every resident’s visitors. A guest who only wants a quiet room has no need for that.
Mounting the machine’s folders
A hostPath volume connects a folder on the machine to the inside of a pod. It is convenient for tests, but it is dangerous. If the pod can write into the machine’s folders, it might replace important files or read secrets that belong to other pods. In one well-known trick, a pod mounts the machine’s root folder and then has full control of the machine.
Running as non-root, and gaining power
Two Restricted controls work as a pair. The first says the program must run as a normal user. The second says the program may not gain more power than it started with. Some programs use special files that grant extra power when run. Blocking this closes a door that attackers often try.
The gatekeeper reads what the pod asks for. It does not know whether the program inside is honest. So it can prevent risky requests, but it cannot detect a program that is already compromised. It is one layer of safety, not the only one.
What the standards do not cover
Pod Security Standards do not scan images for known flaws, do not limit who can talk to whom on the network, do not control who may use the Kubernetes API, and do not watch programs while they run. Those jobs belong to other tools, and a strong setup uses several together. We look at this in the security chapter.
6Pod Security Admission: Modes and Labels
You choose a level for a namespace by adding labels. Each label picks a level and a mode, and the mode says what happens when a pod breaks the rules.
Three modes
Enforce
Pods that break the level are refused. They are never created. This is the strong setting.
Audit
Pods that break the level are allowed, but a note is written into the cluster’s audit log for later review.
Warn
Pods that break the level are allowed, but the person creating them sees a warning message straight away.
Consider a speed camera system. Enforce is a locked barrier that stops the car. Audit is the camera that quietly records the number plate for later. Warn is a sign that flashes “you are too fast” as you pass. You can use all three at once, or introduce them gradually.
How labels are named
Each mode has its own namespace label. The label names begin with pod-security.kubernetes.io followed by a slash and the mode, which is enforce, audit, or warn. The value of the label is the level: privileged, baseline, or restricted. For example, a namespace labelled with enforce set to baseline will refuse pods that break Baseline.
Each mode can also have a version label, which pins the rules to a particular Kubernetes version, or to the word latest. Pinning is useful, because the standards grow slowly over time. If you pin to a version, your rules stay exactly the same when the cluster is upgraded. If you use latest, the rules follow the newest definition.
| Label part | Values | Meaning |
|---|---|---|
| enforce | privileged, baseline, restricted | Refuse pods that break this level |
| audit | privileged, baseline, restricted | Record a note for pods that break this level |
| warn | privileged, baseline, restricted | Show a warning for pods that break this level |
| enforce-version, audit-version, warn-version | A version number, or latest | Which release of the rules to use |
Mixing modes
The three modes are independent, so you can set different levels for each. A very common pattern is to enforce Baseline, while auditing and warning at Restricted. That way, nothing dangerous gets in, and teams also learn early which of their workloads would fail the stricter level, without anything breaking.
A company sets the namespace for its web applications to enforce Baseline and to audit and warn at Restricted. Developers see warnings every time they deploy a pod that runs as root. Over a few weeks, they fix their images one by one. When the warnings stop, the team changes enforce to Restricted, and the namespace is now hardened with no surprises.
Cluster-wide defaults and exemptions
Besides namespace labels, an administrator can set defaults for the whole cluster, through the configuration of the admission controller. They can also list exemptions: users, runtime classes, or namespaces that the controller should skip entirely. Exemptions are sometimes needed for system components, but every one weakens the protection, so keep the list very short and review it often.
If a cluster-wide default level is set, a namespace with no labels still gets protection. This closes the gap where someone creates a namespace and forgets to label it.
7Architecture: Where the Gatekeeper Sits
To use Pod Security Admission well, it helps to know exactly where it stands in the path of a request and what pieces are involved.
The path of a request
Everything in Kubernetes goes through the API server, the front door of the cluster. When someone asks to create an object, the request passes through several stages in a fixed order. First comes authentication, which asks who the caller is. Then authorization, which asks whether this caller may do this action. Then admission, which is a series of checkpoints that may change or refuse the request. Finally, the object is saved.
Admission has two kinds of checkpoints. Mutating ones may change the request, such as adding default settings. Validating ones only accept or refuse. Pod Security Admission is a validating checkpoint. It never changes a pod. It only says yes or no, and it sees the pod after any mutating checkpoints have made their changes.
flowchart TD
REQ["Request to create a pod"] --> AN["Authentication: who is this?"]
AN --> AZ["Authorization: is this person allowed?"]
AZ --> MUT["Mutating admission: defaults and changes"]
MUT --> VAL["Validating admission"]
VAL --> PSA["Pod Security Admission"]
VAL --> OTHER["Other policy checks"]
PSA --> DEC{"All checks pass?"}
OTHER --> DEC
DEC -->|"Yes"| STORE["Saved in the cluster store"]
DEC -->|"No"| REJ["Refused with reason"]
In the figure, notice that Pod Security Admission is one of several validating checks. Other policy tools sit at the same stage. If any of them says no, the pod is refused. This is why you can safely combine PSA with other tools.
Think of getting a building permit. First the office checks who you are, then whether you are allowed to build in this area. Then some officers add standard notes to your plans. Finally, inspectors check the plans against safety codes. Any inspector can refuse the permit. PSA is one of those inspectors.
The pieces involved
The standards
The three definitions, built into Kubernetes and versioned along with it.
The admission plugin
Code inside the API server that compares each pod with the level set for its namespace.
Namespace labels
The per-namespace choice of level, mode, and version.
Cluster configuration
Optional defaults and exemptions, set by the cluster administrator.
Audit log and warnings
Where the results of audit and warn modes appear.
Built in, so no extra install
Pod Security Admission is part of the API server, turned on by default in current versions of Kubernetes. That is a great advantage: no extra programs to run, no extra network calls, and very little added delay. The trade-off is that it offers only the three fixed levels. It cannot express custom rules.
A team runs a managed cluster from a cloud provider. They do not control the API server, and cannot install anything into it. Because Pod Security Admission is already inside it, they only need to label their namespaces. Within an hour, every application namespace refuses privileged pods, with no new software.
8Internal Working: What Happens to a Pod
Let us follow a real deployment and see when the check happens, and why sometimes you see a warning but no refusal.
Checking pods, not Deployments
Most people do not create pods directly. They create a Deployment, which then creates a ReplicaSet, which then creates pods. The important detail is that enforcement happens when the pod itself is created, not when the Deployment is created. So a Deployment with a risky template is accepted and saved. Only when its controller tries to make the pods does the gatekeeper refuse them.
That could confuse a team: the Deployment exists, but no pods appear. To help, audit and warn modes also check the pod template inside Deployments and similar objects at the time they are created. So the developer sees a warning when applying the Deployment, even though enforcement, if enabled, will still happen later at the pod stage.
sequenceDiagram
participant D as Developer
participant API as API server
participant PSA as Pod Security Admission
participant RS as ReplicaSet controller
D->>API: Create Deployment
API->>PSA: Check pod template in warn and audit modes
PSA-->>API: Warning: template breaks Restricted
API-->>D: Deployment saved, warning shown
RS->>API: Create pod from template
API->>PSA: Check pod in enforce mode
PSA-->>API: Refuse: pod runs as root
API-->>RS: Pod rejected
RS->>API: Record failure event on ReplicaSet
Read the figure from top to bottom. The developer creates a Deployment and instantly gets a warning. The Deployment is saved. Later, the ReplicaSet controller tries to create a pod, and the enforce check refuses it. The reason is recorded as an event on the ReplicaSet, not on the Deployment. Looking at the events on the ReplicaSet is the place to find why no pods are running.
Imagine handing plans for a housing estate to the council. They may say “this design has a problem” while you hand it in. But the real refusal only arrives when a builder tries to start a particular house. If you do not read the builder’s notes, you might wonder why no house has appeared.
How the decision is made
For each pod, the plugin reads the namespace labels and works out the level and version for each mode. It then evaluates the pod against each control in that level. If any control is broken, the pod fails for that mode. The checks are done against every container, including init containers, which run before the main ones, and ephemeral containers, which are temporary ones added for debugging.
The plugin also has a cache and a set of shortcuts. If the level is privileged, no checks are needed. Exempt users and namespaces are skipped. Certain updates to a running pod are ignored, so that changing a harmless field on a pod that already exists does not suddenly cause a refusal.
What the messages look like
When a pod is refused, the message names the level, the control that was broken, and the container. For example, it may say that a container must not run as root, or that the system-call filter must be set. A message can list several problems at once. Reading these messages carefully is the fastest way to fix a workload, because they tell you exactly what to change.
| Object created | Enforce mode checks it? | Audit and warn modes check it? |
|---|---|---|
| Pod | Yes | Yes |
| Deployment, StatefulSet, DaemonSet | No, but its pods are checked later | Yes, using the pod template |
| Job and CronJob | No, but its pods are checked later | Yes, using the pod template |
| ReplicaSet and similar controllers | No, but its pods are checked later | Yes, using the pod template |
Changing a namespace label does not remove running pods. It only affects pods created or changed after the label is set. A pod that was already running with risky settings stays until it is restarted, so a cleanup may need a planned restart of workloads.
9Rolling It Out Safely
Turning on strict rules all at once can break running applications. A careful, step-by-step approach avoids nasty surprises.
The gentle path
The safest way is to learn first, then fix, then enforce. Start with the warn and audit modes, which never refuse anything. Collect the results, repair the workloads that would fail, and only then switch on enforcement. At each step, tell the teams what is coming, and give them time.
flowchart LR
A["1. List namespaces and their owners"] --> B["2. Turn on warn and audit at target level"]
B --> C["3. Review warnings and audit notes"]
C --> D["4. Fix workloads or choose a lower level"]
D --> E["5. Dry-run the enforce label"]
E --> F["6. Turn on enforce"]
F --> G["7. Keep audit and warn on for the next level"]
Take stock
List every namespace, who owns it, and what runs there. System namespaces need special care. Decide a target level for each group.
Turn on warn and audit
Label namespaces so that pods breaking the target level produce warnings and audit notes. Nothing is refused yet.
Read the results
Collect the messages from deployments and from the audit log. Group them by control, so you can see the most common problems.
Fix or adjust
Update images and settings so workloads follow the level. Where a workload truly cannot comply, move it to a separate namespace with a lower level, and record the reason.
Dry-run enforcement
Ask the cluster to test the enforce label on a namespace without applying it. It reports which existing pods would have failed.
Enforce
Apply the enforce label. Watch for refused pods in the first days, and keep a quick way to go back.
Aim higher
Keep audit and warn set to the next stricter level, so that you see what would be needed to raise the bar later.
Introducing a new safety rule at a factory works best in stages. First you put up signs and give warnings. Then you inspect and help people fix their habits. Only later do you make the rule strict, with penalties. Doing it in the opposite order upsets everyone and stops the work.
The dry run
Kubernetes lets you preview the effect of an enforce label. When you apply the label with a server-side dry-run option, the system checks every running pod in the namespace against the new level and reports warnings for those that would not pass, without changing anything. This is the single most useful tool before turning on enforcement, because it tells you exactly what would break.
Begin in test and development environments, learn the common problems, and write a short guide for developers. By the time you reach production, most fixes will be well known and easy.
Scheduled jobs and rarely used workloads may not have run during your review period. A nightly job that breaks the new rule will only fail when it next runs. Check for such workloads before enforcing, and test them in a safe place.
10Data Flow and Lifecycle of a Policy Decision
From the moment someone applies a label to the day a pod is refused or recorded, here is the whole life of one policy.
Decision
The security team decides the level for a group of namespaces, based on what runs there and how sensitive it is.
Labelling
Labels for the chosen modes and versions are put on the namespace. The plugin reads them on every relevant request.
Request
Someone, or a controller, asks to create or update a pod in that namespace.
Evaluation
The plugin checks exemptions, finds the level and version, and tests the pod against each control.
Outcome
Enforce may refuse the pod. Warn adds a message for the caller. Audit adds a note to the audit record of the request.
Observation
Refusals appear as events and errors. Audit notes flow to your log system, where teams can search and count them.
Review
Findings are reviewed, workloads are fixed, exemptions are re-examined, and the levels are raised when ready.
This is much like a traffic law. Lawmakers decide the speed limit, signs are put up, drivers pass by, cameras check, some get tickets and others warnings, the records are reviewed, and the limit is changed if needed. The cycle repeats forever, which is the sign of a healthy rule.
What happens during upgrades
When Kubernetes is upgraded, the definitions of the standards may be refined. If a namespace label uses latest, the new definition applies at once, and pods that used to pass might start to fail. If the label pins a version, the old definition keeps applying. Pinning gives control, but you must remember to update the pin from time to time, or you will fall behind current good practice.
What happens to a pod that changes
Most updates to a running pod are not related to security, such as changing a label or an annotation. The plugin knows this, and does not re-check them, so that unrelated changes are not blocked. Updates to fields that matter for security, such as the image or the security context, are checked again.
| Event | Effect on running pods | Effect on new pods |
|---|---|---|
| Add or raise an enforce label | None until they are restarted | Refused if they break the level |
| Remove an enforce label | None | No longer checked, unless a cluster default applies |
| Upgrade Kubernetes with pinned version | None | Same rules as before |
| Upgrade Kubernetes with latest label | None | New definition may refuse more |
| Add an exemption | None | Exempt users or namespaces are skipped |
Keep a short record of why each namespace has its level and why any exemption exists. Months later, when someone asks why a pod is allowed to be privileged, the answer will be at hand.
11Making Workloads Fit the Restricted Level
Most applications can meet the Restricted level with a handful of changes. Here is what those changes are, in plain words.
The usual list of fixes
Run as a normal user
Build the image so the program runs under a numbered ordinary user, and tell Kubernetes that the container must not run as root.
Forbid gaining power
Set the container so it cannot gain more privileges than it started with.
Drop all capabilities
Remove every capability, and add back only the low-port capability if the program really needs to open a port below 1024.
Choose a safe system-call filter
Set the seccomp profile to the runtime default, which blocks dangerous calls yet allows normal ones.
Use allowed volume types
Use only volumes from the short safe list, such as ConfigMaps, Secrets, emptyDir, and persistent claims, instead of host folders.
Write only where allowed
Applications that used to write to their own image folders may need a temporary volume for that, especially with a read-only file system.
Preparing for a strict safety inspection is like tidying a workshop. You put tools back in their cabinets, cover sharp edges, and mark clear paths. Most of it is simple and quick, but you must actually walk around the workshop and check each corner.
Ports below 1024
Many old programs listen on port 80 or 443. Ports below 1024 were traditionally reserved for root. Under the Restricted level, the simplest solution is to have the program listen on a higher port, such as 8080, and let the Kubernetes Service map the familiar port to it. Only if that is not possible should the low-port capability be added.
Init containers and sidecars
The rules apply to every container in the pod, not only the main one. Init containers that run first, and helper sidecars, must follow the same rules. A common surprise is a helper injected by a service mesh or a security tool, which may itself need special power. Such tools often offer a safer mode, which should be used, or they need to live in a namespace with a lower level.
Third-party charts and vendor software
Software from vendors and public packages may not be written for Restricted. Before installing it into a hardened namespace, look at its settings. Many packages have options to run as non-root and to drop capabilities. If they do not, ask the vendor, or run them in a separate namespace with Baseline, and record the reason.
| Situation | What to do |
|---|---|
| Image runs as root by default | Rebuild with a normal user, or choose a maintained image that already does |
| Application writes to its own folders | Give it a temporary writable volume, and check file ownership |
| Needs to open port 80 | Move to a high port and map it in the Service |
| Needs the machine’s folders | Rethink the design, or put it in a dedicated privileged namespace with tight access |
| Node-level agent such as monitoring or storage | Run it in a system namespace at Privileged, controlled by administrators only |
When a pod is refused, the quick fix is to lower the namespace level. Resist this. Instead, ask why the pod needs the power. Most of the time, a small change to the pod solves the problem, and the namespace stays protected.
12Security Around the Standards
Pod Security Standards are strong, but only when the ways around them are also closed. Here are the questions of who may change the rules, and what else must be layered on.
Who can change the labels
The labels that control pod security live on the namespace. Anyone who is allowed to edit a namespace can weaken its rules by changing the labels. This is a common gap. Use role-based access control, or RBAC, the Kubernetes system that decides who can do what, so that only cluster administrators can change namespaces and their labels. Ordinary developers should be able to create pods in their namespace, but not edit the namespace itself.
House rules are useless if any tenant can cross them out on the notice board. The notice board should be behind glass, and only the landlord should hold the key.
Layers of defence
No single control stops every attack. A strong setup layers several, so that a failure of one does not lead to a disaster. Pod Security Standards handle what pods may ask for. Other layers handle images, network paths, permissions, secrets, and what happens at run time.
| Layer | Question it answers | Example tools or features |
|---|---|---|
| Image safety | Is what we run free of known flaws? | Image scanning, signed images, trusted registries |
| Pod Security Standards | Is the pod asking for too much power? | Pod Security Admission |
| Access control | Who may create pods and change rules? | RBAC, limited service accounts |
| Network rules | Who may talk to whom? | NetworkPolicies |
| Secrets handling | Are passwords protected? | Encryption at rest, external secret stores |
| Run-time watching | Is something strange happening now? | Runtime detection tools, audit logs |
| Custom policy | Are our own rules followed? | Policy engines and validating admission policies |
Service accounts and tokens
A service account is an identity that a pod uses to talk to the Kubernetes API. If a pod does not need to talk to the API, do not mount its token. If it does, give it a role with only the permissions it needs. A hardened pod with an all-powerful token is still dangerous, because an attacker inside can use the token to control the cluster from within.
Extra locks: read-only file systems and more
Some good practices go beyond the standards. A read-only root file system stops attackers from writing new programs into the container. Resource limits stop one pod from starving others. Avoiding automatic mounting of tokens reduces exposure. These are not required by the Restricted level, but they fit well beside it.
For code you do not fully trust, such as customer-supplied programs, consider extra isolation through special runtimes that give each pod a stronger wall. The standards reduce risk, but for truly untrusted code, stronger walls are worth the cost.
Every exempt user or namespace can create pods with any power. Keep the list tiny, name each one, record why, and review it regularly. An exemption forgotten for years is an open door.
A company enforced Restricted on all application namespaces, but found during a review that a group of developers had permission to edit namespaces. One of them, to speed up a test, had changed a label to Privileged and never changed it back. The fix had two parts: limit namespace editing to administrators, and add a simple alert that fires whenever a pod security label is changed.
13Advantages, Disadvantages, and Trade-offs
Pod Security Admission is deliberately simple. That simplicity is both its greatest strength and its main limit.
Advantages
- Built into Kubernetes, with nothing extra to install or run.
- Easy to understand: three levels and three modes.
- Turned on by simple namespace labels.
- Warn and audit modes make safe, gradual rollout possible.
- Standards are maintained by the Kubernetes project and follow good practice.
- Very low delay, because it runs inside the API server.
Disadvantages
- Only three fixed levels, with no custom rules.
- Works per namespace, not per individual pod or label.
- Cannot change pods to make them compliant, only accept or refuse.
- Does not cover images, networks, permissions, or run-time behaviour.
- Existing pods are not checked again until they are recreated.
- Old applications may need real work to fit Restricted.
Comparing with the alternatives
| Approach | Strength | Weakness |
|---|---|---|
| Pod Security Admission | Built in, simple, standard levels | No custom rules, no fixing |
| Policy engines such as Kyverno or OPA Gatekeeper | Custom rules, can also change or generate objects, reporting | Extra software to run, learn, and keep healthy |
| Validating admission policies | Built-in way to write custom rules in an expression language | Newer, needs careful writing and testing |
| The old PodSecurityPolicy | Was flexible | Removed from Kubernetes, confusing to use |
| Nothing | No effort | Any pod can ask for any power |
Pod Security Admission is like a standard building code: clear, widely known, and enough for most houses. A policy engine is like a custom rulebook written for your own estate, with extra rules for your own needs. Many estates use the standard code first and add custom rules only where the code is not enough.
How the two are often combined
A common approach is to use Pod Security Admission as the baseline for every namespace, since it is free and always on. Then a policy engine adds rules for things the standards do not cover, such as requiring resource limits, allowing only images from your own registry, or requiring certain labels. The two work side by side at the same admission stage.
Every extra tool needs upkeep. Use the built-in standards first. If you find rules you truly cannot express with them, add a policy engine for those rules only.
14Design Patterns and Anti-patterns
Patterns are arrangements that teams have found to work. Anti-patterns are habits that look convenient but cause trouble.
Helpful patterns
Enforce low, warn high
Enforce Baseline, and audit and warn at Restricted, so the floor is safe and the path upward is visible.
Separate namespaces by trust
Group workloads by how much power they need. Ordinary apps, sensitive apps, and system tools live in different namespaces with different levels.
Cluster-wide default
Set a default level so that even unlabelled namespaces are protected.
Labels as code
Keep namespace definitions and labels in version control, and apply them through a pipeline, so changes are reviewed.
Secure base images
Provide approved images that already run as a normal user, so teams start compliant by default.
Dedicated place for privileged tools
Keep node-level agents in one or two well-guarded system namespaces, managed only by administrators.
A well-designed school has different areas: open classrooms, a locked chemistry lab, and a staff-only boiler room. Each area has rules that match its risk. You would not put the boiler in the classroom, nor apply lab rules to the playground.
Anti-patterns to avoid
Problem
Leaving application namespaces at Privileged, or with no labels and no cluster default, because “it works.”
Why It’s Harmful
Any pod, from any developer or any compromised program, can ask for full machine power. One small mistake can lead to control of the whole cluster.
Correct Approach
Set at least Baseline in every application namespace, and set a cluster-wide default for the rest.
Problem
Switching on enforce for Restricted everywhere in one day, with no warning period.
Why It’s Harmful
Deployments fail, rollouts stop, teams are angry, and the first reaction is to remove the rules altogether.
Correct Approach
Use warn and audit first, dry-run the enforce label, and roll out gradually with clear communication.
Problem
Long lists of exempt users and namespaces added whenever something fails.
Why It’s Harmful
Each exemption is a hole in the protection, and forgotten exemptions stay open for years.
Correct Approach
Fix the workload instead, or move it to a properly labelled namespace. Where an exemption is unavoidable, document it and review it on a schedule.
Problem
Letting developers edit namespaces and their labels freely.
Why It’s Harmful
Anyone can quietly lower the level, and the protection disappears without anybody noticing.
Correct Approach
Limit namespace editing to administrators using RBAC, and alert on any change to pod security labels.
Problem
Believing that Restricted makes a cluster secure and stopping there.
Why It’s Harmful
The standards do not scan images, limit network paths, control permissions, or watch running programs. Attackers use the gaps.
Correct Approach
Treat the standards as one layer, and add image scanning, network rules, careful RBAC, and run-time monitoring.
15Best Practices and Common Mistakes
A short list of habits that make the standards work in practice, and the mistakes that most often trip teams up.
Best practices
Label every namespace on purpose
Make choosing a level part of creating a namespace, and set a cluster default as a safety net.
Use all three modes together
Enforce the level you have reached, and audit and warn at the next level.
Pin versions deliberately
Pin to a known version for predictable behaviour, and schedule reviews to move the pin forward.
Build compliant images from the start
Provide approved base images that run as a normal user, and make compliance part of your pipeline.
Keep privileged workloads few and isolated
Place them in dedicated namespaces, reviewed by administrators, with tight access.
Control who can change labels
Restrict namespace editing, keep labels in version control, and alert on changes.
Watch the logs and warnings
Collect audit notes, count them by namespace and control, and track the trend toward zero.
Layer other defences
Add network rules, careful RBAC, image scanning, and run-time detection.
Home safety is not one lock but a habit: lock the door, keep the windows latched, tell neighbours when you travel, and check the smoke alarm. Cluster safety works the same way, and each small habit protects against a different kind of trouble.
Common mistakes
| Mistake | What goes wrong | Better habit |
|---|---|---|
| Assuming labels remove running risky pods | Old pods stay dangerous until restarted | Plan restarts after raising a level |
| Reading only the Deployment for errors | The real refusal is on the ReplicaSet events | Check events on the ReplicaSet, and the warnings when applying |
| Forgetting init containers and sidecars | The pod is refused because of a helper container | Check every container in the pod |
| Using latest for the version everywhere | An upgrade changes rules unexpectedly | Pin, then update on a schedule |
| Setting only warn and never enforcing | Warnings are ignored, and nothing improves | Set a date to switch to enforce |
| Applying Restricted to system components | Networking or storage stops working | Keep them in their own privileged namespaces |
| Setting the user but not forbidding root | The image may still start as root | Require non-root and set a numeric user |
A rule that looks harmless can stop an important rollout during an incident. Try each level in a test cluster first, and make sure you know the quick way to go back.
A gentle start plan
In week one, list the namespaces and set a cluster default of Baseline in warn and audit modes. In week two, review the warnings and fix the easy ones. In week three, dry-run enforce for Baseline on application namespaces, and turn it on. In the following weeks, move the most sensitive namespaces to warn and audit at Restricted, fix what appears, and then enforce. Keep going until the system namespaces are the only exceptions.
16Monitoring, Logging, and Troubleshooting
A rule you cannot see working is a rule you cannot trust. Here is how to watch pod security and how to fix the usual problems.
Where the signals appear
Warnings on apply
Shown to the person applying a manifest. Helpful for developers, but not stored anywhere.
Audit log annotations
Notes added to the audit record of the request when audit mode fires. They are the main source for review across the cluster.
Events on controllers
Refusals show as events on the ReplicaSet, Job, or similar object that tried to create the pod.
API server metrics
Counters about admission decisions, and their delay, can be scraped by your monitoring system.
Think of a bank vault log book. Each attempt to open the door is written down, with the time and the person. Reviewing the book shows who is trying, how often, and whether someone is testing the lock.
What to track
Alerts worth having
Alert when a pod security label on a namespace is changed or removed. Alert when a new namespace appears with no level set. Alert when refusals rise suddenly in a production namespace. Alert when a workload is created in a privileged namespace by someone who is not an administrator. These alerts catch both accidents and attempts to weaken the protection.
Troubleshooting the usual problems
| Symptom | Likely cause | Where to look |
|---|---|---|
| Deployment exists but has no pods | Pods are refused by enforce mode | Events on the ReplicaSet |
| Warning says a container may run as root | Non-root is not required or no user is set | The security context of that container |
| Pod refused for its system-call filter | Filter is missing or set to unconfined | The seccomp setting on the pod or container |
| Refusal mentions a capability | Extra capability added, or not all dropped | The capabilities list of each container |
| Pod refused but the main container looks fine | An init container or injected sidecar breaks the rule | All containers in the full pod description |
| New namespace has no protection | No labels and no cluster default | Namespace labels and the admission configuration |
| Rules changed after upgrade | Version label is set to latest | The version labels on the namespace |
Refusal messages list every broken control at once. Fix all of them in one change, rather than fixing one, retrying, and meeting the next.
Emergency path
If enforcement blocks something urgent, the quickest safe action is to change the mode on that one namespace from enforce to warn, fix the workload, and turn enforce back on. Record that you did it and why. Do not remove protections across the whole cluster to fix a single workload.
17Real-World Examples
Three short stories show the ideas in action. The details are typical rather than taken from any one company.
Example 1: The friendly first step
A small company with twelve namespaces had never set any pod rules. They set a cluster default of Baseline in warn and audit modes only. A week later the audit log showed that three applications mounted host folders and one ran a privileged container that was left over from an old test. They removed the leftovers, fixed the three, and turned on enforce for Baseline. No outage occurred, and the cluster was safer within a month.
Example 2: The stubborn old application
A finance team wanted their reporting tool to run under Restricted, but it ran as root, wrote logs into its own folder, and listened on port 80. They rebuilt the image with a normal user, gave it a temporary volume for logs, moved it to port 8080, and dropped all capabilities. The changes took two days. The tool worked the same as before, and the namespace could be enforced at Restricted.
Example 3: The monitoring agent that needed power
A platform team’s monitoring agent needed to read machine-level files, which is not allowed under Baseline or Restricted. Instead of lowering the level for all application namespaces, they created one dedicated namespace called monitoring-system at Privileged. Only administrators could edit it, and an alert fired whenever a new workload appeared there. Application namespaces stayed hardened, and the agent worked.
The stories are like arranging a school’s key cabinet. Most staff get keys only for their own classrooms. The caretaker has a special key set, kept in a locked box that only a few can open. The rule is not “nobody gets power,” but “power sits in the smallest possible place.”
What the stories share
Each team learned first, using warnings and audit notes. Each fixed workloads instead of lowering the rules. And each placed the few workloads that truly needed deep access into a small, well-guarded place. Security improved without stopping the business.
18Frequently Asked Questions
Short answers to questions that beginners often ask.
The standards are the rules: three levels called Privileged, Baseline, and Restricted. The admission controller is the built-in gatekeeper that checks pods against those rules, according to labels on the namespace.
It was deprecated and then removed in Kubernetes version 1.25. Pod Security Admission is its built-in, simpler replacement. Teams needing more custom rules use policy engines or validating admission policies alongside it.
Use Privileged only for trusted system components. Use Baseline as a sensible default for ordinary applications. Use Restricted for sensitive or public-facing workloads, and aim to move more namespaces there over time.
Enforcement happens at pod creation. The Deployment is saved, but its pods are refused. Look at the events on the ReplicaSet to find the reason.
No. Existing pods keep running. The new level only affects pods that are created or updated later. Restart workloads to bring them under the new rules.
Use warn and audit modes first, then apply the enforce label with a server-side dry run, which reports which existing pods would fail without changing anything.
Pinning gives predictable behaviour across upgrades but needs occasional updating. Latest keeps up with the newest definition but may change results after an upgrade. Many teams pin in production and use latest in test.
No. It offers only the three fixed levels. For custom rules, use validating admission policies or a policy engine, which can run alongside it.
It greatly reduces one kind of risk, but it does not cover image flaws, network paths, permissions, secrets, or run-time attacks. Use it as one layer among several.
They often need Privileged access. Keep them in dedicated system namespaces at the Privileged level, managed only by administrators, and keep ordinary applications elsewhere.
Only cluster administrators. Use RBAC to prevent developers from editing namespaces, keep labels in version control, and alert on changes.
Set warn and audit at Baseline for all application namespaces, review the results, fix the workloads, then enforce Baseline. After that, repeat the process for Restricted on your most sensitive namespaces.
19Summary and Key Takeaways
A last look at the whole picture, in plain words.
A Kubernetes cluster is a shared building, and pods are its tenants. Because containers share the machine’s kernel, a pod with too much power can harm every other tenant. Pod Security Standards are the house rules that say how much power a pod may have, and they come in three levels: Privileged for trusted system parts, Baseline for ordinary applications, and Restricted for hardened workloads.
Pod Security Admission is the built-in gatekeeper that checks pods against those levels. You choose a level and a mode for each namespace using labels. Enforce refuses, audit records, and warn tells the person straight away. A gentle rollout uses audit and warn first, fixes workloads, tests with a dry run, and only then enforces.
The standards are simple and strong, but they are not everything. Guard the labels with RBAC, keep exemptions few, and combine the standards with image scanning, network rules, careful permissions, and run-time monitoring. Watch the warnings and audit notes, and keep raising the bar step by step.
Key Takeaways
- Containers share a kernel — a pod with too much power can escape its box, so limit what every pod may ask for.
- Three levels fit three needs — Privileged for trusted system parts, Baseline as a sensible default, Restricted for hardened and sensitive workloads.
- Labels drive the gatekeeper — enforce, audit, and warn modes are set per namespace, and each can use a different level and a pinned version.
- Roll out in stages — start with warn and audit, fix workloads, dry-run the enforce label, then enforce and aim for the next level.
- Enforcement happens at pod creation — a Deployment may be saved while its pods are refused, so read the events on the ReplicaSet, and remember that running pods are not evicted.
- Protect the rules themselves — limit who can edit namespace labels, keep exemptions tiny and reviewed, and alert on label changes.
- The standards are one layer — combine them with image scanning, network policies, RBAC, secrets care, and run-time detection for real defence in depth.