Skip to main content

Overview

Pod Security Policy (PSP) and Pod Security Admission (PSA) were introduced by the Kubernetes Auth Special Interest Group (SIG) to govern pod security in Kubernetes clusters.
Pod Security Policy (PSP) was deprecated in Kubernetes v1.21 and removed in v1.25. It is replaced by Pod Security Standards (PSS) combined with Pod Security Admission (PSA). PSS profiles can be used with any PSA mode.

Pod Security Standards (PSS)

PSS defines three security profiles:
ProfileRestrictivenessDescription
privilegedUnrestrictedAllows all capabilities and does not restrict any security context settings. Allows privilege escalation. Suitable for system-wide programs like logging agents and storage drivers.
baselineRestrictedRestricts certain capabilities (e.g., hostPath, hostNetwork, hostIPC, hostPID) and encourages security context settings like readOnlyRootFilesystem and runAsNonRoot. Prevents known privilege escalations. Suitable for most workloads.
restrictedHighly restrictedEnforces strict security measures: disallows privilege escalation, requires runAsNonRoot, restricts host namespace and hostPath volume access. Follows pod hardening best practices. Suitable for high-security workloads.

Pod Security Admission (PSA)

PSA is a built-in admission controller that enforces Pod Security Standards. It is enabled by default in Kubernetes v1.25 and later. Verify it is enabled by checking the kube-apiserver arguments for PodSecurity in --enable-admission-plugins:
kube-apiserver.yaml
- kube-apiserver
  - --enable-admission-plugins=NodeRestriction,PodSecurity
PSA has three enforcement modes:
ModeDescriptionOn violation
enforceRejects pods that do not meet the policyPod is rejected
auditRecords violations in audit logs; pods are allowed to runRecorded in audit logs
warnDisplays a warning to the user; pods are allowed to runWarning message displayed

PSA exemptions

You can configure exemptions so that specific users, runtime classes, or namespaces bypass Pod Security Admission enforcement entirely (all modes are skipped for exempted subjects).
Exemption dimensionDescription
UsernamesRequests from specified authenticated (or impersonated) usernames are ignored
RuntimeClassNamesRequests for pods with a specified RuntimeClass are ignored
NamespacesRequests for pods in specified namespaces are ignored
1

Configure the admission controller

/etc/kubernetes/admission-config.yaml
apiVersion: apiserver.config.k8s.io/v1
kind: AdmissionConfiguration
plugins:
- name: PodSecurity
  configuration:
    apiVersion: pod-security.admission.config.k8s.io/v1
    kind: PodSecurityConfiguration
    defaults:
      enforce: "privileged"
      enforce-version: "latest"
      audit: "privileged"
      audit-version: "latest"
      warn: "privileged"
      warn-version: "latest"
    exemptions:
      usernames: []
      runtimeClasses: []
      namespaces: []
2

Pass the configuration to kube-apiserver

kube-apiserver.yaml
- kube-apiserver
  - --enable-admission-plugins=NodeRestriction,PodSecurity
  - --admission-control-config-file=/etc/kubernetes/admission-config.yaml

Using PSS and PSA together

1

Label the namespace with a mode and profile

If no labels are set on a namespace, the default policy is privileged.
Changing namespace labels affects existing pods by re-evaluating them against the new policy and returning violations as warnings. Existing pods that violate an enforce policy will not be terminated, but new pods violating the policy will be rejected.
kubectl label namespace <ns> pod-security.kubernetes.io/<mode>=<profile>

# Examples
kubectl label namespace prod pod-security.kubernetes.io/enforce=restricted
kubectl label namespace dev pod-security.kubernetes.io/warn=baseline

# Apply multiple labels
kubectl label namespace staging \
  pod-security.kubernetes.io/audit=baseline \
  pod-security.kubernetes.io/warn=baseline
2

Create pods that comply with the namespace profile

privileged-pod.yaml
apiVersion: v1
kind: Pod
metadata:
  name: privileged-pod
  namespace: privileged-namespace
spec:
  containers:
    - name: privileged-container
      image: nginx:latest
      securityContext:
        privileged: true
        allowPrivilegeEscalation: true
        capabilities:
          add: ["ALL"]
Appropriate for workloads requiring full host access, such as system daemons or monitoring agents.

Build docs developers (and LLMs) love