Blog

Kubernetes Pod Security: Standards, Admission and securityContext

A practical guide to Kubernetes Pod Security: the Pod Security Standards, Pod Security Admission, and the securityContext settings that keep pods locked down.

Bruno Baldo·Sep 14, 2026·9 min read·Reviewed by Rainforest Technologies

Kubernetes Pod Security is the discipline of constraining what individual pods are allowed to do, so that a foothold inside one container does not hand an attacker the whole node. It is the layer where most real-world cluster hardening either happens or quietly fails to happen — and since the removal of PodSecurityPolicy, it is built on three moving parts you need to understand together: the Pod Security Standards, Pod Security Admission, and the pod-level securityContext. This guide walks through all three, shows the settings that matter, and explains how to adopt them without breaking the workloads you already run.

This article is part of our Kubernetes security cluster. If you have not already locked down access and traffic, pair it with our guides on Kubernetes RBAC and Kubernetes network policies.

Why pod-level security matters

Containers share a kernel. That single sentence explains why pod security carries so much weight. Unlike virtual machines, containers on the same node are isolated by kernel primitives — namespaces, cgroups, capabilities, seccomp — rather than by a hypervisor boundary. When a pod is granted more privilege than it needs, you are widening the blast radius of any bug in your application or its dependencies.

The classic failure chain looks like this: an attacker exploits a vulnerability in a web-facing service and gets code execution inside the container. If that container runs as root, has extra Linux capabilities, or mounts a host path, the escape from container to node is often trivial. From the node, an attacker can read every other pod's secrets, tamper with the kubelet, or pivot across the cluster. A container escape, in other words, is frequently a node compromise — and a node compromise is a very short walk from a cluster compromise.

Pod security is how you make that walk long and difficult. The goal is not to trust your application code less; it is to assume it will eventually be compromised and to ensure that the compromise stays boxed in.

From PodSecurityPolicy to Pod Security Standards

For years, the answer to pod hardening was PodSecurityPolicy (PSP) — a cluster-scoped resource that gated pod creation against a set of rules. PSP was powerful but notoriously awkward: its authorization model was confusing, ordering between multiple policies was non-obvious, and it was easy to lock yourself (or your workloads) out.

PSP was deprecated in Kubernetes 1.21 and removed entirely in 1.25. If you still have PSP objects lying around, they do nothing on modern clusters. The replacement is deliberately simpler and split into two concepts: a set of standard profiles (the Pod Security Standards) and a built-in enforcement mechanism (Pod Security Admission). The Standards describe what good looks like; Admission decides whether to allow, warn, or audit a pod against a chosen Standard.

The three Pod Security Standards levels

The Pod Security Standards define three cumulative levels, from most permissive to most locked down:

  • Privileged — essentially unrestricted. This level allows known privilege escalations and is intended for trusted, infrastructure-style workloads (think system components or a CNI plugin) that genuinely need broad access. Application namespaces should almost never run here.
  • Baseline — a minimally restrictive profile that blocks the most obvious and dangerous escalations while staying easy to adopt. It forbids things like host namespaces, privileged containers, and hostPath volumes, but still permits running as root. Baseline is a sensible floor for most application namespaces.
  • Restricted — the hardened profile. It enforces current pod-hardening best practices: running as non-root, dropping all capabilities, disabling privilege escalation, and requiring a seccomp profile, among others. This is the target for anything handling sensitive data or exposed to untrusted input.

The mental model is a ladder: everything blocked by baseline is also blocked by restricted, plus a lot more. You pick the highest level a workload can tolerate.

How Pod Security Admission enforces per namespace

Pod Security Admission (PSA) is the admission controller — enabled by default in current Kubernetes — that applies a chosen Standard to a namespace. You configure it not with a policy object but with labels on the namespace itself. There are three modes:

  • `enforce` — pods that violate the level are rejected at creation time.
  • `audit` — violations are allowed but recorded in the audit log.
  • `warn` — violations are allowed but return a warning to the user who created the pod.

Each mode takes a level (privileged, baseline, or restricted) and, optionally, a pinned version. A namespace can carry all three at once, which is exactly how you adopt safely — warn and audit at restricted while only enforcing baseline, for example.

apiVersion: v1

kind: Namespace

metadata:

  name: payments

  labels:

    pod-security.kubernetes.io/enforce: baseline

    pod-security.kubernetes.io/enforce-version: latest

    pod-security.kubernetes.io/audit: restricted

    pod-security.kubernetes.io/warn: restricted

That single set of labels blocks the worst behaviors immediately (enforce: baseline) while telling you, for every deploy, exactly what you would need to fix to reach restricted. Note that PSA works at the namespace granularity — there is no per-pod exemption inside an enforced namespace, so design your namespace layout with security tiers in mind.

The securityContext settings that actually harden a pod

The Standards and Admission decide which rules apply. The securityContext is where you write the rules into your manifests. These are the settings that carry the most weight:

spec:

  securityContext:

    runAsNonRoot: true

    seccompProfile:

      type: RuntimeDefault

  containers:

    - name: app

      image: registry.example.com/app:1.4.2

      securityContext:

        allowPrivilegeEscalation: false

        readOnlyRootFilesystem: true

        privileged: false

        capabilities:

          drop: ["ALL"]

  • `runAsNonRoot: true` (and a concrete runAsUser) stops the container from running as UID 0. This alone defeats a large class of escapes.
  • `allowPrivilegeEscalation: false` prevents a process from gaining more privileges than its parent — for example via setuid binaries.
  • `readOnlyRootFilesystem: true` makes the container's root filesystem immutable, so an attacker cannot drop a payload or modify binaries. Mount an emptyDir for the few paths that genuinely need to be writable.
  • `capabilities.drop: ["ALL"]` strips every Linux capability and forces you to add back only what you truly need (rarely anything).
  • `seccompProfile.type: RuntimeDefault` applies the container runtime's default seccomp filter, blocking dangerous syscalls.
  • `privileged: false` — a privileged container is effectively root on the node. There is almost never a good reason for an application to run privileged.

