Orchestration

Master Kubernetes Pod Security Standards: Full Guide

Introduction

In the dynamic and often perilous landscape of cloud-native computing, securing your Kubernetes clusters is paramount. While Kubernetes offers powerful orchestration capabilities, it doesn’t secure your workloads by default. One of the most critical aspects of Kubernetes security is controlling what pods can do, how they run, and what privileges they possess. This is precisely where Kubernetes Pod Security Standards (PSS) come into play. PSS provides a set of predefined security policies ranging from highly permissive to highly restrictive, helping cluster administrators enforce security best practices for their workloads.

Historically, Pod Security Policies (PSPs) were the go-to solution for this, but they were notoriously complex to manage and had several usability issues, leading to their deprecation. PSS, introduced as a successor, simplifies the enforcement of pod security by defining three distinct policies: Privileged, Baseline, and Restricted. These policies can be applied at the namespace level, providing a more intuitive and flexible approach to securing your pods. Implementing PSS is no longer optional; it’s a fundamental requirement for any robust Kubernetes deployment, safeguarding your applications from common vulnerabilities and escalating privileges.

This comprehensive guide will walk you through the essential concepts of Kubernetes Pod Security Standards, from understanding the different policy levels to implementing them effectively using Admission Controllers. We’ll cover practical examples, delve into production considerations, and provide troubleshooting tips to ensure your cluster remains secure and compliant. By the end of this guide, you’ll have a solid understanding of how to leverage PSS to harden your Kubernetes environment and protect your valuable applications and data.

TL;DR: Kubernetes Pod Security Standards (PSS)

Kubernetes Pod Security Standards (PSS) define three security profiles (Privileged, Baseline, Restricted) to enforce pod security. You apply them using Pod Security Admission (PSA) controllers at the namespace level. This guide shows you how to enable PSA, label namespaces, and create exceptions for specific workloads. Essential for hardening your cluster against common vulnerabilities.

Key Commands:


# Label a namespace with a PSS profile in enforce mode
kubectl label namespace <namespace-name> pod-security.kubernetes.io/enforce=restricted

# Label a namespace with a PSS profile in audit mode
kubectl label namespace <namespace-name> pod-security.kubernetes.io/audit=baseline

# Label a namespace with a PSS profile in warn mode
kubectl label namespace <namespace-name> pod-security.kubernetes.io/warn=restricted

# Check the current PSA configuration for a namespace
kubectl describe namespace <namespace-name>

# Deploy a pod that violates a policy (e.g., restricted) to see the effect
kubectl apply -f pod-privileged.yaml

Prerequisites

Before diving into the implementation of Kubernetes Pod Security Standards, ensure you have the following:

  • Kubernetes Cluster: A running Kubernetes cluster (version 1.23 or newer is recommended, as Pod Security Admission is GA from 1.25). You can use Minikube, Kind, or any cloud provider’s managed Kubernetes service (EKS, GKE, AKS).
  • kubectl: The Kubernetes command-line tool, configured to connect to your cluster. Refer to the official kubectl installation guide for instructions.
  • Basic Kubernetes Knowledge: Familiarity with core Kubernetes concepts such as Pods, Deployments, Namespaces, and RBAC.
  • Administrative Access: You need administrative privileges on the cluster to manage namespaces and potentially modify admission controllers.

Step-by-Step Guide

1. Understanding Pod Security Standards (PSS) Profiles

Kubernetes Pod Security Standards define three distinct security profiles, each with increasing levels of restriction. Understanding these profiles is crucial for choosing the right one for your workloads. These profiles are designed to address different security needs, from allowing highly privileged applications to enforcing strict security best practices. They are a significant improvement over the deprecated Pod Security Policies (PSPs) in terms of usability and clarity, providing a clear path for securing your pods.

