Skip to main content
RunBook Academy

KubernetesLXII · Pod Security StandardsPod Security Standards

Pod Security Standards — overview of the three profiles

Advanced⏱ ~14 minkubectl

What you'll learn

  • Explain the three PSS profiles and what each one allows
  • Distinguish PSS from PodSecurityPolicy (deprecated) and from OPA/Kyverno
  • Identify the production pattern of enforcing `restricted` cluster-wide
  • Recognise the failure modes (too-strict enforcement, too-loose audit)

Prerequisites

Verified against Kubernetes 1.34.x · kubeadm 1.34.x · kubectl 1.34.x · etcd 3.6.x · CoreDNS 1.11.x · containerd 1.7.x / 2.x · 2026-08-16

Not yet marked complete on this device.

Pod Security Standards (PSS) is the built-in declarative policy for Pods. Three profiles — privileged, baseline, restricted — define what a Pod can do. This lesson covers what each profile allows, the relationship to deprecated alternatives (PodSecurityPolicy, PSP), and the production pattern.

The three profiles

The profiles are cumulative: restricted is a strict subset of baseline, which is a strict subset of privileged. A workload that passes restricted passes baseline and privileged; a workload that fails restricted may pass baseline.

ProfilePurposeUse case
PrivilegedNo restrictionsSystem workloads that need full access
BaselinePrevents known privilege escalationsUntrusted code; multi-tenant clusters
RestrictedMinimum-allowTrusted workloads; production
flowchart LR
    A[Privileged] --> B[Baseline]
    B --> C[Restricted]
    A -.any workload allowed.-> P[OK]
    B -.most workloads allowed.-> P
    C -.hardened workloads only.-> P

What each profile forbids

FieldPrivilegedBaselineRestricted
privilegedAllowedForbiddenForbidden
hostNetworkAllowedForbiddenForbidden
hostPIDAllowedForbiddenForbidden
hostIPCAllowedForbiddenForbidden
hostPath volumesAllowedAllowed (limited)Forbidden
capabilitiesAllLimitedDrop ALL, add only NET_BIND_SERVICE
runAsUserAnyAnyMust not be 0
runAsNonRootAnyAnyRequired true
allowPrivilegeEscalationAnyAnyRequired false
Volume typesAnyAnyOnly configMap, csi, downwardAPI, emptyDir, ephemeral, persistentVolumeClaim, projected, secret
seccompProfileAnyAnyRuntimeDefault or Localhost
appArmorProfileAnyAnyRuntimeDefault or Localhost

The restricted profile is the production target; it forbids every common privilege escalation path.

readOnlyRootFilesystem is deliberately absent from this table. It is a valuable hardening setting, but it is not part of baseline or restricted and the Pod Security admission controller never checks it. If you want it enforced, that is a job for a policy engine such as Kyverno or Gatekeeper, not for a namespace label.

Enforcement modes

PSS is enforced via the PodSecurity admission controller, which is enabled by default in 1.34. The controller reads namespace labels:

  • pod-security.kubernetes.io/enforce: privileged|baseline|restricted — the enforced profile. Pods that violate are rejected.
  • pod-security.kubernetes.io/audit: privileged|baseline|restricted — the audit profile. Violations are logged in the audit log; Pods are not rejected.
  • pod-security.kubernetes.io/warn: privileged|baseline|restricted — the warn profile. Violations produce a warning event; Pods are not rejected.

A namespace can have all three labels. A typical configuration:

metadata:
  name: prod
  labels:
    pod-security.kubernetes.io/enforce: restricted
    pod-security.kubernetes.io/audit: restricted
    pod-security.kubernetes.io/warn: restricted

All three modes use restricted. Violations are rejected, logged, and warned.

Relationship to PodSecurityPolicy (PSP)

PSP was the predecessor to PSS, deprecated in 1.21 and removed in 1.25. The differences:

AspectPSPPSS
ConfigurationCustom CRDBuilt-in profiles
OrderMutatingValidating (read-only)
DefaultCluster-widePer-namespace via labels
ExpressivenessCustom rulesThree fixed profiles

