Kubernetes Pod Security Standards: Real-World Implementation, Pitfalls, and Best Practices
What Are Kubernetes Pod Security Standards?
Kubernetes Pod Security Standards (PSS) are a set of built-in, versioned security profiles that define how workloads can interact with the host and the cluster. These standards help administrators control what actions pods can perform, providing a practical baseline for enforcing security controls. PSS replaces the deprecated PodSecurityPolicy (PSP) mechanism as of Kubernetes v1.25, simplifying the approach to workload security.
There are three main Pod Security Standards, each offering a different level of restriction:
- Privileged: No restrictions. Pods can do anything the node allows, including accessing the host’s resources and running as root. This profile is not recommended for most workloads, but may be required for some infrastructure-level components such as network plugins or storage daemons.
- Baseline: Blocks known privilege escalation vectors but is flexible enough for most application workloads. This profile disallows privileged containers, restricts certain host features, but still allows some use of host networking and ports. It aims to balance security with application compatibility.
- Restricted: Enforces the strictest controls. This profile blocks privileged containers, running as root, use of host network and namespaces, and mandates dropping most Linux capabilities. It is required for highly sensitive or multi-tenant clusters, as well as compliance-focused environments.
PodSecurityAdmission (PSA) is the controller that enforces these standards. It operates by reading labels on namespaces and applying the corresponding security controls to all pods within that namespace. Depending on the configuration, PSA can audit (log violations), warn (notify but allow), or enforce (block non-compliant pods).
# Example pod with strict security context for 'restricted'
apiVersion: v1
kind: Pod
metadata:
name: compliance-app
spec:
containers:
- name: main
image: registry.company.com/compliance:2.1
securityContext:
runAsNonRoot: true
runAsUser: 1001
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
seccompProfile:
type: RuntimeDefault
In this example, the pod will pass the restricted profile because it avoids running as root (runAsNonRoot: true), assigns a specific non-root user (runAsUser: 1001), prohibits privilege escalation (allowPrivilegeEscalation: false), drops all Linux capabilities, and applies the default seccomp profile for syscall filtering. These are all requirements for compliance with the restricted standard, and represent what production security teams should aim for unless a strong use case demands otherwise.
Key concept explanations:
- Privilege escalation: The ability for a process running in a container to gain increased privileges, potentially compromising the host or cluster.
- Linux capabilities: Fine-grained permissions that can be added or removed from a process, allowing more granular control over what the process can do.
- Seccomp profile: A security mechanism for limiting the system calls that a container can make, reducing the attack surface.
Understanding these standards is essential before enforcement. Next, let’s look at how to apply and manage these standards in your cluster.
Enforcing Pod Security Standards with PodSecurityAdmission
As of Kubernetes 1.25, PodSecurityAdmission (PSA) is the default method to apply Pod Security Standards. PSA is a built-in admission controller that evaluates pods at creation time, determining whether they meet the specified security requirements. Unlike previous mechanisms, you do not need to install extra webhook configurations or third-party controllers; enforcement is as simple as labeling your namespaces.
# Enforce 'restricted' profile for all pods in the 'prod-secure' namespace
kubectl label namespace prod-secure pod-security.kubernetes.io/enforce=restricted
kubectl label namespace prod-secure pod-security.kubernetes.io/enforce-version=latest
# Audit violations in the 'staging' namespace without blocking pods
kubectl label namespace staging pod-security.kubernetes.io/audit=restricted
# Warn users about violations in the 'dev' namespace, but allow pods
kubectl label namespace dev pod-security.kubernetes.io/warn=restricted
Namespace labels control the policy in three modes:
- enforce: Violating pods are rejected and not admitted to the namespace.
- warn: Pods are still accepted, but the user receives a warning message indicating a violation.
- audit: Violations are only logged for auditing purposes; pods are not blocked or warned.
For example, you might begin by labeling your development namespaces with warn or audit to observe which workloads would be blocked, without disrupting your teams. Once all pods are compliant, you can switch to enforce mode for production.
Practical scenario: Suppose you have a legacy application in the staging namespace. By labeling this namespace with audit=restricted, you can see which pods would violate the restricted policy, review the audit logs, and plan the necessary changes before moving to enforcement.
For the latest Kubernetes documentation on PSA, see Pod Security Admission – Kubernetes.io.
Now that you know how enforcement works, let’s examine how different pod specifications interact with these standards and what to expect in real-world usage.
Real-World Examples of Pod Security Standards
Below are practical manifests and their behavior under different Pod Security Standards. These are based on real scenarios you’ll face migrating from PSP, onboarding new teams, or dealing with legacy images.
Example 1: Legacy App with Privileged Container
apiVersion: v1
kind: Pod
metadata:
name: legacy-priv
spec:
containers:
- name: sysadmin
image: internal/legacy-admin:latest
securityContext:
privileged: true
runAsUser: 0
What happens? In a namespace with enforce=baseline or enforce=restricted, this pod is rejected:
Error from server (Forbidden): pod violates pod security policy: privileged containers are not allowed
Explanation: The privileged: true setting grants the container full access to the host, and runAsUser: 0 means it runs as the root user. Both are explicitly forbidden by baseline and restricted standards. Only namespaces with enforce=privileged permit this configuration.
Practical guidance: If you must run legacy workloads that require privileged access, isolate them in dedicated namespaces and apply strict access controls. Avoid this model for third-party or untrusted workloads.
Example 2: Typical Microservice with Baseline Security
apiVersion: v1
kind: Pod
metadata:
name: webapp
spec:
containers:
- name: flaskapi
image: registry.company.com/flaskapi:3.2
ports:
- containerPort: 8080
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
What happens? This pod will pass baseline enforcement because it disables privilege escalation and drops all extra Linux capabilities. However, restricted requires explicit non-root execution settings (runAsNonRoot: true and runAsUser), which are absent here. To pass restricted, you must add these fields.
Example improvement:
securityContext:
allowPrivilegeEscalation: false
runAsNonRoot: true
runAsUser: 1000
capabilities:
drop:
- ALL
This highlights why reviewing and updating manifests is essential when tightening security standards.
Example 3: Compliant Pod for Restricted Policy
apiVersion: v1
kind: Pod
metadata:
name: secure-api
spec:
containers:
- name: api
image: registry.company.com/secure-api:1.0
securityContext:
runAsNonRoot: true
runAsUser: 1000
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop:
- ALL
seccompProfile:
type: RuntimeDefault
What happens? This pod will run in any namespace, regardless of the enforced Pod Security Standard. It meets all requirements: runs as non-root, disables privilege escalation, uses a read-only root filesystem, drops all capabilities, and applies the default seccomp profile. This configuration should be your baseline for new applications.
Common Pitfalls in Production
- Privileged initContainers: Even if your main containers are secure, a privileged
initContainerwill cause the pod to be rejected bybaselineorrestricted.
Example: An initContainer that sets up environment files withprivileged: truewill block the entire pod. - Third-party images: Many off-the-shelf images run as root by default. You must override
runAsNonRoot/runAsUserin the manifest or rebuild the image if it does not support non-root users.
Example: Public images from Docker Hub often lack proper user settings. - HostPath usage: Mounting host directories is forbidden on
restrictedand discouraged onbaseline. You’ll need to refactor storage patterns, such as usingPersistentVolumeClaimsinstead. - Network and host namespace sharing: These are blocked by
restricted. For workloads that require host networking, isolate them in their own namespace or re-architect to avoid this dependency.
These examples and pitfalls illustrate the impact of Pod Security Standards on real workloads. Understanding these nuances helps teams avoid common issues during migration or enforcement.
Trade-offs, Comparison, and Pitfalls
Choosing the right security profile involves understanding the trade-offs between security, compatibility, and developer effort. The following table summarizes the differences between profiles:
| Profile | Key Restrictions | Typical Use Cases | Developer Effort |
|---|---|---|---|
| Privileged | None. Full host access, all capabilities, root allowed. | Node management, CNI/CNI plugins, storage daemons. | None (but high security risk). |
| Baseline | No privileged containers, some host features allowed, root discouraged but not forbidden. | Most web services, internal apps, legacy workloads. | Low: Usually just minor manifest tweaks. |
| Restricted | No privileged containers, no root, no hostPath, no host network or pid/ipc, most capabilities dropped, seccomp enforced. | Zero-trust clusters, SaaS, fintech, regulated industries. | Moderate to high: May require image and code changes, dev retraining. |
Performance Impact: The main impact of enforcing stricter Pod Security Standards is on development agility and workload compatibility, rather than on runtime performance. For example, requiring non-root images or disabling host networking may necessitate significant changes in legacy applications. However, the PSA controller itself does not introduce direct CPU or memory overhead.
In addition to built-in PodSecurityAdmission, Kubernetes supports extensible admission controllers. For teams needing more granular or custom policies, alternatives like OPA Gatekeeper and Kyverno are available.
Alternatives: OPA Gatekeeper and Kyverno
OPA Gatekeeper and Kyverno are policy engines that extend Kubernetes admission control with custom rules. They allow you to write policies for scenarios not covered by PSS, such as enforcing specific annotations or restricting allowed image registries. However, adopting these tools introduces extra operational overhead and increases complexity.
| Admission Controller | Strengths | Weaknesses |
|---|---|---|
| PodSecurityAdmission (PSA) | Simple, built-in, low overhead, supports PSS profiles, no extra CRDs. | Not customizable beyond the three profiles. |
| OPA Gatekeeper | Highly customizable policies, covers more than PSS. | Requires management, can impact API server latency, learning curve. |
| Kyverno | User-friendly policy syntax, supports mutations, policy reports. | Extra components to manage, more RBAC setup. |
Teams should start with PSA for broad baseline enforcement and only introduce more advanced policy engines if use cases demand customization.
Best Practices for Rolling Out Pod Security Standards
- Start with
auditorwarnbefore moving toenforce. This gives development teams time to adapt and prevents outages due to blocked pods.
Example: Label non-production namespaces withwarn=restrictedand monitor compliance reports. - Document and share compliant pod templates with your teams to accelerate adoption and reduce errors.
Example: Provide a YAML library ofrestricted-compliant manifests. - Automate checks in CI/CD pipelines (e.g.,
kubectl --dry-runor kube-linter) to catch violations before deployment.
Example: Integrate policy checks in pull request workflows. - Review and update base images—use
USERin Dockerfiles, drop capabilities, and setseccompprofiles.
Example: Rebuild images so the application process does not require root. - Isolate legacy or privileged workloads in dedicated namespaces, with clear boundaries and access controls.
Example: Segregate system daemons in a namespace withenforce=privilegedand limit user access.
By following these practices, you can roll out Pod Security Standards smoothly and with minimal disruption.
Key Takeaways
Key Takeaways:
- Pod Security Standards are essential for securing Kubernetes workloads and are enforced by the built-in PodSecurityAdmission controller as of v1.25.
- Adopt
restrictedas your default for new production namespaces—it’s the best way to avoid privilege escalation and supply chain risks.- Legacy workloads may need to stay on
baselineorprivilegeduntil refactored. Use namespace isolation.- Always test enforcement in
auditorwarnmode before switching toenforceto prevent outages.- For specialized security needs, OPA Gatekeeper or Kyverno provide custom controls, but with added complexity.




