DevOps: Enforce Pod Security Standards With CI and AI Checks
DevOps steps to roll out Kubernetes pod security standards safely. CI- and AI-assisted checks, dry-run tests, and a staged audit-to-enforce path.
Pod Security Standards are the three Kubernetes-defined profiles, Privileged, Baseline, and Restricted, enforced through the built-in Pod Security Admission controller. PSA is validating only, non-mutating, and has been generally available since Kubernetes v1.25. Our recommended starting move: turn on audit and warn first, watch what breaks, then enforce per namespace once you trust the results.
TL;DR:
- Most workloads should be migrated gradually from the Privileged profile to Baseline and then to Restricted, focusing on high-risk and externally-facing applications.
- Setting audit and warn policies before enforcement helps identify non-compliant workloads and reduces deployment failures.
- Key controls to inspect include seccomp profiles, capabilities, runAsNonRoot, readOnlyRootFilesystem, volume types, and sysctls, with dropping all capabilities and avoiding Unconfined profiles as priorities.
- PSA only validates against fixed profiles and does not mutate pods, necessitating additional tools like Webhooks or policy engines for comprehensive mutation and customization.
- A thorough migration often involves auditing current PSPs, mapping their fields to Pod Security Standards, and testing policies in non-production environments for smooth enforcement.
Table of Contents
- What Privileged, Baseline, and Restricted Actually Allow
- How Pod Security Admission Applies These Profiles
- Migrating From PodSecurityPolicy to Pod Security Admission
- Commands and Manifests to Test PSS Safely
- Checklist of Controls to Set or Inspect
- Where PSS Falls Short and When to Add a Policy Engine
- Patterns We Use for CI-Gated Pod Security
- Getting the Rollout Order Right
- How We Can Help You Roll This Out Faster
- FAQ
- Sources
What Privileged, Baseline, and Restricted Actually Allow
Each profile is a different line in the sand, and picking the right one per namespace matters more than picking the strictest one everywhere. We have watched teams enforce Restricted cluster-wide on day one and spend the next two weeks debugging legitimate workloads that simply needed a node-level agent.
Privileged is the profile with effectively no restrictions. It exists for system-level and infrastructure workloads, things like CNI plugins, storage drivers, or monitoring agents that genuinely need host access. Treat it as an exception namespace, not a default.
Baseline blocks the privilege escalations security teams actually worry about, while staying permissive enough for most everyday application pods. It is the sensible floor for namespaces running typical business logic.
Restricted is where the real hardening lives. According to the Kubernetes Pod Security Standards, this profile requires runAsNonRoot, mandates dropping all Linux capabilities, and forbids the Unconfined seccomp profile. It is built for workloads handling sensitive data or exposed to untrusted input.
A few operational points worth internalizing before you start labeling namespaces:
- Privileged suits infrastructure and system daemons, never general application traffic.
- Baseline fits most business applications without requiring a rewrite of existing manifests.
- Restricted is appropriate for high-risk or externally-facing workloads where the blast radius of a compromise matters most.
- Some Restricted controls are operating-system specific and only apply when
pod.spec.os.nameis not set towindows, so mixed-OS clusters need a bit of extra care when mapping policy to node pools.
The profile choice is not permanent. Many teams start a namespace at Baseline, run it there for a few release cycles, then graduate it to Restricted once they have confirmed nothing depends on root access or extra capabilities. That staged approach costs little and avoids the all-or-nothing trap.
How Pod Security Admission Applies These Profiles
PSA reads namespace labels, not cluster-wide flags, which means the profile you want lives right on the namespace object. Three label keys do the work: pod-security.kubernetes.io/enforce, pod-security.kubernetes.io/audit, and pod-security.kubernetes.io/warn. Each accepts a profile name, and you can optionally pin a Kubernetes minor version so the policy definition does not shift under you on upgrade.
The enforcement best practices from Kubernetes are explicit that audit and warn should go on before enforce ever does, and that the two are independent switches. Set warn without audit and you get developer-facing messages but no server-side record. Set audit without warn and you get a paper trail nobody sees until they go looking for it. You need both to close the visibility gap.
A workable rollout sequence looks like this:
- Label the namespace with
auditandwarnset to your target profile, leavingenforceunset or at Privileged. - Run normal traffic for a defined soak period and collect audit log entries.
- Fix any workloads the audit and warn output flags as non-compliant.
- Flip
enforceto the target profile once violations drop to zero.
| Label key | Purpose | Typical starting value |
|---|---|---|
| Kubernetes | Blocks non-compliant pods | privileged (then raised later) |
| Kubernetes | Logs violations without blocking | baseline or restricted |
| pod-security.kubernetes.io/warn | Shows kubectl warnings to users | baseline or restricted |
Cluster-level defaults can also be set through the API server’s admission configuration file, though the exact apiVersion varies by release, with pod-security.admission.config.k8s.io/v1 used in v1.25. System namespaces like kube-system are commonly exempted from enforcement since they run infrastructure pods that need Privileged-level access. If you are running an older API version, confirm the admission config schema matches before you copy an example from current docs, since field names have moved between releases.
For a deeper look at how admission control ties into broader cluster security, our overview of pod security and admission control walks through the mechanics in more detail.
Migrating From PodSecurityPolicy to Pod Security Admission
PodSecurityPolicy is deprecated, and the migration path is mechanical but unforgiving if you skip steps. The official migration guide lays out the core problem clearly: PSP could mutate pod specs to make them compliant, and PSA cannot. Anything your PSPs were silently fixing for you will now simply fail enforcement.

