Implementing Pod Security Policies in Kubernetes

Pod Security Policies are a Kubernetes feature designed to control the security settings of pods, such as user privileges, volume types, host networking, and more.

Security is a critical concern in any Kubernetes environment, especially as workloads scale and become more complex.

From unauthorized privilege escalations to unrestricted host access, the potential for security breaches grows without robust policies in place.

That’s where Pod Security Policies (PSPs) come in.

 By defining and enforcing PSPs, platform teams can ensure that workloads run under strict, pre-approved configurations—reducing the attack surface and ensuring compliance with security best practices.

In this blog post, we’ll walk through what Pod Security Policies are, why they matter, and how to implement them effectively in a modern Kubernetes cluster.

Whether you’re securing a small development cluster or a large-scale production environment, PSPs are a foundational step in enforcing strong security controls.

⚠️ Note: Pod Security Policies are deprecated as of Kubernetes 1.21 and removed in 1.25. We’ll also cover Pod Security Admission (PSA) as the recommended alternative moving forward.

Additional Resources:

You might also like:


What Are Pod Security Policies?

Pod Security Policies (PSPs) are a Kubernetes feature that allows administrators to control the security aspects of pod specifications at a granular level.

Their main goal is to restrict what pods are allowed to do and what resources they can access, based on predefined security rules.

PSPs act as a gatekeeper that intercepts pod creation and update requests.

If a pod’s configuration violates the constraints defined in the policy, the request is denied—ensuring that only compliant workloads can run in the cluster.

Purpose of PSPs

At their core, Pod Security Policies help:

  • Enforce security best practices consistently across all pods

  • Minimize the blast radius of a compromised container

  • Ensure compliance with organizational or regulatory standards

Key Features and Controls

Pod Security Policies provide fine-grained control over a variety of pod-level security settings, including:

  • Privileged Mode: Controls whether a container can run in privileged mode.

  • RunAsUser: Enforces which Linux user ID containers must run as.

  • Allowed Volume Types: Specifies which volume types (e.g., hostPath, configMap, emptyDir) are permitted.

  • Host Namespaces: Restricts access to host network, process, and IPC namespaces.

  • Capabilities: Controls Linux capabilities that can be added or dropped.

  • SELinux Options: Sets security labeling via SELinux.

  • AppArmor and Seccomp Profiles: Enforces mandatory access control profiles if supported by the container runtime.

By using these controls, security teams can significantly reduce the risk posed by misconfigured or overly-permissive containers.

🔐 PSPs are powerful, but they require careful configuration to avoid blocking legitimate workloads. Testing in a staging environment is highly recommended before rolling out cluster-wide enforcement.


Deprecation Notice and Alternatives

Pod Security Policies (PSPs) were officially deprecated in Kubernetes v1.21 and fully removed in v1.25, signaling a shift toward more flexible and extensible security models.

While PSPs served as a foundational tool for cluster-level security, they had limitations in usability, configurability, and extensibility—leading to the development of more powerful alternatives.

Why Were PSPs Deprecated?

  • Complex to configure and maintain

  • Difficult to debug when policies block pod deployments

  • Lack of namespace scoping and fine-grained exceptions

As a result, the Kubernetes community introduced new approaches that better align with modern DevSecOps workflows.

Modern Alternatives to PSPs

Here are three leading alternatives to implement pod-level security in Kubernetes:

1. Pod Security Admission (PSA)

Pod Security Admission is a built-in admission controller introduced as a replacement for PSPs. It uses predefined security profiles (privileged, baseline, restricted) that can be applied to namespaces.

  • ✅ Native to Kubernetes (v1.23+)

  • ✅ Easier to adopt with progressive enforcement modes (audit, warn, enforce)

  • ❌ Less customizable than PSPs or third-party tools

2. OPA/Gatekeeper

Open Policy Agent (OPA) with Gatekeeper is a powerful, policy-as-code framework for Kubernetes admission control.

  • ✅ Highly customizable with Rego policy language

  • ✅ Supports dry runs, audit mode, and constraint templates

  • ❌ Steeper learning curve

Check out our related post: RBAC Kubernetes: How to Manage User Access Effectively

3. Kyverno

