Hardening MiniDock
In one sentence: Production hardening matches one mitigation to each link of the attack chain — verify what you run (digest pinning, scanning, signing), constrain what it can do (user remap, read-only rootfs, no new privileges), and contain what it can reach (segmentation, secrets off disk).
You already know
- From Lesson 6: capabilities, seccomp, LSM — the default sandwich around every container.
- From Lesson 8: digests make content verifiable; from Lesson 28: absent edges are unreachability.
Before it runs: trust the bytes
Most compromises arrive in the image, not through the kernel. Three gates: pin digests — deploy image@sha256:…, not a mutable tag someone can quietly repoint (Lesson 17's mutable-pointer risk, weaponized); scan layers against vulnerability databases before promotion; verify signatures so only images signed by your build system are admitted. All three are pull-time policies bolted onto machinery you already designed in Parts 2–3.
While it runs: assume breach
Layer the runtime so a compromised app is a disappointing prize. User-namespace remap (Lesson 4): container-root maps to an unprivileged host UID, so an escape lands without privileges. Read-only rootfs: the overlay upper becomes immutable; the app writes only to declared volumes and tmpfs — malware can't persist itself. no-new-privileges: setuid binaries can't re-escalate. Network segmentation (Lesson 28) bounds lateral movement; tmpfs secrets (Lesson 25) keep credentials off every disk and out of every image layer.
flowchart TB A1["attacker publishes
poisoned image tag"] -- "blocked by" --> D1["digest pinning +
signature verification"] A2["known CVE in a layer"] -- "blocked by" --> D2["pre-deploy scanning"] A3["app exploited at runtime"] -- "contained by" --> D3["read-only rootfs +
no-new-privileges"] A4["escape to host"] -- "lands unprivileged via" --> D4["user-ns remap +
L6 sandwich"] A5["lateral movement"] -- "bounded by" --> D5["network segmentation (L28)"] A6["credential theft from disk"] -- "prevented by" --> D6["tmpfs-only secrets (L25)"]
sequenceDiagram participant A as Attacker participant R as Registry participant E as Hardened engine A->>R: repoint tag web:stable at poisoned manifest E->>R: pull web@sha256:9f3c… (pinned digest, ignores the tag) R-->>E: the ORIGINAL manifest — tags can lie, digests can't E->>E: signature check: signed by our CI ✓ note over E: even if forced to use tags, the unsigned
poisoned manifest fails admission
Anchor these
- Verify bytes before run; constrain behavior during run; bound reach after breach.
- Tags are attack surface — production deploys pin digests.
- Every hardening knob reuses a mechanism from earlier lessons; security is configuration of good architecture.
See what actually stuck.
Take the practice scenarios now.