Before you touch the PSA labels, map every PSP field in use to its PSS equivalent and flag the fields PSS has no opinion on at all, things like host path allowlists or specific volume plugin restrictions that PSP controlled but PSS does not address. Those gaps need a different tool, which we cover in the limitations section below.
A migration sequence that has held up for us across several clusters:
- Inventory active PSPs and the fields each one sets, separating mutating fields from purely validating ones.
- Remove or neutralize mutating behavior first, updating manifests so they already comply with the target PSS profile without help.
- Clone your current policy behavior into PSS labels on a non-production namespace and dry-run deployments against it.
- Move to audit and warn mode cluster-wide, watching logs for workloads still relying on now-removed mutation.
- Only then disable PSPs and switch affected namespaces to enforce.
Running kubectl apply --dry-run=server against representative manifests before changing any label catches most surprises early. Teams that skip the “clone offline” step tend to discover their mutation dependency in production, which is a far more expensive place to learn it.
Commands and Manifests to Test PSS Safely
Testing PSS on a live cluster does not require a maintenance window if you sequence it correctly. Start with labels only, verify behavior, then tighten.
- Label a target namespace for audit and warn without enforcing:
kubectl label --overwrite ns my-namespace pod-security.kubernetes.io/audit=restricted pod-security.kubernetes.io/warn=restricted. - Pin the version alongside the profile if you want stability across upgrades, for example
pod-security.kubernetes.io/audit-version=latest. - Submit a representative manifest with
kubectl apply --dry-run=server -f pod.yamland read the returned warnings directly in your terminal. - Check the audit log or your log aggregator for
pod-security.kubernetes.io/audit-violationsannotations, which record what would have been blocked. - List namespaces missing any PSS labels with
kubectl get ns -o json | jq '.items[] | select(.metadata.labels["pod-security.kubernetes.io/enforce"] == null)'so nothing slips through unlabeled. - Once audit logs stay clean for your chosen soak window, flip
enforceto match.
Pro Tip: Run audit and warn for at least one full deployment cycle, including your slowest-moving batch jobs, before enforcing. Fast-moving services will look compliant in a day; the one cron job that runs monthly is what bites you later.
Warn messages show up to whoever runs kubectl apply, which is useful for catching issues during development, but audit annotations are what you want for a permanent record across a team that may not read terminal output closely.
Checklist of Controls to Set or Inspect
Most PSS failures trace back to a short, repeatable list of manifest fields. Reviewing these before enforcement saves far more time than debugging after a blocked deployment.
- Set
seccompProfile.typetoRuntimeDefaultor a namedLocalhostprofile;Unconfinedis explicitly forbidden under Restricted. - Drop
ALLcapabilities insecurityContext.capabilities.drop, adding back onlyNET_BIND_SERVICEwhen a workload genuinely needs to bind a privileged port. - Set
runAsNonRoot: trueand definereadOnlyRootFilesystem: truewherever the application supports it. - Pin
procMountto the default value rather thanUnmasked. - Restrict volume types to the approved set and avoid
hostNetwork,hostPID, orhostPortunless the workload is explicitly exempted as infrastructure. - Limit
sysctlsto the documented safe list rather than allowing arbitrary kernel parameter overrides.
The Restricted profile requires dropping all capabilities and forbids the Unconfined seccomp profile, two of the most commonly missed fields when teams migrate existing workloads, according to the Kubernetes Pod Security Standards documentation. Baking these checks into CI, rather than catching them at admission time, turns a blocked deployment into a quick pull request comment instead.
Where PSS Falls Short and When to Add a Policy Engine
PSA is deliberately narrow. It validates against three fixed profiles and cannot mutate a pod spec to fix it, so any workload that depended on PodSecurityPolicy quietly injecting defaults needs either a manifest rewrite or a Mutating Admission Webhook to do that work going forward.
- PSA has no mutation capability, so defaults like forcing
runAsNonRootonto a pod that forgot to set it must come from a webhook, not PSA itself. - The three PSS levels are opinionated and fixed. Fine-grained rules, custom field restrictions, or organization-specific exceptions need a dedicated policy engine.
- Tools like Kyverno, OPA Gatekeeper, or Kubewarden fill that gap, at the cost of added operational complexity and another system to trust and maintain. Our guide to Kyverno admission rules covers how to layer that on top of PSA rather than replace it.
Patterns We Use for CI-Gated Pod Security
Catching violations in a pull request beats catching them at the admission controller, every time. Our typical CI gate runs a manifest linter against the target PSS profile before merge, checks securityContext fields explicitly, and fails the build on any Restricted violation rather than waiting for a cluster rejection.
We have also found AI-assisted manifest review genuinely useful here: a well-structured prompt can flag a missing seccompProfile or an unnecessary capability faster than a human reviewer skimming a long YAML file, which is the workflow we document in our AI manifest auditing guide. Pair that with RBAC rules that limit who can change the PSS labels on a namespace, since a loosened label is a much quieter failure mode than a rejected deployment.
Reading audit logs after the fact tells you what almost went wrong. Gating in CI stops it from becoming an incident in the first place.
— James
Getting the Rollout Order Right
Pod Security Standards are one control among several, not a complete security posture on their own. RBAC, network policy, and runtime security tooling still carry weight PSS was never built to cover, and treating it as the whole job is how gaps get missed.
We would rather see a namespace sit in audit mode for a month longer than see a rushed enforce rollout take down a batch job nobody tested. Slow, observable rollouts beat brittle hardening that looks secure on paper and breaks the first time an edge case shows up.
— James
How We Can Help You Roll This Out Faster
Working through namespace-by-namespace PSS migration on top of everything else on your plate is exactly the kind of work our Kubernetes Health Check was built for: a focused, $300 one-off review that looks at your current admission configuration, flags workloads that will break under Restricted, and hands you a concrete rollout plan instead of a generic audit report.

