Skip to main content

Overview

Pod Security Policy (PSP) was deprecated in Kubernetes v1.21 and removed in v1.25. For current clusters, use Pod Security Standards and Pod Security Admission instead, or a policy-as-code solution such as Kyverno, Open Policy Agent (OPA), or Gatekeeper.
Pod Security Policy (PSP) was a cluster-level admission controller that allowed you to define conditions a pod must meet in order to run in the cluster. It not only blocked non-compliant pods from being created but also could mutate pod configurations using defaultAddCapabilities. To enable PSP, add PodSecurityPolicy to the --enable-admission-plugins flag on the kube-apiserver:
kube-apiserver.yaml
- kube-apiserver
  - --enable-admission-plugins=NodeRestriction,PodSecurityPolicy

Usage and concept

Consider the following insecure pod configuration:
sample-pod.yaml
apiVersion: v1
kind: Pod
metadata:
  name: sample
spec:
  containers:
    - name: ubuntu
      image: ubuntu
      securityContext:
        privileged: true
        runAsUser: 0
        capabilities:
          add: ["CAP_SYS_BOOT"]
  volumes:
    - name: data-volume
      hostPath:
        path: /data
This pod runs as a privileged user with root access, has the CAP_SYS_BOOT capability (which allows rebooting the host), and mounts the host filesystem — all of which are insecure configurations.
1

Create a Pod Security Policy

Define a PSP to block the insecure configurations above:
pod-security-policy.yaml
apiVersion: policy/v1beta1
kind: PodSecurityPolicy
metadata:
  name: restricted-psp
spec:
  privileged: false
  seLinux:
    rule: RunAsAny
  runAsUser:
    rule: MustRunAsNonRoot
  fsGroup:
    rule: RunAsAny
  supplementalGroups:
    rule: RunAsAny
  volumes:
    - 'persistentVolumeClaim'
  requiredDropCapabilities:
    - 'CAP_SYS_BOOT'
  defaultAddCapabilities:
    - 'CAP_SYS_TIME'
This policy:
  • Rejects pods with privileged: true
  • Rejects pods running as runAsUser: 0 (root)
  • Rejects pods using hostPath volumes (only persistentVolumeClaim is permitted)
  • Rejects pods with the CAP_SYS_BOOT capability
  • Adds CAP_SYS_TIME to all pods by default, even if not specified
2

Authorize the Pod Security Policy with RBAC

Enabling the PSP admission controller alone is not enough. Without authorizing service accounts to use a PSP, the admission controller cannot communicate with the security policies API and will reject all pod creation requests.Every pod has a service account (defaulting to default in the namespace). Create a Role and RoleBinding to let the default service account use the PSP:
role.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: psp-role
rules:
  - apiGroups: ['policy']
    resources: ['podsecuritypolicies']
    resourceNames: ['restricted-psp']
    verbs: ['use']
3

Create a pod that complies with the policy

sample-pod.yaml
apiVersion: v1
kind: Pod
metadata:
  name: sample
spec:
  containers:
    - name: ubuntu
      image: ubuntu
      securityContext:
        privileged: false
        runAsUser: 1000
  volumes:
    - name: data-volume
      persistentVolumeClaim:
        claimName: my-pvc

Build docs developers (and LLMs) love