17 - Pod & Workload Security
Why this matters
Even a hardened cluster is exposed if any pod can run privileged, mount the host filesystem, or escalate to root. This is the layer that stops container breakout.
Read this first — Definitions & Explanations
Run as non-root
Containers should not run as UID 0 unless absolutely required. Reduces blast radius if compromised.
Pod Security Admission (PSA)
Built-in admission that enforces Pod Security Standards profiles (privileged, baseline, restricted) per namespace.
allowPrivilegeEscalation: false
Prevents a process from gaining more privileges than its parent (important hardening flag).
readOnlyRootFilesystem
Makes container root filesystem read-only so malware can’t easily write binaries to disk (app must support it).
Capabilities / seccomp / AppArmor
Drop Linux capabilities you don’t need; use seccomp/AppArmor profiles to restrict syscalls and behavior.
Official docs (read for detail)
- Pod Security Standards
- Pod Security Admission
- Security Context
- Configure a Security Context for a Pod or Container
Key Concepts
- securityContext (pod-level and container-level):
runAsNonRoot,runAsUser,readOnlyRootFilesystem,allowPrivilegeEscalation,capabilities.drop - Pod Security Admission (PSA): replaced PodSecurityPolicy —
privileged,baseline,restrictedlevels, enforced via namespace labels - Privileged containers, hostPath, hostNetwork, hostPID/hostIPC — why each is dangerous
- Linux capabilities — drop
ALL, add back only what's needed - seccomp profiles — syscall filtering
- AppArmor / SELinux — mandatory access control (know they exist, deep dive is optional)
YouTube search terms
- "Kubernetes Pod Security Admission explained restricted baseline privileged"
- "Kubernetes securityContext explained runAsNonRoot capabilities"
- "Kubernetes seccomp profiles explained"
- "Container breakout Kubernetes privileged pods"
Hands-on lab (on prod-sim)
# Enforce restricted PSA on a namespace
kubectl create namespace locked-down
kubectl label namespace locked-down \
pod-security.kubernetes.io/enforce=restricted \
pod-security.kubernetes.io/enforce-version=latest
# Try to run a privileged pod — should be REJECTED outright
kubectl run priv --image=nginx -n locked-down --overrides='
{"spec":{"containers":[{"name":"priv","image":"nginx","securityContext":{"privileged":true}}]}}'
# expect: Error from server (Forbidden): violates PodSecurity "restricted:latest"
# Try a compliant pod
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
name: safe-pod
namespace: locked-down
spec:
securityContext:
runAsNonRoot: true
runAsUser: 1000
seccompProfile:
type: RuntimeDefault
containers:
- name: safe-pod
image: nginx
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop: ["ALL"]
ports:
- containerPort: 8080
EOF
kubectl get pod safe-pod -n locked-down # should succeed (nginx may still fail readOnlyRootFS at runtime — that's the point, dig into why)
# Compare: same "safe-pod" spec in default (privileged) namespace works, but in `locked-down` you had to think about every setting
kubectl describe pod safe-pod -n locked-down | grep -A10 Events
# hostPath / hostNetwork abuse demo (should also be blocked under restricted)
kubectl run hostnet --image=nginx -n locked-down --overrides='{"spec":{"hostNetwork":true,"containers":[{"name":"hostnet","image":"nginx"}]}}'
Notes
(fill in your own words after watching + labbing)