The three profiles are:

  1. Privileged: This is the least restrictive policy. It imposes no restrictions on pods, allowing for known privilege escalations. This profile is intended for workloads that specifically require elevated privileges, like system-level agents or infrastructure components that need to interact directly with the host. While necessary for some specialized applications, it should be used with extreme caution due to the significant security risks it poses.
  2. Baseline: This profile offers a balance between security and compatibility. It prevents known privilege escalations but allows a wide range of common application workloads to run without issues. It disallows practices like running as root, using hostPath volumes, or allowing privilege escalation. This is often a good starting point for most applications that don’t require specific elevated privileges.
  3. Restricted: This is the most restrictive policy, enforcing current hardening best practices. It prevents known privilege escalations and significantly limits pod capabilities to reduce the attack surface. This profile requires pods to run as a non-root user, use immutable container images, and avoid host-level access. It’s ideal for critical, user-facing applications where security is paramount.

Choosing the correct profile for each namespace is a critical design decision that balances security requirements with application functionality. It’s often recommended to start with ‘Restricted’ and only move to ‘Baseline’ or ‘Privileged’ if absolutely necessary, with clear justifications and compensating controls. For more granular control over network security, consider implementing Kubernetes Network Policies alongside PSS.

2. Enabling Pod Security Admission (PSA)

Pod Security Admission (PSA) is a built-in Kubernetes admission controller that enforces the Pod Security Standards. It replaced Pod Security Policies (PSPs) as the recommended way to enforce pod security. PSA is enabled by default in Kubernetes clusters version 1.25 and later. If you are running an older version (1.23 or 1.24), you might need to ensure it’s explicitly enabled. For cloud-managed Kubernetes services, PSA is typically enabled by default.

To verify if PSA is active and to understand its configuration, you can check the API server’s manifest or the cluster’s admission controller settings. The PSA controller intercepts requests to create or update pods and checks them against the configured PSS profile for the pod’s namespace. This enforcement happens at three levels: `enforce`, `audit`, and `warn`.

  • Enforce: Pods that violate the policy are rejected. This is the strictest mode and should be used when you are confident that all workloads in the namespace comply.
  • Audit: Pods that violate the policy are allowed, but an audit annotation is added to the request, which can be seen in the API server’s audit logs. This is useful for testing policies without breaking existing workloads.
  • Warn: Pods that violate the policy are allowed, but a user-facing warning is returned. This is great for gradual rollout and informing users about upcoming policy changes.

You can check your Kubernetes version to confirm PSA status.


kubectl version --short

# Expected output (version 1.25+ indicates PSA is GA and enabled by default)
# Client Version: v1.28.3
# Kustomize Version: v5.0.4
# Server Version: v1.28.3

If your cluster is older than 1.25, you might need to enable the `PodSecurity` admission plugin in your API server configuration. For self-managed clusters, this typically involves editing the `kube-apiserver` manifest. For cloud providers, consult their documentation (e.g., GKE Pod Security Admission, EKS Pod Security Standards).

3. Applying PSS Profiles to Namespaces

The core of PSS implementation lies in labeling namespaces with the desired security profiles. You can apply different profiles and modes (enforce, audit, warn) to each namespace, providing fine-grained control over your cluster’s security posture. This flexibility allows you to gradually introduce stricter policies without disrupting critical applications.

Let’s start by creating a new namespace for our demonstration. We’ll then apply different PSS labels to it.


# Create a new namespace
kubectl create namespace pss-demo

# Verify the namespace is created
kubectl get namespace pss-demo

# Expected output
# NAME      STATUS   AGE
# pss-demo  Active   5s

Now, let’s apply the `restricted` profile in `enforce` mode to our `pss-demo` namespace. This means any pod deployed to this namespace that violates the `restricted` profile will be rejected.


# Apply the 'restricted' profile in 'enforce' mode
kubectl label namespace pss-demo pod-security.kubernetes.io/enforce=restricted

# Verify the label
kubectl describe namespace pss-demo

# Expected output snippet (look for Labels)
# Name:         pss-demo
# Labels:       kubernetes.io/metadata.name=pss-demo
#               pod-security.kubernetes.io/enforce=restricted
#               pod-security.kubernetes.io/enforce-version=latest
# ...

You can also apply policies in `audit` and `warn` modes simultaneously, which is excellent for testing and phased rollouts. For example, you might want to audit against `restricted` while enforcing `baseline` and warning about `restricted`.