Equally important are the things you should not set. Avoid `hostNetwork`, `hostPID`, and `hostIPC`, which break the isolation between the pod and the node. Avoid `hostPath` volumes, which mount node directories straight into the pod. These are precisely the behaviors the baseline and restricted levels exist to block.

Resource limits are part of pod security

Security is not only about privilege — availability counts too. A pod with no limits can consume all the CPU or memory on a node and starve its neighbors, which is a denial-of-service condition whether it happens by accident or by malice. Always set requests and limits:

resources:

  requests:

    cpu: "100m"

    memory: "128Mi"

  limits:

    cpu: "500m"

    memory: "256Mi"

Pair these with a LimitRange and ResourceQuota per namespace so that even forgotten workloads inherit sane bounds.

When you need an admission controller beyond PSA

Pod Security Admission is intentionally scoped: it enforces the three Standards and nothing else. That covers a great deal, but it cannot express organization-specific rules. PSA cannot, for example, require that images come only from your registry, mandate a particular label, forbid the latest tag, or block a specific mount path while allowing others.

When you need that kind of custom policy, you reach for a general-purpose policy engine that plugs into Kubernetes as a validating admission webhook. Policy-as-code engines let you write rules in a dedicated policy language, test them, and version them alongside the rest of your infrastructure. The pattern is to let PSA handle the standard baseline/restricted enforcement and layer a policy engine on top for everything unique to your environment. Keep the two complementary rather than duplicating the Standards in custom policy.

Rolling it out without breaking your workloads

The fastest way to lose your team's trust is to flip a namespace to enforce: restricted and watch half the deployments fail. Adopt in stages instead:

  1. Observe first. Add warn: restricted and audit: restricted labels to a namespace without any enforce label. Nothing breaks; you simply collect a list of every violation your workloads currently trigger.
  2. Fix the manifests. Work through the warnings, adding the securityContext fields above. Most fixes are small and mechanical.
  3. Enforce the floor. Once workloads are clean, set enforce: baseline, then raise it to enforce: restricted for the namespaces that can take it.
  4. Default new namespaces. Configure a cluster-wide default so that new namespaces start at least at baseline rather than wide open.

This audit-first approach means the enforcement switch is a formality by the time you throw it — the workloads already comply.

Shift left: scan manifests in CI

Everything above happens at the cluster boundary. The cheaper place to catch a misconfigured pod is long before it ever reaches a cluster — in the pull request that introduces it. Manifests, Helm charts, and Kustomize overlays are code, and they can be scanned like code.

Wiring pod-security checks into CI means a manifest that runs as root, mounts a hostPath, or forgets resource limits fails the build with a clear message pointing at the offending line. Developers get feedback in seconds, in the tool they already use, instead of discovering the problem when a deploy is rejected — or worse, when it is not. This is the same shift-left principle we apply across the rest of the Kubernetes security lifecycle.

How Rainforest helps

Rainforest brings pod-security enforcement into the developer workflow rather than bolting it on at the end. Our infrastructure-as-code scanning analyzes your Kubernetes manifests, Helm charts, and Terraform for exactly the issues this article covers — containers running as root, missing securityContext fields, host namespaces, privileged flags, and absent resource limits — and surfaces them directly in pull requests. Our container security scanning extends that coverage to the images those pods run, so a hardened pod spec is not undermined by a vulnerable base image.

The result is one consistent picture: policy checks in CI that mirror what Pod Security Admission will enforce in the cluster, so misconfigurations are caught while they are still a code change and not yet an incident.

If you want to see how that fits your pipeline, book a demo and we will walk through your own manifests.

Frequently asked questions

What are Kubernetes Pod Security Standards?

The Pod Security Standards are three predefined security profiles — privileged, baseline, and restricted — maintained as part of Kubernetes. They describe a graduated set of restrictions on what a pod is allowed to do, from unrestricted (privileged) through a sensible default (baseline) to a fully hardened profile (restricted). They are definitions, not an enforcement mechanism on their own.

What replaced PodSecurityPolicy?

PodSecurityPolicy (PSP) was deprecated in Kubernetes 1.21 and removed in 1.25. It was replaced by the combination of the Pod Security Standards (the profiles) and Pod Security Admission (the built-in controller that enforces those profiles per namespace). For rules that go beyond the Standards, teams use a general-purpose policy-as-code admission controller.

What is Pod Security Admission?

Pod Security Admission (PSA) is the admission controller, enabled by default in current Kubernetes versions, that applies a chosen Pod Security Standard to a namespace. You configure it with namespace labels in three modes — enforce (reject violations), audit (log them), and warn (warn the user) — each set to a level such as baseline or restricted.

What is a securityContext?

A securityContext is a section of a pod or container spec that defines its security settings — such as runAsNonRoot, allowPrivilegeEscalation, readOnlyRootFilesystem, dropped capabilities, and the seccomp profile. It is where the actual hardening of a pod is written, and it is what the Pod Security Standards evaluate.

What is the difference between baseline and restricted?

Baseline is a minimally restrictive profile that blocks the most dangerous escalations — privileged containers, host namespaces, hostPath volumes — while still allowing pods to run as root. Restricted is the hardened profile that additionally requires running as non-root, dropping all capabilities, disabling privilege escalation, and applying a seccomp profile. Restricted is a strict superset of baseline.

Bruno Baldo

Written by

Bruno Baldo

CMO

Um pouco de marketing e um pouco de curiosidade e temos a receita pra criar um apaixonado por cyber!

Keep reading