If your infrastructure spans Terraform-managed clusters too, a Terraform / IaC Audit covers the broader configuration surface as a one-off review, and these reviews are informed by prompt libraries and manifest-checking workflows used in practice.
- Kubernetes Health Check: a one-off review of your PSA configuration and workload readiness.
- Terraform / IaC Audit: a one-off review of the infrastructure code feeding your clusters.
- Hourly consulting available for teams that need hands-on help finishing a migration already in progress.
Book a review through our work-with-me page and we will tell you exactly where your namespaces stand before you flip a single label to enforce.
FAQ
What are the four C’s of Kubernetes security?
The four C’s are a commonly used mental model for layered security: Cloud, Cluster, Container, and Code, working from the infrastructure layer inward to the application itself. Pod Security Standards operate mainly at the Cluster and Container layers, setting rules for how pods can be configured, while code-level and cloud-level controls need separate tooling.
What does “restricted” mean in the context of Pod Security Standards?
Restricted is the strictest of the three Pod Security Standards profiles, and it requires pods to run as a non-root user, drop all Linux capabilities, and avoid the Unconfined seccomp profile, according to the Kubernetes Pod Security Standards. It is intended for workloads handling sensitive data or exposed to untrusted traffic, where a compromised container should have as little leverage as possible.
What is a security pod?
There is no distinct Kubernetes object called a “security pod.” The term usually refers to a regular pod configured under a hardened securityContext, following the Baseline or Restricted Pod Security Standards profile rather than running with default, unrestricted settings.
What are the best security practices for Kubernetes?
Layering controls works better than relying on any single mechanism: apply Pod Security Standards at the namespace level, pair them with network policies and tight RBAC, and keep runtime security monitoring in place for behavior PSS cannot see. Least-privilege thinking extends beyond pod configuration into service accounts and network access, a principle covered well in this explanation of least privilege access.
How do I migrate from PodSecurityPolicy without breaking workloads?
Map each PodSecurityPolicy field to its Pod Security Standards equivalent first, paying close attention to any field PSP used to mutate automatically, since PSA cannot do that. The official migration guide recommends testing with audit and warn mode before enforcing, which gives you a safe window to fix workloads that depended on PSP’s old mutating behavior.
Recommended
- Hardening a Pod securityContext With AI Review
- Pod Security Standards in Practice: Hardening Workloads
- Securing a Kubernetes Cluster: Pod Security and Admission
- Using AI to Harden GitLab CI Security Scanning Pipelines
Get 500 Battle-Tested DevOps AI Prompts — Free
500 battle-tested, copy-paste AI prompts engineered by a senior systems engineer — every one with fill-in placeholders and safety/back-out notes. Drop your email and it's yours.
- 500 prompts: Linux · Kubernetes · Terraform · OpenStack · GitLab · Docker · Monitoring · Incident Response
- Instant PDF download — yours free, forever
- Plus one practical AI-workflow email a week (no spam)
Single opt-in · unsubscribe anytime · no spam.