Skip to main content
RunBook Academy

KubernetesXIV · Namespace ArchitectureTenancy and isolation

Pod Security Standards per namespace — restricted, baseline, privileged

Advanced⏱ ~16 minkubectl

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

Not yet marked complete on this device.

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., via kubectl apply output).

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: true
  • hostPath volumes (some types)
  • hostPorts (other than specific allowed ranges)
  • privileged: true containers
  • Specific dangerous capabilities (e.g., SYS_ADMIN)
  • procMount other than Default
  • Specific volume types (e.g., hostPath)

Restricted adds:

  • runAsNonRoot: true required
  • allowPrivilegeEscalation: false required
  • capabilities.drop: ["ALL"] required
  • seccompProfile.type must be RuntimeDefault or Localhost
  • runAsUser must be non-zero (or runAsNonRoot: 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:

  1. Identify PSP usage: list all Pods and check for PSP- controlled capabilities.
  2. Map PSP rules to PSS levels: most PSPs map to baseline or restricted.
  3. Add PSS labels to namespaces: start with audit mode to log violations.
  4. Verify no violations: review audit logs; fix workloads that violate PSS.
  5. Switch to warn mode: developers see warnings on kubectl apply.
  6. Switch to enforce mode: 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: true and runAsUser: <non-zero> to the securityContext.
  • Init containers with privileged operations: a database migration that needs SYS_ADMIN. Solution: redesign the migration to run without SYS_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-Hardening covers capability dropping and seccomp; PSS restricted is the cluster-level equivalent.
  • The Docker course part LIX-Docker-Hardening covers container hardening; PSS is the cluster-level equivalent.
  • The Ansible course part XLIX-Ansible-Compliance covers compliance policies; PSS is the cluster-level equivalent.

Quiz

Knowledge check · 4 questions

  1. Q1. Which Pod Security Standards level requires `runAsNonRoot: true` and `capabilities.drop: ["ALL"]`?

  2. Q2. Pod Security Standards are enforced at the Pod level, declared in the Pod's securityContext.

  3. 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`.

  4. 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 restricted on production namespaces. The most secure level; prevents common container escapes.
  • Use baseline only 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 audit mode to surface violations; fix them; then enforce.
  • Document PSS levels and exceptions. Each namespace’s PSS level should be intentional; exceptions need security review.