Read-only root filesystem
Immutable at runtime, with explicit writable paths.
An immutable container cannot be modified after it starts — no dropped binaries, no rewritten config, no tampered app. A read-only root filesystem makes that real: mount the container’s rootfs read-only and an attacker with code execution cannot write a tool to disk, edit a script, or persist anything. It is also a detection signal — a write attempt where none should happen is a high-confidence alarm.
$ docker run -d --read-only \--tmpfs /tmp:size=64m \ # the one place it may write, in RAM--tmpfs /run:size=8m \-v applogs:/var/log/app \ # a named volume for durable writesmyapp:1.0$ docker exec <id> sh -c 'echo x > /app/evil' 2>&1sh: can't create /app/evil: Read-only file system # tampering blocked
Give back exactly the writable paths needed
Almost every app writes somewhere, so read-only is paired with explicit writable mounts: a tmpfs (memory-backed, vanishes on stop) for scratch and temp files, and named volumes for data that must persist. The result is that every writable location is declared in the run spec and auditable — the opposite of “the whole filesystem is writable and who knows what changed.” Find the paths by running once and reading the permission errors.
services:api:image: registry.internal/api@sha256:9f2a...read_only: truetmpfs: ["/tmp", "/run"]volumes: ["apidata:/var/lib/api"] # explicit, auditable writable pathsecurity_opt: ["no-new-privileges:true"]cap_drop: ["ALL"]volumes: { apidata: {} }
Immutable by policy
Because it is so effective and so cheap, read-only rootfs is something to require rather than hope for — it is part of the restricted Pod Security profile and easy to mandate with a policy engine. Combined with non-root and dropped capabilities, an immutable container gives an attacker who lands inside almost no way to establish a foothold: nothing to write, nothing to install, nothing to keep.