Kyverno is a Kubernetes-native policy engine that simplifies policy definition using YAML.

  • ✅ Easy syntax and Kubernetes-native CRDs

  • ✅ Supports mutations, validations, and generate policies

  • ✅ Actively adopted and maintained by the CNCF


Key Pod Security Policy Components

When Pod Security Policies (PSPs) were active in Kubernetes, they provided fine-grained control over the security configurations of pods.

Below are some of the most important components that made up a typical PSP definition:

privileged: true/false

Controls whether a pod can run in privileged mode, which grants elevated permissions to containers. Setting this to false is a key step in reducing the attack surface.

Allowed Volume Types

Specifies which volume types a pod is allowed to use (e.g., configMap, secret, emptyDir, hostPath). Restricting certain volume types like hostPath can prevent unauthorized access to host resources.

yaml
allowedHostPaths:
- pathPrefix: "/var/log"
readOnly: true


Host Networking, IPC, and PID

These settings control whether a pod can share the host’s network namespace (hostNetwork), inter-process communication (hostIPC), or process ID namespace (hostPID).

yaml
hostNetwork: false
hostPID: false
hostIPC: false

Disabling these options is crucial to maintain pod isolation.

User and Group ID Controls

Allows enforcement of which user or group IDs a container can run as:

  • runAsUser: Specifies UID

  • runAsGroup: Specifies GID

  • supplementalGroups: Additional group IDs

  • fsGroup: Group ownership for mounted volumes

These constraints help enforce least privilege access inside the container.

AppArmor and Seccomp Profiles

AppArmor and Seccomp provide Linux kernel-level security. PSPs can restrict which profiles are allowed.

yaml
allowedAppArmorProfiles:
- "runtime/default"
seccompProfiles:
“runtime/default”

These profiles reduce the system calls and capabilities containers can access, further hardening the runtime environment.

readOnlyRootFilesystem

Forces containers to mount their root file system as read-only, reducing the risk of tampering or unauthorized writes inside the container.

yaml
readOnlyRootFilesystem: true

These components together enabled teams to implement strict security boundaries within their Kubernetes clusters.

While PSPs are deprecated, their concepts live on in newer tools like Kyverno and OPA Gatekeeper.


Step-by-Step: Implementing PSPs

Although Pod Security Policies (PSPs) have been deprecated and removed in Kubernetes v1.25, understanding how they were implemented can still help when migrating to alternatives like Pod Security Admission or Kyverno.

Here’s a step-by-step guide to implementing PSPs on supported Kubernetes versions (<= v1.24):

1. Enable the PSP Admission Controller

To begin, you need to enable the PodSecurityPolicy admission controller in the Kubernetes API server configuration.

In kube-apiserver (e.g., as a manifest in kubeadm-managed clusters), add:

yaml
--enable-admission-plugins=...,PodSecurityPolicy,...

⚠️ Note: Order matters. Make sure PodSecurityPolicy is included properly and not disabled in the --disable-admission-plugins flag.

2. Create a Basic PodSecurityPolicy YAML

Here’s a simple example that restricts privileges while allowing essential operations:

yaml
apiVersion: policy/v1beta1
kind: PodSecurityPolicy
metadata:
name: restricted-psp
spec:
privileged: false
runAsUser:
rule: 'MustRunAsNonRoot'
seLinux:
rule: 'RunAsAny'
fsGroup:
rule: 'MustRunAs'
ranges:
- min: 1
max: 65535
supplementalGroups:
rule: 'MustRunAs'
ranges:
- min: 1
max: 65535
readOnlyRootFilesystem: true
volumes:
- 'configMap'
- 'secret'
- 'emptyDir'

This policy denies privileged mode, enforces non-root containers, and limits volume types.

3. Create Role/ClusterRole and RoleBinding/ClusterRoleBinding

To allow specific users or service accounts to use the PSP, bind it using RBAC.

yaml
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: psp-user
rules:
- apiGroups: ['policy']
resources: ['podsecuritypolicies']
resourceNames: ['restricted-psp']
verbs: ['use']

Then bind it:

yaml
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: use-psp
roleRef:
kind: ClusterRole
name: psp-user
apiGroup: rbac.authorization.k8s.io
subjects:
- kind: ServiceAccount
name: default
namespace: default

