PRACTITIONER GUIDE | CLOUD SECURITY
Practitioner GuideUpdated 13 min read

Kubernetes Pod Security Standards: Deploying PSA After PSP Removal

1.25
Kubernetes version that permanently removed PodSecurityPolicy, requiring migration to PSA
3
PSS policy levels: Privileged (unrestricted), Baseline (known privilege escalations blocked), Restricted (hardened)
3
PSA enforcement modes per namespace: enforce (reject), audit (log), warn (user warning)
0
RBAC bindings required -- PSA is configured entirely via namespace labels, unlike PSP

SponsoredRetool

Retool's new app builder is where AI-generated code ships safely

Building apps with AI is easy. Getting them to production safely is another story.

Start building for free today

PodSecurityPolicy was removed in Kubernetes 1.25, and many teams running 1.24 or earlier have accumulated clusters with PSP disabled but nothing replacing it -- meaning pods run with whatever security context the developer specified. Pod Security Admission (PSA) with Pod Security Standards (PSS) is the built-in replacement: namespace labels that enforce predefined security profiles at the admission controller level with zero additional components to install. This guide covers the migration path from PSP (or from nothing), how to audit workloads before enabling enforcement, how to handle the namespaces that legitimately need elevated privileges, and how to use OPA Gatekeeper as a supplement when PSA's namespace-level granularity is insufficient.

Understand the Three PSS Profiles Before Applying Any Labels

Applying PSS profiles without auditing workloads first will break production. The three profiles have meaningfully different blast radii.

Privileged: applies no restrictions

The Privileged profile allows all pod security fields -- equivalent to no policy at all. Use it only for namespaces running infrastructure that legitimately requires host-level access: node agents, CNI plugins, CSI drivers, monitoring daemonsets like Falco. Every other namespace should have at minimum Baseline enforced.

Baseline: blocks known privilege escalation paths

Baseline prohibits: privileged containers, privilege escalation (allowPrivilegeEscalation: false required), hostNetwork/hostPID/hostIPC, dangerous capabilities (NET_RAW, SYS_ADMIN, SYS_PTRACE), Seccomp set to Unconfined, and HostPath volumes. Most application containers built from standard images (nginx, postgres, node) meet Baseline without any securityContext changes.

Restricted: hardened configuration for security-sensitive workloads

