KubernetesXIV · Namespace ArchitectureTenancy and isolation
Pod Security Standards per namespace — restricted, baseline, privileged
What you'll learn
- Configure Pod Security Standards (restricted, baseline, privileged) per namespace
- Distinguish the three PSS levels and what each allows
- Migrate from PodSecurityPolicy (deprecated) to PSS
- Audit namespaces for PSS compliance
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
Pod Security Standards (PSS) are the namespace-level admission control that enforces security policies at Pod-creation time. This lesson covers the three levels, the namespace labels that activate them, and the migration from the deprecated PodSecurityPolicy.
The three PSS levels
# Privileged: no restrictions
apiVersion: v1
kind: Namespace
metadata:
name: kube-system
labels:
pod-security.kubernetes.io/enforce: privileged
pod-security.kubernetes.io/enforce-version: latest
# Baseline: minimal restrictions
---
apiVersion: v1
kind: Namespace
metadata:
name: monitoring
labels:
pod-security.kubernetes.io/enforce: baseline
pod-security.kubernetes.io/enforce-version: latest
# Restricted: hardened baseline
---
apiVersion: v1
kind: Namespace
metadata:
name: prod
labels:
pod-security.kubernetes.io/enforce: restricted
pod-security.kubernetes.io/enforce-version: latest
Three levels (least to most restrictive):
- Privileged: no restrictions. Pods can run as root,
with host namespaces, with all capabilities. Use only
for system namespaces (
kube-system, etc.). - Baseline: minimal restrictions. Prevents known privilege escalations. Pods cannot use host namespaces or dangerous capabilities. Default for most namespaces.
- Restricted: hardened baseline. Runs as non-root, drops capabilities, read-only root filesystem. The production standard.
The PSS namespace labels
PSS is activated by namespace labels:
pod-security.kubernetes.io/enforce: restricted # enforce; reject if violated
pod-security.kubernetes.io/enforce-version: latest # which PSS version
pod-security.kubernetes.io/audit: restricted # log violations
pod-security.kubernetes.io/audit-version: latest
pod-security.kubernetes.io/warn: restricted # warn the user
pod-security.kubernetes.io/warn-version: latest
Three modes per label:
enforce: reject Pods that violate the policy.audit: allow Pods but log violations to the API server audit log.warn: allow Pods but display a warning to the user (e.g., viakubectl applyoutput).
Production discipline: use enforce: restricted on
production namespaces; use audit: restricted and
warn: restricted on dev namespaces to alert developers
to violations.
What each level restricts
Baseline blocks:
hostPID: true,hostIPC: true,hostNetwork: truehostPathvolumes (some types)hostPorts(other than specific allowed ranges)privileged: truecontainers- Specific dangerous capabilities (e.g.,
SYS_ADMIN) procMountother thanDefault- Specific volume types (e.g.,
hostPath)
Restricted adds:
runAsNonRoot: truerequiredallowPrivilegeEscalation: falserequiredcapabilities.drop: ["ALL"]requiredseccompProfile.typemust beRuntimeDefaultorLocalhostrunAsUsermust be non-zero (orrunAsNonRoot: true)- Volumes restricted to configMap, csi, downwardAPI, emptyDir, ephemeral, persistentVolumeClaim, projected and secret
readOnlyRootFilesystem is not on either list. It is
worth setting, but Pod Security admission does not check
it under any profile — enforcing it needs a policy
engine.
flowchart LR
Privileged[Privileged] --> Baseline[Baseline]
Baseline --> Restricted[Restricted]
Baseline -.->|"blocks hostPID, hostPath, hostNetwork"| Baseline
Restricted -.->|"adds runAsNonRoot, drop ALL caps"| Restricted
The progression: each level adds restrictions. A Pod that passes restricted passes baseline; a Pod that passes baseline passes privileged.
Production patterns
Production namespace with restricted:
apiVersion: v1
kind: Namespace
metadata:
name: team-a-prod
labels:
pod-security.kubernetes.io/enforce: restricted
pod-security.kubernetes.io/enforce-version: latest
pod-security.kubernetes.io/audit: restricted
pod-security.kubernetes.io/warn: restricted
All three modes (enforce, audit, warn) set to restricted. The namespace is locked down.
Staging with warn only:
apiVersion: v1
kind: Namespace
metadata:
name: team-a-staging
labels:
pod-security.kubernetes.io/warn: restricted
pod-security.kubernetes.io/audit: restricted
Staging allows violations (no enforce) but warns the user
and audits. Production data flows through staging first; any
PSS violations are visible to operators.
Namespace for node agents:
apiVersion: v1
kind: Namespace
metadata:
name: monitoring
labels:
pod-security.kubernetes.io/enforce: baseline
pod-security.kubernetes.io/enforce-version: latest
Monitoring agents may need hostPath or other baseline-
violating capabilities; baseline allows them.
Migrating from PodSecurityPolicy
PodSecurityPolicy (PSP) was deprecated in Kubernetes 1.21 and removed in 1.25. PSS is the replacement. The migration:
- Identify PSP usage: list all Pods and check for PSP- controlled capabilities.
- Map PSP rules to PSS levels: most PSPs map to
baselineorrestricted. - Add PSS labels to namespaces: start with
auditmode to log violations. - Verify no violations: review audit logs; fix workloads that violate PSS.
- Switch to
warnmode: developers see warnings onkubectl apply. - Switch to
enforcemode: violations are rejected.
stateDiagram-v2
[*] --> Audit
Audit --> Warn: no violations
Warn --> Enforce: developers adapt
Enforce --> [*]
Production discipline: migrate in stages. Start with audit to surface violations; fix them; then enforce.
Auditing PSS compliance
# Check PSS level for each namespace
kubectl get namespaces -o custom-columns=NAME:.metadata.name,ENFORCE:.metadata.labels.pod-security\.kubernetes\.io/enforce
# Find Pods that violate restricted (in audit/warn mode)
kubectl get pods -A -o json | \
jq '.items[] | select(.metadata.namespace != null) | select(.spec.containers[].securityContext.runAsNonRoot != true) | .metadata.namespace + "/" + .metadata.name'
The second command finds Pods without runAsNonRoot: true
in any container — a PSS restricted violation.
# Audit log entries for PSS violations
# (requires API server audit logging configured)
apiserver_audit_event{verb="create",objectRef.resource="pods",level="Request"}
Production discipline: monitor audit logs for PSS violations; fix them before switching to enforce mode.
Pods that don’t pass restricted
Common production workloads that violate restricted:
- Database images that run as root: many database images
default to root. Solution: add
runAsNonRoot: trueandrunAsUser: <non-zero>to the securityContext. - Init containers with privileged operations: a database
migration that needs
SYS_ADMIN. Solution: redesign the migration to run withoutSYS_ADMIN. - Sidecars with hostPath volumes: log shippers that read
/var/log. Solution: use a different logging approach (stdout/stderr, node-level log shipper).
For each violation, the fix is usually either (a) modify the workload to comply, or (b) move the workload to a namespace with baseline enforcement.
Cross-course references
- The Linux course part
XXIX-Linux-Hardeningcovers capability dropping and seccomp; PSS restricted is the cluster-level equivalent. - The Docker course part
LIX-Docker-Hardeningcovers container hardening; PSS is the cluster-level equivalent. - The Ansible course part
XLIX-Ansible-Compliancecovers compliance policies; PSS is the cluster-level equivalent.
Quiz
Knowledge check · 4 questions
Q1. Which Pod Security Standards level requires `runAsNonRoot: true` and `capabilities.drop: ["ALL"]`?
Q2. Pod Security Standards are enforced at the Pod level, declared in the Pod's securityContext.
Q3. A team's Deployment worked fine with PSS `baseline` enforcement. After switching the namespace to `restricted`, the Deployment's Pods are rejected. Diagnose and remediate.
Namespace `team-a-prod` previously had `pod-security.kubernetes.io/enforce: baseline`. After upgrading to `restricted`, all Pods are rejected with messages like `violates PodSecurity "restricted:latest": runAsNonRoot=true required`.
Q4. How do you migrate a cluster from PodSecurityPolicy (PSP) to Pod Security Standards (PSS)?
Passing score: 75%. Answers are checked in this browser.
Production discipline
- Enforce
restrictedon production namespaces. The most secure level; prevents common container escapes. - Use
baselineonly for system namespaces that need additional privileges (kube-system, monitoring). - Migrate to PSS from PSP. PSP is removed in 1.25+; PSS is the replacement.
- Audit PSS compliance before enforcing. Use
auditmode to surface violations; fix them; then enforce. - Document PSS levels and exceptions. Each namespace’s PSS level should be intentional; exceptions need security review.