This grants the default service account in the default namespace access to use restricted-psp.

4. Apply the Policy to Appropriate Users or Service Accounts

Apply the PSP YAML, RBAC roles, and bindings using:

bash
kubectl apply -f restricted-psp.yaml
kubectl apply -f psp-role.yaml
kubectl apply -f psp-rolebinding.yaml


5. Test the Configuration

Try deploying a pod that violates the PSP to verify enforcement:

yaml
apiVersion: v1
kind: Pod
metadata:
name: privileged-pod
spec:
containers:
- name: nginx
image: nginx
securityContext:
privileged: true

This pod should fail admission if the PSP is working correctly.


Example PodSecurityPolicy YAML

Below is a basic example of a PodSecurityPolicy (PSP) YAML manifest designed to enforce strict security boundaries, prevent privilege escalation, and limit access to host resources.

📄 Example: Restricted PodSecurityPolicy

 

yaml
apiVersion: policy/v1beta1
kind: PodSecurityPolicy
metadata:
name: restricted-psp
spec:
privileged: false # Do not allow privileged containers
allowPrivilegeEscalation: false # Prevent escalation to root
requiredDropCapabilities:
- ALL # Drop all Linux capabilities
volumes:
- 'configMap'
- 'emptyDir'
- 'secret'
- 'downwardAPI'
- 'projected'
hostNetwork: false # Disallow access to host network
hostIPC: false # Disallow access to host IPC namespace
hostPID: false # Disallow access to host PID namespace
runAsUser:
rule: MustRunAsNonRoot # Enforce non-root container users
seLinux:
rule: RunAsAny
fsGroup:
rule: MustRunAs
ranges:
- min: 1
max: 65535
supplementalGroups:
rule: MustRunAs
ranges:
- min: 1
max: 65535
readOnlyRootFilesystem: true # Enforce immutable container file systems


🔒 What This PSP Protects Against

This policy helps secure your Kubernetes workloads by:

  • Blocking privileged containers: Prevents pods from having root-like access to the host.

  • Disabling privilege escalation: Ensures containers can’t gain additional privileges.

  • Restricting volume types: Only allows safe volumes like configMap, secret, and emptyDir.

  • Enforcing non-root user contexts: Requires containers to run as non-root users.

  • Preventing host namespace access: Blocks shared access to host-level networking, process trees, and inter-process communication.

  • Ensuring immutable root filesystems: Reduces attack surface by disallowing runtime writes to the container filesystem.

This example offers a good starting point for implementing secure defaults.

In production environments, you can tailor the values based on your application needs and threat model.


Migration Strategy Post-Deprecation

With PodSecurityPolicies (PSPs) officially removed in Kubernetes v1.25, it’s crucial to migrate to supported alternatives to maintain a secure cluster.

Thankfully, several mature solutions exist, offering both built-in and extensible policy enforcement mechanisms.

🔄 Using Pod Security Admission (PSA)

Pod Security Admission (PSA) is a built-in replacement for PSPs introduced in Kubernetes v1.22 and stable in v1.25.

PSA applies preset policy levels (privileged, baseline, restricted) via namespace labels.

Example: Enforcing restricted PSA in a namespace

 

bash
kubectl label namespace secure-app \
pod-security.kubernetes.io/enforce=restricted \
pod-security.kubernetes.io/audit=restricted \
pod-security.kubernetes.io/warn=restricted

This configuration enforces the restricted policy (comparable to a strict PSP) and also logs any policy violations for audit and warning purposes.

🔧 Policy-as-Code with Kyverno and OPA/Gatekeeper

For teams needing fine-grained, customizable policies, Kyverno and OPA/Gatekeeper are powerful tools.

🛠️ Kyverno

Kyverno uses Kubernetes-native YAML syntax, making it approachable for platform teams.

Example: Disallow privileged pods

yaml
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: disallow-privileged
spec:
validationFailureAction: enforce
rules:
- name: validate-privileged
match:
resources:
kinds:
- Pod
validate:
message: "Privileged mode is not allowed."
pattern:
spec:
containers:
- securityContext:
privileged: false

🔐 OPA/Gatekeeper

OPA Gatekeeper uses Rego, a declarative policy language. It’s more flexible but has a steeper learning curve than Kyverno.

