# Demonstration: A Pod Before and After Hardening ## Before: the default, unhardened Pod ```yaml apiVersion: v1 kind: Pod metadata: name: app-unhardened spec: containers: - name: app image: myapp:latest ``` Checking what this actually runs as: ``` $ kubectl exec app-unhardened -- id uid=0(root) gid=0(root) groups=0(root) $ kubectl exec app-unhardened -- touch /etc/anything-i-want $ kubectl exec app-unhardened -- ls -la /etc/anything-i-want -rw-r--r-- 1 root root 0 Jan 1 00:00 /etc/anything-i-want ``` Running as root, with a fully writable filesystem, including system directories. This is not a misconfiguration — it's simply what happens when nothing restricts it. ## After: the same application, hardened ```yaml apiVersion: v1 kind: Pod metadata: name: app-hardened spec: securityContext: runAsNonRoot: true runAsUser: 1000 containers: - name: app image: myapp:latest securityContext: readOnlyRootFilesystem: true capabilities: drop: ["ALL"] ``` ``` $ kubectl exec app-hardened -- id uid=1000 gid=0 groups=0 $ kubectl exec app-hardened -- touch /etc/anything-i-want touch: /etc/anything-i-want: Read-only file system ``` Same application image, same functionality (assuming the app doesn't itself require root or filesystem writes it wasn't told about) — but a compromise of this container now can't write to the filesystem, can't use the elevated capabilities that were dropped, and never had root to begin with. ## What this actually buys you Nothing here fixed a bug in `myapp:latest` — the image is identical in both cases. What changed is what an attacker (or a bug behaving unexpectedly) could DO if something inside that container went wrong. The unhardened version had almost no limits; the hardened version has several independent ones, any of which alone would have blocked the `touch` command above. ## Instructor Notes **Demo script:** Run both Pods live if time allows — watching `touch` succeed on one and fail on the other in real time is far more convincing than reading it. **Approximate timing:** 8-10 minutes live; 5-7 minutes self-paced. **Common misconception to preempt:** students sometimes read the hardened Pod's failed `touch` as "hardening broke something." Reinforce: the FUNCTIONALITY didn't change (the application itself never needed to write to `/etc`) — only an unnecessary, unused capability was removed. If hardening breaks something the application genuinely needs, that's real information about the application, not a reason to skip hardening. **Optional extension:** ask what would happen if `myapp:latest` were built assuming it could write a cache file to `/tmp` inside the container — a good bridge to the fact that `readOnlyRootFilesystem` often needs an explicit `emptyDir` volume mounted at the specific path an application legitimately needs to write to (ROOT 08), rather than being an all-or-nothing choice.