Kubernetes How To

Kubernetes How To

Reading time1 min
#Kubernetes#Cloud#Security#PodSecurityPolicies#DevOps#ContainerSecurity

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:

FieldPurpose
privilegedGrants/disallows all root access and host features.
allowedCapabilitiesControls specific Linux capabilities containers may assume.
runAsUserEnforces UID policy for containerized processes.
seLinuxLimits/permits SELinux contexts.
volumesExplicitly lists allowed volume types (hostPath, emptyDir, etc.).
hostNetwork, hostPID, hostIPCBans 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
      
  • 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.