Pod Security
Harden containers with SecurityContext and Pod Security Standards.
Time: ~10 minutes Difficulty: Intermediate
What You Will Learn
Section titled “What You Will Learn”- Pod Security Standards: Privileged, Baseline, Restricted
- Pod Security Admission: enforce, warn, audit modes
- SecurityContext: runAsNonRoot, readOnlyRootFilesystem, drop ALL capabilities
- Why running as root is dangerous
- What gets blocked and why
The Three Security Levels
Section titled “The Three Security Levels”| Level | What It Allows |
|---|---|
| Privileged | Everything. No restrictions. |
| Baseline | Blocks known privilege escalations (no privileged containers, no hostNetwork) |
| Restricted | Strictest. Non-root, read-only filesystem, all capabilities dropped. |
Deploy
Section titled “Deploy”Navigate to the demo directory:
cd demos/pod-securityThe namespace enforces baseline and warns on restricted violations:
kubectl apply -f manifests/namespace.yamlTest 1: Privileged Pod (Blocked)
Section titled “Test 1: Privileged Pod (Blocked)”kubectl apply -f manifests/privileged-pod.yamlThis is blocked by the baseline enforcement. Privileged containers can access the host kernel.
Test 2: Insecure Pod (Allowed with Warnings)
Section titled “Test 2: Insecure Pod (Allowed with Warnings)”kubectl apply -f manifests/insecure-pod.yamlThis passes baseline (not privileged) but triggers restricted warnings because it runs as root. Check the warnings in the output.
Verify it runs as root:
kubectl exec insecure-pod -n security-demo -- id# uid=0(root)
kubectl exec insecure-pod -n security-demo -- whoami# rootTest 3: Secure Pod (No Warnings)
Section titled “Test 3: Secure Pod (No Warnings)”kubectl apply -f manifests/secure-pod.yamlNo warnings. This pod follows all restricted requirements:
kubectl exec secure-pod -n security-demo -- id# uid=1000 gid=1000
# Read-only root filesystemkubectl exec secure-pod -n security-demo -- touch /test-file# touch: /test-file: Read-only file system
# /tmp is writable (emptyDir mount)kubectl exec secure-pod -n security-demo -- touch /tmp/test-file# WorksWhat is Happening
Section titled “What is Happening”manifests/ namespace.yaml # Namespace with PSA labels (enforce=baseline, warn=restricted) insecure-pod.yaml # Runs as root, no security hardening secure-pod.yaml # Non-root, read-only FS, all caps dropped privileged-pod.yaml # Privileged container (blocked by baseline)Security settings in the secure pod:
| Setting | What It Does |
|---|---|
runAsNonRoot: true | Prevents running as UID 0 |
runAsUser: 1000 | Sets the user ID |
readOnlyRootFilesystem: true | Container filesystem is read-only |
allowPrivilegeEscalation: false | Blocks setuid/setgid binaries |
capabilities.drop: [ALL] | Removes all Linux capabilities |
seccompProfile: RuntimeDefault | Restricts syscalls to a safe set |
Experiment
Section titled “Experiment”-
Change the namespace to enforce
restricted:Terminal window kubectl label namespace security-demo \pod-security.kubernetes.io/enforce=restricted --overwriteNow the insecure-pod will be blocked too.
-
Check what capabilities a container has:
Terminal window kubectl exec insecure-pod -n security-demo -- cat /proc/1/status | grep Cap -
Reset to baseline:
Terminal window kubectl label namespace security-demo \pod-security.kubernetes.io/enforce=baseline --overwrite
Cleanup
Section titled “Cleanup”kubectl delete namespace security-demoFurther Reading
Section titled “Further Reading”See docs/deep-dive.md for a detailed explanation of Linux capabilities, seccomp profiles, AppArmor, SELinux contexts, and migrating from PodSecurityPolicy to Pod Security Admission.
Next Step
Section titled “Next Step”Move on to kubectl Debug to learn how to troubleshoot running and crashed pods.