Kubernetes Pod Security Standards: Deploying PSA After PSP Removal

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.
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.
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
Free resources
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.
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.
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.

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.
Win a $2,495 Black Hat pass.
Full-access to Black Hat USA 2026 in Las Vegas. Subscribe free to enter.