PSS is the simpler, less expressive successor. Custom rules beyond PSS require OPA/Kyverno.

A privileged Pod (privileged profile)

A Pod that would pass privileged but fail restricted:

apiVersion: v1
kind: Pod
metadata:
  name: legacy-app
  namespace: legacy
spec:
  containers:
  - name: app
    image: legacy:v1.0
    securityContext:
      privileged: true          # privileged profile: OK
      runAsUser: 0              # privileged: OK
    volumeMounts:
    - name: host-vol
      mountPath: /host
  volumes:
  - name: host-vol
    hostPath:
      path: /                    # hostPath: privileged OK

The Pod is allowed in legacy (a namespace with enforce: privileged); rejected in prod (with enforce: restricted).

A baseline Pod (baseline profile)

A Pod that passes baseline but fails restricted:

apiVersion: v1
kind: Pod
metadata:
  name: standard-app
  namespace: standard
spec:
  containers:
  - name: app
    image: standard:v1.0
    securityContext:
      runAsUser: 0              # baseline: allowed (UID 0)
      capabilities:
        add: ["SYS_ADMIN"]      # baseline: limited; SYS_ADMIN may pass

The Pod is allowed in standard (enforce: baseline); rejected in prod (enforce: restricted).

A restricted Pod (restricted profile)

A Pod that passes restricted:

apiVersion: v1
kind: Pod
metadata:
  name: hardened-app
  namespace: prod
spec:
  securityContext:
    runAsNonRoot: true
    runAsUser: 1000
    seccompProfile:
      type: RuntimeDefault
  containers:
  - name: app
    image: myapp:v1.0
    securityContext:
      allowPrivilegeEscalation: false
      readOnlyRootFilesystem: true
      capabilities:
        drop: ["ALL"]

The Pod is allowed in prod (enforce: restricted).

Production patterns

  1. restricted cluster-wide. Every production namespace has enforce: restricted. Exceptions (privileged, baseline) are explicit and documented.
  2. Audit + warn + enforce. All three modes use restricted; violations are rejected, logged, and warned.
  3. Migration to restricted. New namespaces use restricted from creation; existing namespaces use warn or audit first, then switch to enforce.

Production failure modes

  1. privileged is the default. A namespace was created with enforce: privileged (or no label); the cluster’s workloads run with full access. The fix is to set enforce: restricted.
  2. warn instead of enforce. Violations are warned but allowed; the policy is advisory. The fix is to use enforce.
  3. No audit mode. Violations are not in the audit log; the SIEM does not see them. The fix is to use audit for compliance.
  4. Exceptions are not documented. A namespace uses privileged because of a legacy workload; the team does not know about it. The fix is to document every exception.

Cross-course references

  • The Observability course covers the audit log entries for PSS violations.
  • The Linux course covers the kernel features (capabilities, seccomp, namespaces) that PSS enforces.

Quiz

Knowledge check · 4 questions

  1. Q1. Which Pod Security Standards profile should production namespaces enforce by default?

  2. Q2. Pod Security Standards (PSS) is the successor to PodSecurityPolicy (PSP), which was deprecated in 1.21 and removed in 1.25.

  3. Q3. Your cluster has 80 namespaces, all with `pod-security.kubernetes.io/enforce: baseline`. The security team wants to enforce `restricted` cluster-wide. Walk the migration plan.

    The cluster has 80 namespaces with `enforce: baseline`. Most workloads run as root (`runAsUser: 0`), use `hostPath` volumes, and have no `seccompProfile`. The team wants `restricted` but cannot break the workloads in one shot.

  4. Q4. Name the three PSS modes (enforce, audit, warn) and what each one does.

Passing score: 75%. Answers are checked in this browser.

Production discipline

A defensible PSS programme enforces restricted in every production namespace, with audit and warn also set to restricted. Exceptions (privileged, baseline) are explicit, documented, and reviewed quarterly. The audit log records every violation; the SIEM alerts on the violations. A cluster whose PSS is restricted everywhere has a workload security programme that is auditable; a cluster whose PSS is privileged everywhere has a programme that is not.