# Apply 'baseline' in enforce, 'restricted' in audit, and 'restricted' in warn
kubectl label namespace pss-demo pod-security.kubernetes.io/enforce=baseline \
                                 pod-security.kubernetes.io/audit=restricted \
                                 pod-security.kubernetes.io/warn=restricted --overwrite

# Verify the labels
kubectl describe namespace pss-demo

# Expected output snippet
# Name:         pss-demo
# Labels:       kubernetes.io/metadata.name=pss-demo
#               pod-security.kubernetes.io/audit=restricted
#               pod-security.kubernetes.io/audit-version=latest
#               pod-security.kubernetes.io/enforce=baseline
#               pod-security.kubernetes.io/enforce-version=latest
#               pod-security.kubernetes.io/warn=restricted
#               pod-security.kubernetes.io/warn-version=latest
# ...

4. Testing PSS Enforcement

Now that we have applied a `restricted` policy to our `pss-demo` namespace, let’s test its enforcement. We’ll try to deploy a pod that violates the `restricted` profile and observe the outcome. A common violation for the `restricted` profile is running as the root user or requesting host access.

First, let’s try to deploy a simple Nginx pod that *complies* with the `restricted` profile. This pod should run as a non-root user and not request any elevated privileges.


# pod-compliant.yaml
apiVersion: v1
kind: Pod
metadata:
  name: compliant-nginx
spec:
  containers:
  - name: nginx
    image: nginx:latest
    securityContext:
      runAsNonRoot: true
      runAsUser: 1000 # Example non-root user ID
      allowPrivilegeEscalation: false
      capabilities:
        drop:
          - ALL
      seccompProfile:
        type: RuntimeDefault
    ports:
    - containerPort: 80

# Deploy the compliant pod
kubectl apply -f pod-compliant.yaml -n pss-demo

# Expected output
# pod/compliant-nginx created

# Verify the pod status
kubectl get pod compliant-nginx -n pss-demo

# Expected output
# NAME              READY   STATUS    RESTARTS   AGE
# compliant-nginx   1/1     Running   0          10s

Now, let’s try to deploy a pod that *violates* the `restricted` profile. This pod will attempt to run as root and allow privilege escalation, which are explicitly forbidden by the `restricted` policy.


# pod-privileged.yaml
apiVersion: v1
kind: Pod
metadata:
  name: privileged-nginx
spec:
  containers:
  - name: nginx
    image: nginx:latest
    securityContext:
      runAsUser: 0 # Running as root, violates restricted
      allowPrivilegeEscalation: true # Violates restricted
      capabilities:
        add:
          - SYS_ADMIN # Example of adding capabilities, violates restricted
    ports:
    - containerPort: 80

# Deploy the privileged pod (this should be rejected)
kubectl apply -f pod-privileged.yaml -n pss-demo

# Expected output (example error message)
# Error from server (Forbidden): error when creating "pod-privileged.yaml": pods "privileged-nginx" is forbidden: violates PodSecurity "restricted:latest": allowPrivilegeEscalation != false (container "nginx" must set securityContext.allowPrivilegeEscalation=false)
#   unrestricted capabilities (container "nginx" must drop all capabilities)
#   runAsNonRoot != true (container "nginx" must set securityContext.runAsNonRoot=true)
#   seccompProfile (pod or container "nginx" must set securityContext.seccompProfile.type to "RuntimeDefault" or "Localhost")

As you can see, the pod creation request was rejected, and a clear error message indicates which aspects of the `restricted` policy were violated. This demonstrates the `enforce` mode in action. If the namespace was labeled with `audit` or `warn` mode for `restricted`, the pod would have been created, but with an audit log entry or a warning message, respectively.

5. Exemptions and Gradual Rollout

While PSS provides powerful enforcement, there might be legitimate reasons to exempt certain namespaces or workloads from strict policies. For example, system-critical components, legacy applications, or specific tools might require elevated privileges. PSS allows for exemptions, but these should be used sparingly and with careful consideration.

Exemptions can be configured at the cluster level in the Pod Security Admission configuration, typically by modifying the `PodSecurityConfiguration` object. The exemptions can be based on:

  • Usernames: Exempt specific service accounts or user identities.
  • RuntimeClassNames: Exempt pods using a particular RuntimeClass.
  • Namespaces: Exempt entire namespaces from PSS enforcement.

