CoursesAdvanced container securityHardening the container

Read-only root filesystem

Immutable at runtime, with explicit writable paths.

Advanced12 min · lesson 11 of 25

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.

terminal
$ 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 writes
myapp:1.0
$ docker exec <id> sh -c 'echo x > /app/evil' 2>&1
sh: 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.

compose.yaml
services:
api:
image: registry.internal/api@sha256:9f2a...
read_only: true
tmpfs: ["/tmp", "/run"]
volumes: ["apidata:/var/lib/api"] # explicit, auditable writable path
security_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.

readOnlyRootFilesystem breaks apps that write to /
The usual failure is a cryptic crash on startup because the app writes a lockfile, cache, or socket under a now-read-only path. Do not abandon read-only — enumerate what it writes (run it once, watch the errors) and grant each path an explicit tmpfs or volume. A handful of named writable mounts is worth an immutable filesystem everywhere else.