Example use case: Restrict hostPath volume usage

📦 Sample Migration Path

StepDescription
1️⃣Audit existing PSPs and policies in use
2️⃣Map policies to PSA levels or create custom Kyverno/OPA rules
3️⃣Apply PSA labels to namespaces or install Kyverno/Gatekeeper
4️⃣Test enforcement in staging
5️⃣Gradually roll out to production clusters

By planning a thoughtful migration, teams can retain (and even enhance) their cluster security posture in a post-PSP Kubernetes world.


Best Practices for Pod Security

Securing your Kubernetes environment requires a proactive and layered approach.

Whether you’re using legacy PodSecurityPolicies or newer tools like PSA, Kyverno, or OPA, following these best practices can help you maintain a robust security posture.

🔒 Principle of Least Privilege

Always grant the minimum permissions necessary for a container or workload to function. This includes:

  • Avoiding privileged: true unless absolutely necessary

  • Running containers as non-root users

  • Disabling unnecessary Linux capabilities

  • Restricting access to host resources like volumes, networking, and process IDs

💡 Tip: Combine Kubernetes SecurityContext settings with policy enforcement tools like Kyverno or OPA to ensure compliance.

🧱 Use Namespace-Based Policies

Isolating workloads into namespaces allows you to apply differentiated security postures based on trust levels.

  • Use Kubernetes namespaces to segregate workloads (e.g., prod, dev, external)

  • Apply Pod Security Admission labels to enforce varying levels of restriction

  • Pair with Network Policies to limit communication between namespaces

See our related guide on Implementing Pod Security Admission for more on namespace-level controls.

🤖 Automate Policy Enforcement in CI/CD

Catch security misconfigurations early by integrating policy validation into your CI/CD pipelines:

  • Use tools like Kyverno CLI or Conftest (for OPA) in pre-deployment checks

  • Validate Helm charts or Kubernetes manifests before merging or applying

  • Block deployments that violate enforced policies

Example: A GitHub Actions workflow that fails the pipeline if a new Pod configuration includes hostNetwork: true.

📋 Conduct Regular Audits and Reviews

Security isn’t a one-time task. Regularly auditing your cluster and policies ensures ongoing compliance and visibility:

  • Use audit logs or OPA’s audit mode to review violations

  • Schedule recurring policy reviews during sprint retros or release cycles

  • Stay updated with changes in Kubernetes security features and deprecations

🔍 Need observability too? Check out our post on Dynatrace vs Kibana for tools that help monitor security-related metrics and logs.

By combining these practices with modern tooling, you can build a Kubernetes environment that’s secure, compliant, and resilient to common threats.


Conclusion

Securing your Kubernetes workloads is not optional—it’s essential.

As containerized applications scale across cloud-native environments, the surface area for attacks grows alongside them.

That’s why understanding and implementing Pod Security Policies (PSPs) or their modern alternatives is so critical.

🔑 Key Takeaways

  • Pod Security Policies were once the native mechanism for enforcing pod-level security but have since been deprecated in favor of tools like Pod Security Admission (PSA), OPA/Gatekeeper, and Kyverno.

  • Effective security starts with least privilege, strong isolation through namespaces, and automated enforcement in CI/CD pipelines.

  • Tools like PSPs and their successors help restrict privileged access, enforce safe volume usage, and prevent common container security misconfigurations.

🔐 Secure Workloads, Secure Infrastructure

Whether you’re running a small dev cluster or managing production-grade Kubernetes at scale, securing your workloads should be top of mind.

Misconfigurations—especially around pod privileges, user IDs, and host access—can be the gateway for serious breaches.

✅ Call to Action

Now is the time to audit your current pod security setup:

  • Are you using deprecated PSPs? Start planning your migration.

  • Are your workloads running with more privileges than necessary?

  • Is your CI/CD pipeline enforcing security policies before deployment?

If you’re ready to modernize your Kubernetes security posture, start small—but start today.

🔎 Need more guidance? Explore our related posts on Implementing Pod Security Admission, RBAC Kubernetes: How to Manage User Access Effectively, and Optimizing Kubernetes Resource Limits to further harden your clusters.

Be First to Comment

    Leave a Reply

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