Note: Modifying the `PodSecurityConfiguration` is an advanced operation and usually requires direct access to the `kube-apiserver` configuration, which might not be available in managed Kubernetes services. For most users, applying PSS labels at the namespace level is the primary method of control.

A better strategy for gradual rollout and managing exceptions is to use the `warn` and `audit` modes initially.

  1. Audit Mode: Apply `pod-security.kubernetes.io/audit=restricted` to a namespace. This will log violations without blocking deployments. Analyze the audit logs to identify non-compliant pods.
  2. Warn Mode: Apply `pod-security.kubernetes.io/warn=restricted`. This will warn users about violations during deployment but still allow the pod to run. This is excellent for communicating upcoming policy changes to developers.
  3. Enforce Mode: Once you’ve addressed all violations and are confident, switch to `pod-security.kubernetes.io/enforce=restricted`.

Let’s demonstrate the `warn` mode. First, remove the `enforce` label and add `warn=restricted`.


# Remove enforce label and add warn label
kubectl label namespace pss-demo pod-security.kubernetes.io/enforce- --overwrite
kubectl label namespace pss-demo pod-security.kubernetes.io/warn=restricted --overwrite

# Verify the labels
kubectl describe namespace pss-demo

# Expected output snippet
# Labels:       kubernetes.io/metadata.name=pss-demo
#               pod-security.kubernetes.io/warn=restricted
#               pod-security.kubernetes.io/warn-version=latest
# ...

Now, try to deploy the `privileged-nginx` pod again.


# Deploy the privileged pod with warn mode
kubectl apply -f pod-privileged.yaml -n pss-demo

# Expected output (notice the Warning, but the pod is created)
# Warning: PodSecurity "restricted:latest" policy: allowPrivilegeEscalation != false (container "nginx" must set securityContext.allowPrivilegeEscalation=false), unrestricted capabilities (container "nginx" must drop all capabilities), runAsNonRoot != true (container "nginx" must set securityContext.runAsNonRoot=true), seccompProfile (pod or container "nginx" must set securityContext.seccompProfile.type to "RuntimeDefault" or "Localhost")
# pod/privileged-nginx created

# Verify the pod status
kubectl get pod privileged-nginx -n pss-demo

# Expected output
# NAME               READY   STATUS    RESTARTS   AGE
# privileged-nginx   1/1     Running   0          5s

The pod was created, but a warning was issued. This is extremely useful for identifying non-compliant workloads before enforcing stricter policies. For advanced security policies, you might consider tools like Kyverno which offer more fine-grained control and policy-as-code capabilities beyond PSS.

Production Considerations

Implementing Pod Security Standards in a production environment requires careful planning and execution to avoid disrupting critical services. Here are key considerations:

  1. Phased Rollout: Never apply `enforce` mode directly to production namespaces without prior testing. Start with `warn` mode, then `audit` mode, and finally `enforce`. This allows you to identify and remediate violations gradually.
  2. Namespace Segmentation: Strategically segment your cluster into namespaces with different PSS profiles based on their security requirements. For example, highly sensitive applications might reside in `restricted` namespaces, while system agents could be in `baseline` or even `privileged` namespaces (with strong justification).
  3. Legacy Applications: Identify and isolate legacy applications that cannot easily comply with `restricted` or `baseline` policies. These might need dedicated `privileged` or `baseline` namespaces, or require significant refactoring. This is also a good opportunity to review your overall Kubernetes Network Policies for these isolated applications.
  4. Admission Controllers and Policy Engines: While PSS is excellent for basic pod security, consider integrating more advanced policy engines like Open Policy Agent (OPA) Gatekeeper or Kyverno for more complex, custom security policies, especially if your organization has specific compliance requirements. These tools can augment PSS by providing even finer-grained control and custom validation rules for various Kubernetes resources. For instance, Kyverno can enforce image signing via Sigstore and Kyverno.
  5. Monitoring and Alerting: Monitor audit logs for PSS violations, especially when running in `audit` or `warn` mode. Set up alerts for unexpected violations in `enforce` mode, indicating a potential misconfiguration or security incident. Tools like eBPF Observability with Hubble can provide deep insights into network and container behavior, complementing PSS.
  6. CI/CD Integration: Incorporate PSS compliance checks into your CI/CD pipelines. Tools like Datree or Conftest can validate Kubernetes manifests against PSS profiles before deployment, catching violations early in the development cycle.
  7. RBAC and Least Privilege: PSS complements RBAC. Ensure that users and service accounts only have the necessary permissions. For example, don’t grant permission to create pods in a `privileged` namespace to users who don’t absolutely need it.
  8. Container Image Security: PSS focuses on runtime security. Combine it with robust container image scanning (e.g., Trivy, Snyk) to address vulnerabilities within your container images.
  9. Documentation and Training: Document your PSS strategy, including which profiles are applied to which namespaces and why. Train your development and operations teams on PSS requirements and how to write compliant applications.
  10. Performance Impact: While Pod Security Admission is highly optimized, any admission controller adds a slight overhead to API server operations. For most clusters, this impact is negligible, but it’s a factor to consider in extremely high-throughput environments.

