Pod Security
|
This content was generated with the assistance of AI and should be verified against the official documentation before being relied on in production; see the section bibliography for the reference material consulted while preparing these pages. |
A container is a process on a shared kernel, so what that process is allowed to do — which user it runs as, which Linux
capabilities it holds, which system calls it may make — decides how much damage a compromised application can cause.
Kubernetes exposes those controls through the securityContext field and enforces cluster-wide minimums through Pod
Security Admission. This page is written against Kubernetes 1.37; see
the section index for the version baseline. Who may call the API is covered separately
in Authentication, Authorization and RBAC.
securityContext
securityContext exists at two levels: on the Pod (spec.securityContext, applying to all containers and volumes) and
on each container (spec.containers[].securityContext, overriding the Pod for that container).
| Field | Effect |
|---|---|
|
The kubelet refuses to start a container whose image would run as UID 0. |
|
Numeric UID/GID of the container process. Use a non-zero value that matches the image. |
|
Group ownership applied to supported volumes so a non-root process can write to them (Pod level). Together with
|
|
Extra group IDs for the process. |
|
The image filesystem is read-only; give the application writable |
|
Sets |
|
Removes every Linux capability; add back only specific ones (for example |
|
Gives near-host access. Avoid. |
|
Applies the container runtime’s default system-call filter. |
|
Selects an AppArmor profile ( |
|
SELinux label (level, role, type, user) on hosts that use SELinux. |
apiVersion: apps/v1
kind: Deployment
metadata:
name: catalog-api
namespace: bookshelf
spec:
replicas: 2
selector:
matchLabels:
app: catalog-api
template:
metadata:
labels:
app: catalog-api
spec:
securityContext:
runAsNonRoot: true
runAsUser: 10001
runAsGroup: 10001
fsGroup: 10001
seccompProfile:
type: RuntimeDefault
containers:
- name: catalog-api
image: ghcr.io/example/bookshelf-catalog-api:1.0.0
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop: ["ALL"]
volumeMounts:
- name: tmp
mountPath: /tmp
volumes:
- name: tmp
emptyDir: {}
kubectl exec deploy/catalog-api -n bookshelf -- id
kubectl exec deploy/catalog-api -n bookshelf -- touch /etc/probe # fails on a read-only root
uid=10001 gid=10001 groups=10001
touch: /etc/probe: Read-only file system
Pod Security Standards
The Pod Security Standards (PSS) define three cumulative profiles:
| Profile | Meaning |
|---|---|
|
Unrestricted; for system and infrastructure workloads such as CNI or storage drivers. |
|
Blocks known privilege escalations: no |
|
Current hardening best practice: everything in baseline plus non-root, no privilege escalation, capabilities dropped,
|
Pod Security Admission
Pod Security Admission (PSA) is a built-in admission controller, enabled by default, that applies a PSS profile to a
namespace according to labels. Three modes can be set independently, each with an optional -version label to pin the
policy to a Kubernetes release (latest by default):
| Mode label | On violation |
|---|---|
|
Reject the Pod. |
|
Allow, but record an audit-log annotation. |
|
Allow, but return a warning to the client. |
The standard rollout pattern is to warn and audit at the target level first, fix workloads, then enforce.
apiVersion: v1
kind: Namespace
metadata:
name: bookshelf
labels:
pod-security.kubernetes.io/enforce: baseline
pod-security.kubernetes.io/enforce-version: v1.37
pod-security.kubernetes.io/warn: restricted
pod-security.kubernetes.io/warn-version: latest
pod-security.kubernetes.io/audit: restricted
# Dry-run the effect of enforcing "restricted" on an existing namespace
kubectl label --dry-run=server --overwrite ns bookshelf \
pod-security.kubernetes.io/enforce=restricted
Warning: existing pods in namespace "bookshelf" violate the new PodSecurity enforce level "restricted:latest"
Warning: postgres-0: runAsNonRoot != true, seccompProfile
namespace/bookshelf labeled (server dry run)
PSA only checks Pod specs (workload controllers are checked through their Pod templates via warnings) and applies per
namespace; exemptions and a default per-cluster configuration go in an AdmissionConfiguration file. To try the flow on
kind, the official namespace-level and cluster-level tutorials walk through creating a cluster with PSA configured and
deploying compliant and non-compliant Pods. For rules PSA cannot express, see
Admission Control and Policy.
Source: Kubernetes Docs — Apply Pod Security Standards at the Namespace Level. Source: Kubernetes Docs — Apply Pod Security Standards at the Cluster Level.
PodSecurityPolicy is gone
PodSecurityPolicy (PSP) was deprecated in 1.21 and removed in 1.25; any tutorial or book that uses
policy/v1beta1 PSPs is obsolete. Migrate by mapping each PSP to the closest PSS level, enabling PSA in warn/audit
mode, fixing workloads, then switching to enforce; use ValidatingAdmissionPolicy or Kyverno for policies PSS cannot
express.
User namespaces
With hostUsers: false the Pod runs in its own Linux user namespace: UID 0 inside the container maps to an unprivileged
high UID on the host, so a container breakout yields no host root. User-namespace support reached GA in Kubernetes 1.36
(beta and on by default from 1.33). It needs a supported runtime (recent containerd or CRI-O), a kernel with ID-mapped
mounts, and does not combine with hostNetwork, hostPID or hostIPC (host network support was being added under a
separate gate; verify before relying on it). Pods using it can satisfy parts of the restricted profile’s non-root
requirement, which is why the standards treat them specially.
apiVersion: v1
kind: Pod
metadata:
name: importer
namespace: bookshelf
spec:
hostUsers: false
containers:
- name: importer
image: ghcr.io/example/bookshelf-importer:1.0.0
Source: Kubernetes Docs — User Namespaces.
Seccomp and the wider checklist
Enabling seccompProfile: RuntimeDefault on every Pod blocks several dozen rarely needed system calls with very little
compatibility risk; the seccomp tutorial shows custom Localhost profiles on kind. For a production review, work through
the official security checklist (API server and etcd hardening, RBAC, network policies, audit logging, node
configuration) and the application security checklist (secrets, image provenance, least privilege). Related controls
elsewhere in this section: Network Policies for traffic isolation,
Secrets for credentials, and RuntimeClass sandboxes in
Dynamic Resource Allocation and Devices.
Image supply chain
A hardened Pod still runs whatever image it is given. Pin images by digest, scan them, sign and verify them, build from
minimal bases, and run as non-root by construction; the Docker pages cover this in depth (see
Image Best Practices and Security). Admission policy can then
require trusted registries or signatures cluster-wide. The imagePullPolicy and imagePullSecrets mechanics are in
Pods.