A container is a process, not a VM — it shares the host kernel. Understand what isolates a container, what does not, and where the attack surface really is before you try to secure it.
Containers feel like tiny machines but are just host processes with restricted visibility, created by kernel features — namespaces (what the process can see) and cgroups (what it can use). Crucially, all containers share the one host kernel. That single fact drives container security: a kernel exploit or a misconfigured container can cross the boundary that a true VM would hold.
VM Container
guest OS + own kernel shares the HOST kernel
hardware-level isolation process isolation via kernel features
heavy, slow to start light, starts in ms
strong boundary boundary is only as strong as the
kernel + how you configured the container
Isolation is provided by:
namespaces -> what the process SEES (pids, net, mounts, users)
cgroups -> what the process can USE (cpu, memory)
capabilities/seccomp/LSM -> what the process can DO to the kernel
Weaken any of these and the "box" leaks onto the host.Threats span the whole container lifecycle, not just the running process. A vulnerable dependency in the image, a secret baked into a layer, an over-privileged runtime, a compromised registry, and a permissive orchestrator each open a different door. Mapping them tells you which lesson addresses which risk.
Where containers get attacked -> where we defend it:
vulnerable packages in the image -> hardening + scanning (L2, L3)
secrets baked into layers -> hardening (L2)
running as root / too many caps -> runtime hardening (L4)
container escape to the host -> runtime hardening (L4)
over-broad cluster permissions -> RBAC (L5)
pod-to-pod lateral movement -> NetworkPolicy (L5)
malicious/unsigned image scheduled -> admission control (L6)
malware running in a live container -> runtime detection - Falco (L6)Container escapes are not magic — they follow from specific misconfigurations. A privileged container, a mounted host path or Docker socket, or a dangerous capability turns "code runs in a container" into "code runs on the node." Knowing the common escape paths tells you exactly which defaults to forbid.
Classic escape paths (each is a config you can forbid):
--privileged -> nearly all isolation off; direct host access
mount /var/run/docker.sock -> control the daemon = own every container + host
mount hostPath: / -> read/write the node's filesystem
cap CAP_SYS_ADMIN -> mount, alter namespaces, often => escape
runs as root (uid 0) -> a bug becomes root-on-host if it escapes
None of these are needed by a normal app. The defense is to make
them impossible by policy (lessons 4-6), not to hope nobody sets them.Every control in this course serves three ideas. Minimize what is in the container (smaller image = fewer vulns, no shell for an attacker). Grant least privilege at runtime (no root, no extra capabilities, read-only where possible). And verify what runs (scan, sign, admit only trusted images). Hold these and most container attacks have nowhere to land.
Three rules that prevent most container incidents:
MINIMAL ship only the app + its runtime. No shell, no
package manager, no curl for the attacker to use.
LEAST PRIVILEGE non-root, drop all capabilities, read-only rootfs,
no host mounts. A bug then can't do much.
VERIFIED only scanned + signed images from trusted sources
are allowed to run (admission control).
The rest of this course is these three rules made concrete.