fivenines
6/40
Lesson 6 · Foundations

The Security Sandwich

In one sentence: Because containers share the host kernel, the engine wraps every container in stacked filters — dropped capabilities, a seccomp syscall filter, and mandatory access control — so that "root in the container" is far less than root.

You already know

  • From Lesson 2: one shared kernel is the speed win and the security risk.
  • From Lesson 4: the USER namespace can map container-root to an unprivileged host user.

Root, divided and filtered

Modern kernels split root's power into ~40 capabilities (bind low ports, load kernel modules, change file ownership…). A container engine drops most by default and keeps a small safe set — a containerized "root" that can chown its own files but cannot load a kernel module. Below that sits seccomp, a per-process allowlist over the ~350 syscalls the kernel exposes; the default profile blocks the dangerous tail (kernel keyring, raw clock manipulation, obscure module calls). Around everything, an LSM (AppArmor/SELinux) enforces path- and label-based rules. Three independent layers: an attacker must get through all of them.

Architecture — filters between the container and the kernel
flowchart TB
  P["container process
('root' inside)"] CAP["capability check
is this power in the kept set?"] SEC["seccomp filter
is this syscall on the allowlist?"] LSM["LSM policy (AppArmor/SELinux)
may this process touch this path?"] K["kernel executes the call"] P --> SEC --> CAP --> LSM --> K ENG["engine
writes all three policies at create time"] -. configures .-> SEC ENG -. configures .-> CAP ENG -. configures .-> LSM

A blocked call, step by step

The layers are boring by design — each just answers allow/deny. Here a compromised container tries to load a kernel module, the classic escape route:

Sequence — an escape attempt dies at two gates
sequenceDiagram
  participant A as Attacker (root in container)
  participant S as seccomp
  participant C as Capability check
  participant K as Kernel
  A->>S: syscall: init_module(evil.ko)
  alt syscall not in allowlist
    S-->>A: EPERM — blocked before the kernel logic runs
  else allowlisted (custom profile)
    S->>C: pass through
    C-->>A: EPERM — CAP_SYS_MODULE was dropped
  end
  note over A,K: two independent layers must both fail
for the call to reach kernel logic

Defense in depth is the design principle to carry forward: never rely on one wall, because Lesson 39 will show you how each individual wall has been breached historically.

Anchor these

  • Root is ~40 separable capabilities; containers keep only a safe subset.
  • seccomp is a syscall allowlist; the LSM guards paths and labels — independent layers.
  • The engine writes policy once at create time; the kernel enforces on every call.
Next step

See what actually stuck.

Take the practice scenarios now.