Troubleshooting

Here are some common issues you might encounter when implementing Kubernetes Pod Security Standards and their solutions:

  1. Issue: Pods are being rejected, but I didn’t apply any PSS labels.

    Solution: Check if a default PSS profile is being enforced at the cluster level or by a higher-level admission controller (like a managed Kubernetes service’s default policies). Some managed services (e.g., GKE Autopilot) enforce the Restricted profile by default. Use kubectl describe namespace <namespace-name> to see if any PSS labels are present, or consult your cloud provider’s documentation.

    
    kubectl describe namespace default
    # Look for pod-security.kubernetes.io/enforce labels
    
  2. Issue: My pod is rejected, and the error message says “violates PodSecurity ‘restricted:latest'”, but my pod seems compliant.

    Solution: Double-check all securityContext fields in your pod/container specification against the Restricted PSS requirements. Common culprits include:

    • runAsNonRoot: true is missing or runAsUser: 0 is set.
    • allowPrivilegeEscalation: false is missing.
    • capabilities.drop: ["ALL"] is missing or capabilities are added.
    • seccompProfile.type: RuntimeDefault or Localhost is missing.
    • Use of hostPath volumes.

A good starting point for a restricted-compliant pod is:


securityContext:
  runAsNonRoot: true
  runAsUser: 1000
  allowPrivilegeEscalation: false
  capabilities:
    drop:
      - ALL
  seccompProfile:
    type: RuntimeDefault
  • Issue: I applied pod-security.kubernetes.io/enforce=restricted, but existing pods are still running.

    Solution: PSS policies are only applied during pod creation or update. Existing running pods are not affected. If you want to enforce the policy on existing deployments, you need to trigger a rolling update or recreate the pods. For Deployments, simply changing an environment variable or image tag will trigger a rollout:

    
    kubectl rollout restart deployment <deployment-name> -n <namespace>
    
  • Issue: I’m seeing “Warning: PodSecurity…” messages, but my pods are still created.

    Solution: This indicates that the namespace has a PSS profile applied in `warn` mode (e.g., pod-security.kubernetes.io/warn=restricted). The pods are being created because `warn` mode does not block creation, it only provides a warning. This is useful for identifying non-compliant workloads before switching to `enforce` mode. To block pod creation, you need to change the label to `enforce` mode: kubectl label namespace <namespace-name> pod-security.kubernetes.io/enforce=restricted --overwrite.

  • Issue: I need to run a privileged container, but PSS is blocking it. How do I make an exception?

    Solution: The safest way to handle this is to move the privileged workload to a dedicated namespace that has a more permissive PSS profile (e.g., `baseline` or `privileged`). For example:

    
    # Create a namespace for privileged workloads
    kubectl create namespace privileged-apps
    
    # Label it with the 'privileged' profile
    kubectl label namespace privileged-apps pod-security.kubernetes.io/enforce=privileged
    
    # Deploy your privileged pod into this namespace
    kubectl apply -f your-privileged-pod.yaml -n privileged-apps
    

    Avoid cluster-wide exemptions if possible, as they can weaken your overall security posture. If you need to manage node-level resources, consider using DaemonSets with appropriate tolerations and node selectors, and ensure their namespace has a `privileged` or `baseline` profile.

  • Issue: My cluster is older than Kubernetes 1.25, and PSS isn’t working.

    Solution: Pod Security Admission became GA in Kubernetes 1.25. If you are on an older version (1.23 or 1.24), you might need to manually enable the `PodSecurity` admission plugin in your `kube-apiserver` configuration. For managed services, check their version compatibility and specific instructions. Upgrading your cluster to 1.25 or newer is the recommended approach for full PSA functionality. For more advanced features like eBPF-based security, you might also be interested in Cilium WireGuard Encryption which works best on newer Kubernetes versions.

  • FAQ Section

    1. What is the difference between Pod Security Standards (PSS) and Pod Security Policies (PSPs)?

      PSS is the successor to PSPs. PSPs were complex, difficult to manage, and had several usability issues, leading to their deprecation in Kubernetes 1.21 and removal in 1.25. PSS simplifies pod security enforcement by defining three clear, opinionated profiles (Privileged, Baseline, Restricted) that are applied at the namespace level using labels and a built-in admission controller (Pod Security Admission). PSS is much easier to use and manage than PSPs.

    2. Can I create custom Pod Security Standards profiles?

      No, PSS defines a fixed set of three profiles (Privileged, Baseline, Restricted). You cannot create custom profiles within the PSS framework itself. If you need more granular or highly customized security policies, you should use a policy engine like Open Policy Agent (OPA) Gatekeeper or Kyverno. These tools allow you to define arbitrary policies that can complement or extend PSS.

    3. How do PSS profiles interact with existing SecurityContext configurations in my pods?

      PSS profiles act as an admission control layer. When a pod is created or updated, its securityContext is evaluated against the PSS profile enforced on its namespace. If the securityContext (or lack thereof) violates the PSS profile, the pod creation/update will be rejected (in `enforce` mode). PSS doesn’t modify your pod’s securityContext; it simply validates it. For instance, if your pod tries to run as root and the namespace is `restricted`, the pod will be denied even if you explicitly set `runAsUser: 0` in your manifest.

    4. What happens if I don’t apply any PSS labels to a namespace?

      If no PSS labels are applied to a namespace, the Pod Security Admission controller will refer to its cluster-wide default configuration. By default, Kubernetes clusters (especially 1.25+) typically run with a permissive default (e.g., `privileged` or no restriction) if not explicitly configured. However, some managed Kubernetes services might enforce a default `baseline` or `restricted` policy across all namespaces. Always check your cluster’s specific configuration or cloud provider’s documentation. It’s best practice to explicitly label all namespaces with an appropriate PSS profile.

    5. Can PSS help with compliance certifications (e.g., PCI DSS, HIPAA)?

      Yes, PSS is a foundational component for achieving various compliance certifications. By enforcing stricter security controls on pods, PSS helps mitigate common vulnerabilities that could lead to data breaches or unauthorized access, which are often requirements for compliance. However, PSS alone is not sufficient for full compliance. It must be combined with other security measures like Network Policies, RBAC, image scanning, encryption (e.g., Cilium WireGuard Encryption), auditing, and regular security assessments to meet comprehensive compliance standards.

    Cleanup Commands

    After you’ve finished experimenting with Pod Security Standards, you can clean up the resources created during this guide.

    
    # Delete the compliant pod
    kubectl delete pod compliant-nginx -n pss-demo
    
    # Delete the privileged pod (if it was created in warn mode)
    kubectl delete pod privileged-nginx -n pss-demo
    
    # Delete the namespace
    kubectl delete namespace pss-demo
    
    
    # Expected output
    # pod "compliant-nginx" deleted
    # pod "privileged-nginx" deleted
    # namespace "pss-demo" deleted
    

    Next Steps / Further Reading

    Congratulations! You’ve successfully navigated the world of Kubernetes Pod Security Standards. To further enhance your cluster’s security and operational efficiency, consider exploring these topics:

    Conclusion

    Kubernetes Pod Security Standards are an indispensable tool in your cloud-native security arsenal. By providing a clear, opinionated framework for enforcing pod security, PSS simplifies

    Leave a Reply

    Your email address will not be published. Required fields are marked *