Restricted adds: runAsNonRoot: true, runAsUser must be nonzero, drop ALL capabilities (re-add only what's needed), seccompProfile must be RuntimeDefault or Localhost (not Unconfined), volumes restricted to approved types only (no hostPath, no NFS without explicit allowance). Expect 30-50% of existing workloads to need securityContext additions before passing Restricted.

Audit Existing Workloads Before Enforcing

Never apply enforce mode without first auditing. Use PSA's built-in audit mode and the kubectl-psa plugin to identify violations without disrupting workloads.

Apply audit labels to all non-system namespaces

Start by labeling all application namespaces with audit mode at the Restricted level: `kubectl label namespace <ns> pod-security.kubernetes.io/audit=restricted pod-security.kubernetes.io/audit-version=latest`. This logs any violations to the Kubernetes audit log without blocking pods. Run workloads normally for 24-48 hours and collect audit events.

Parse audit log for PSS violations

Filter audit logs for `policy.kubernetes.io/audit` events: `kubectl get events -A --field-selector reason=FailedCreate | grep psa`. Each violation event identifies the namespace, workload name, and which specific PSS control was violated. Group violations by type -- allowPrivilegeEscalation violations are simple fixes; HostPath volume violations require architectural changes.

Use kubectl-psa plugin for dry-run checks

Install the psa kubectl plugin via krew: `kubectl krew install psa`. Then check any namespace: `kubectl psa check <namespace> --policy restricted`. This reports exactly which pod specs violate which controls. Use it in CI/CD pipelines to gate deployments: any pod spec that fails `kubectl psa check` at the Restricted level should block the deploy with a clear error message showing which securityContext fields need changing.

Fix violations systematically by control type

Batch similar violations: all pods missing `allowPrivilegeEscalation: false` get a securityContext patch. All pods missing `runAsNonRoot: true` need to be verified to use a non-root USER in their Dockerfile -- simply adding the field without fixing the Dockerfile will cause runtime failures. All pods needing `seccompProfile: RuntimeDefault` just need the annotation added; no application change required.

Free daily briefing

Briefings like this, every morning before 9am.

Threat intel, active CVEs, and campaign alerts, distilled for practitioners. 50,000+ subscribers. No noise.

Apply PSA Labels to Namespaces

Once violations are remediated, apply PSA labels progressively from warn to enforce.

Start with warn mode to catch remaining issues

After fixing audit violations, add warn mode at Restricted: `kubectl label namespace <ns> pod-security.kubernetes.io/warn=restricted pod-security.kubernetes.io/warn-version=latest`. Warn mode returns warnings to kubectl and CI/CD tools on violating apply commands but does not block them. This catches any violations your audit analysis missed and gives developers visibility into problems before enforcement.

Enforce Baseline across all application namespaces first

The safer first enforcement step is Baseline, not Restricted. Apply enforce=baseline to all application namespaces: `kubectl label namespace <ns> pod-security.kubernetes.io/enforce=baseline`. Baseline blocks the highest-risk security contexts (privileged containers, host namespace sharing) with low false-positive risk. The operational disruption is minimal for well-built application containers.

Escalate to Restricted for sensitive workloads

Apply enforce=restricted to namespaces running externally-exposed or security-sensitive workloads after validating workload compliance. For namespaces that cannot be made Restricted without application changes, keep them at Baseline and create a backlog item for the owning team to remediate. Document Baseline exceptions with justification -- many security frameworks accept Baseline as compliant with additional compensating controls.

Label system and infrastructure namespaces explicitly

PSA exempts kube-system by default, but explicitly label other infrastructure namespaces to make the policy visible: `kubectl label namespace kube-system pod-security.kubernetes.io/enforce=privileged`. Explicit labels prevent ambiguity during audits and ensure that if PSA defaults change in future Kubernetes versions, your intentional Privileged exemptions remain in place.

Supplement PSA with OPA Gatekeeper for Per-Workload Exceptions

PSA enforces at the namespace level only. When you need per-workload policy exceptions or custom controls not covered by PSS profiles, OPA Gatekeeper is the appropriate complement.

Install Gatekeeper alongside PSA

OPA Gatekeeper and PSA can coexist in the same cluster. PSA handles namespace-level baseline enforcement; Gatekeeper handles workload-specific policies and custom controls. Install Gatekeeper via Helm: `helm install gatekeeper gatekeeper/gatekeeper --namespace gatekeeper-system`. The two admission controllers run independently -- a pod must pass both to be admitted.

Write ConstraintTemplates for custom policies

Use Gatekeeper ConstraintTemplates (Rego) to enforce policies PSA cannot express: require specific image registries, enforce image digest pinning (no :latest tags), require resource limits on all containers, or block specific environment variable names that suggest credential injection. These are separate from PSS and give you fine-grained workload controls that PSA's three-tier model cannot provide.

The bottom line

Pod Security Standards with PSA is a significant improvement over PSP: no RBAC binding complexity, no webhook to maintain, just namespace labels. The risk is that it is easy to apply labels without auditing workloads first and break production. Audit with the psa plugin and PSA audit mode before any enforce label goes on. Start with Baseline enforcement everywhere, escalate specific namespaces to Restricted, and keep a documented exception registry for the infrastructure namespaces that legitimately need Privileged.

Frequently asked questions

What replaced PodSecurityPolicy in Kubernetes?

PodSecurityPolicy (PSP) was deprecated in Kubernetes 1.21 and removed in 1.25. It was replaced by Pod Security Admission (PSA), which enforces the predefined Pod Security Standards (PSS) via namespace labels. Third-party alternatives include OPA Gatekeeper and Kyverno, which offer more granular policy control than PSA but require additional installation. For most clusters, PSA with PSS profiles is sufficient and has no additional components to manage.

What is the difference between Baseline and Restricted pod security profiles?

Baseline blocks known privilege escalation paths while allowing most legitimate container workloads: it prohibits privileged containers, host namespace sharing (hostPID, hostIPC, hostNetwork), dangerous capabilities (NET_RAW, SYS_ADMIN), and HostPath volumes. Restricted enforces everything in Baseline plus: requires non-root user (runAsNonRoot: true), drops ALL Linux capabilities (only specific ones can be added back), requires read-only root filesystem or seccompProfile, and requires runAsGroup to be nonzero. Most application workloads can meet Baseline; some require config changes to meet Restricted.

How do you handle system namespaces like kube-system with PSA?

System namespaces (kube-system, kube-public, kube-node-lease) run Kubernetes control plane components that require privileged access. Do not apply Baseline or Restricted policies to these namespaces. By default PSA exempts the kube-system namespace from enforcement. For other infrastructure namespaces (monitoring, ingress-nginx, cert-manager), assess each workload's actual security context requirements before applying any PSS profile -- many infrastructure components legitimately need elevated permissions.

Can you apply different enforcement modes simultaneously?

Yes. A namespace can have up to three labels simultaneously: enforce (hard block at admission), audit (allow but log policy violations to audit log), and warn (allow but return a warning to the user/kubectl). The recommended migration strategy is to start with audit mode to discover violations without breaking workloads, then add warn mode, then switch to enforce once violations are resolved. Each mode can reference a different policy level or version.

How do you allow a specific deployment to run privileged in a Restricted namespace?

PSA works at the namespace level only -- there is no per-workload exception mechanism in PSA itself. Options: (1) Move privileged workloads to a separate namespace with Privileged or Baseline policy. (2) Use OPA Gatekeeper or Kyverno instead of PSA for that namespace, which support per-workload exclusions. (3) Accept the Baseline profile for the namespace if the workload only needs a subset of privileges blocked by Restricted. Avoid putting privileged and untrusted workloads in the same namespace.

What does the version field in PSA labels do?

PSA labels accept an optional version field (e.g., `pod-security.kubernetes.io/enforce-version: v1.28`) that pins the policy to the PSS specification for a specific Kubernetes version. Without a version, the policy defaults to 'latest,' which means it updates automatically as Kubernetes adds new controls. Pinning to a specific version prevents surprise admission rejections when upgrading Kubernetes. AWS EKS, GKE, and AKS enforce PSS policies tied to their supported Kubernetes versions.

How do you audit existing workloads before enabling PSA enforcement?

Use `kubectl label namespace <ns> pod-security.kubernetes.io/audit=restricted` without an enforce label, then watch the Kubernetes audit log for policy.kubernetes.io/audit events. The `kubectl-psa` plugin (available via krew) can simulate PSS policy evaluation against existing workloads: `kubectl psa check --namespace <ns>`. Run this before adding the enforce label to identify which deployments need securityContext changes. Fix violations iteratively before switching from audit to enforce mode.

Sources & references

  1. Kubernetes Pod Security Standards Documentation
  2. Pod Security Admission Documentation
  3. Migrating from PSP to PSA

Free resources

25
Free download

Critical CVE Reference Card 2025–2026

25 actively exploited vulnerabilities with CVSS scores, exploit status, and patch availability. Print it, pin it, share it with your SOC team.

No spam. Unsubscribe anytime.

Free download

Ransomware Incident Response Playbook

Step-by-step 24-hour IR checklist covering detection, containment, eradication, and recovery. Built for SOC teams, IR leads, and CISOs.

No spam. Unsubscribe anytime.

Free newsletter

Get threat intel before your inbox does.

50,000+ security professionals read Decryption Digest for early warnings on zero-days, ransomware, and nation-state campaigns. Free, daily, no spam.

Unsubscribe anytime. We never sell your data.

Eric Bang
Author

Founder & Cybersecurity Evangelist, Decryption Digest

Cybersecurity professional with expertise in threat intelligence, vulnerability research, and enterprise security. Covers zero-days, ransomware, and nation-state operations for 50,000+ security professionals every morning.

Black Hat Giveaway

Win a $2,495 Black Hat pass.

Full-access to Black Hat USA 2026 in Las Vegas. Subscribe free to enter.

Joins Decryption Digest daily briefing. Unsubscribe anytime.

Giveaway: Black Hat USA 2026 Full-Access Pass ($2,495 value)

Details →
Daily Briefing

Subscribe to enter the giveaway

Every subscriber is automatically entered. You also get daily threat intel every morning: zero-days, ransomware, and nation-state campaigns. Free. No spam.

Already subscribed? You're already entered.

Giveaway

Win a $2,495 Black Hat USA 2026 pass.