How to Master Kubernetes Pod Security Policies for Bulletproof Cluster Security
Misconfigured containers with excessive privileges can undermine even the most robust Kubernetes cluster. Pod Security Policies (PSPs), though deprecated in 1.21+ (and removed in 1.25), remain relevant for legacy support and architectural foundations. Many production environments—especially clusters running Kubernetes 1.20 or earlier—still rely on these mechanisms to harden workloads.
Engineering Problem: Real-World Privilege Escalation
Suppose a misconfigured deployment allows containers to mount host paths or escalate privileges. A breach follows. Could a PSP have blocked this? Often, yes.
Pod Security Policy—Key Mechanism Overview
A PSP in Kubernetes is a cluster-level resource that controls various security-sensitive aspects of the pod specification, acting as an admission controller. It defines a set of conditions that a pod must satisfy for the API server to accept or modify it.
Critical policy levers include:
Field | Purpose |
---|---|
privileged | Grants/disallows all root access and host features. |
allowedCapabilities | Controls specific Linux capabilities containers may assume. |
runAsUser | Enforces UID policy for containerized processes. |
seLinux | Limits/permits SELinux contexts. |
volumes | Explicitly lists allowed volume types (hostPath, emptyDir, etc.). |
hostNetwork , hostPID , hostIPC | Bans or permits containers to share host namespaces. |
Exclusion example: prohibiting hostPath mounts blocks several lateral movement techniques exploited in incidents like CVE-2020-8558.
Note: In clusters at Kubernetes v1.21+, plan an immediate migration to Pod Security Admission (PSA) or OPA Gatekeeper. This writeup is for direct PSP enforcement.
Building and Enforcing a Restrictive Pod Security Policy
Practical baseline PSP: More restrictive than the default, but might still require adjustment for node-level agents or privileged system workloads.
apiVersion: policy/v1beta1
kind: PodSecurityPolicy
metadata:
name: restricted-psp
spec:
privileged: false
allowPrivilegeEscalation: false
requiredDropCapabilities: ["ALL"]
allowedCapabilities: []
volumes:
- 'configMap'
- 'emptyDir'
- 'secret'
- 'persistentVolumeClaim'
hostNetwork: false
hostIPC: false
hostPID: false
runAsUser:
rule: MustRunAsNonRoot
seLinux:
rule: RunAsAny
fsGroup:
rule: RunAsAny
supplementalGroups:
rule: RunAsAny
- No container may run in privileged mode.
- Host networking, IPC, and PID namespaces off-limits.
- Only common K8s volumes permitted—
hostPath
absent intentionally.
Applying the Policy
kubectl apply -f restricted-psp.yaml
Coupling PSPs to Workloads: RBAC Glue Required
A PSP, by itself, is inert. It must be associated with users or service accounts via RBAC.
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: use-restricted-psp
rules:
- apiGroups: ["policy"]
resources: ["podsecuritypolicies"]
resourceNames: ["restricted-psp"]
verbs: ["use"]
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: bind-restricted-psp
namespace: default
subjects:
- kind: ServiceAccount
name: default
roleRef:
kind: ClusterRole
name: use-restricted-psp
apiGroup: rbac.authorization.k8s.io
Apply using:
kubectl apply -f clusterrole.yaml
kubectl apply -f rolebinding.yaml
Gotcha: If no PSP is assigned to a service account, pod creation for that workload will fail with error:
Error from server (Forbidden): error when creating "pod.yaml": pods "test-pod" is forbidden: no PodSecurityPolicy matched
Use kubectl auth can-i use podsecuritypolicy/restricted-psp --as=system:serviceaccount:default:default -n default
for troubleshooting access.
Testing Enforcements: Privilege Escalation Blocked
Deploy a non-compliant pod as a negative test:
apiVersion: v1
kind: Pod
metadata:
name: test-root-pod
spec:
containers:
- name: busybox
image: busybox
command: ["id"]
securityContext:
runAsUser: 0
Expected result: Admission rejection (403) with MustRunAsNonRoot
violation. Check kubectl describe psp restricted-psp
and review kubectl logs -n kube-system kube-apiserver-$(hostname)
for detailed errors.
Pragmatic Policy Design Tips
- Audit existing pods before strict enforcement: Many legacy apps expect to run as root or need
hostNetwork
. Inventory everything with:kubectl get pods --all-namespaces -o json | jq '.items[].spec.containers[] | {pod: .name, runAsUser: .securityContext.runAsUser, capabilities: .securityContext.capabilities}'
- Namespace separation: Apply least-privileged PSPs in tenant namespaces; grant more permissive PSPs only where node-level agents require.
- Rollout plan: Enforce restrictively in non-prod first. Impactful misconfigurations will block critical controllers (common with CNI, CSI, or kube-proxy Pods).
- Combine with NetworkPolicies: PSPs do not limit network connectivity. Segmentation must be handled separately.
- Edge case—sidecar containers: If using tools that auto-inject sidecars (e.g., Istio), those may demand additional permissions.
Alternatives and Migration Strategies (PSA, OPA Gatekeeper)
As of Kubernetes v1.25+, PSP is removed. Options:
- Pod Security Admission (PSA): Native, standardizes three policy levels:
privileged
,baseline
,restricted
. Lighter operational load but different enforcement mechanics and no RBAC glue.- Example label:
kubectl label namespace dev pod-security.kubernetes.io/enforce=restricted
- Example label:
- OPA Gatekeeper / Kyverno: Declarative, GitOps-friendly, and far more extensible at the cost of additional CRD and controller resources.
Recommendation: For new clusters or upgrades, implement PSA or a third-party solution immediately. Maintain understanding of PSP only for clusters that cannot migrate yet.
Final Thoughts
Thoughtful application of Pod Security Policies can block a range of privilege escalations, unsafe volume usage, and accidental misconfiguration—elements that often propagate unnoticed in sprawling, multi-tenant clusters.
No approach is perfect. Some system components require exceptions, and overzealous PSPs can break system workloads. Review and iterate. For legacy clusters: lock scope, document exceptions, and plan a path to new admission controls.
Want to see how PSP interacts with admission webhooks in mixed-mode clusters? That gets complicated—reach out if you encounter strange race conditions or need to discuss migration paths.
Keep your cluster's blast radius contained. Secure by default; permit by exception. Kubernetes rewards discipline.