What's the difference between Docker's default security posture and a hardened configuration?
Quick Answer
Docker's defaults (a non-full-root capability set, default seccomp/AppArmor profiles) already provide meaningfully more protection than an unconfined process running directly on the host — but they still allow a container to run as root, retain a broader-than-minimal capability set, use a fully writable root filesystem, and have no resource limits, unless explicitly configured otherwise. A hardened configuration deliberately layers on top of these defaults: non-root user, --cap-drop=ALL plus a minimal --cap-add, a read-only root filesystem, explicit resource limits, and — where the threat model warrants it — stricter custom seccomp/AppArmor profiles and signed/verified images.
Detailed Answer
This question ties together every individual hardening measure covered elsewhere in this topic into one comparative picture — useful for demonstrating you understand not just each mechanism individually, but how they compose into a genuinely hardened posture versus a merely-default one.
What Docker already does, out of the box, without any extra configuration
- A restricted default capability set — not full root privilege, even for a container that appears to run as root (see the capabilities question).
- A default seccomp profile blocking dozens of higher-risk, rarely-needed syscalls (see that question).
- A default AppArmor (or SELinux) profile, on hosts where it's available, restricting file/resource access further (see that question).
- Namespace and cgroup isolation — the fundamental isolation mechanism underlying containers in the first place (see the fundamentals topic).
These defaults are genuinely meaningful. Running an unconfined process directly on a host has none of this protection at all. So "just using Docker with no extra hardening" is already a real security improvement over the alternative in several respects.
What Docker's defaults still leave open, by default
- Runs as root unless a
USERinstruction or--userflag says otherwise (see that question). - A writable root filesystem — nothing prevents a compromised process from modifying application files or installing tools unless
--read-onlyis explicitly set (see that question). - No resource limits — a container can consume unbounded CPU/memory unless
--memory/--cpusare explicitly configured (see the lifecycle topic), risking one container starving others sharing the host. - Secrets handled carelessly by default if the author isn't deliberate — nothing in Docker itself prevents baking a secret into an image via
ENV/ARG/COPY(see that question) unless the image's author specifically avoids it. - No image signature verification — nothing prevents pulling and running an unsigned, untrusted, or tampered image by default (see the registries topic's signing question).
A concrete side-by-side
| Default | Hardened | |
|---|---|---|
| User | Root (unless the image's own Dockerfile says otherwise) | Explicit non-root USER, enforced via --user too |
| Capabilities | Docker's modest default set | --cap-drop=ALL + minimal explicit --cap-add |
| Root filesystem | Writable | --read-only, with explicit --tmpfs/volumes for genuine write needs |
| Resource limits | None | Explicit --memory/--cpus |
| Secrets | However the image/deployment happens to handle them | Never baked into images; runtime-injected via files/secrets manager |
| Image provenance | Trusted by name/tag alone | Verified via signing (Cosign) before running |
| seccomp/AppArmor | Docker's default profiles | Default profiles, or a stricter custom profile for especially sensitive workloads |
Why hardening is a deliberate, additive process, not a single switch
There's no single "make it secure" flag. A genuinely hardened container configuration is the sum of many individually modest measures, each closing off one specific category of risk, applied together. This is exactly the defense-in-depth philosophy that runs throughout this entire security topic: no single layer is assumed to be perfectly sufficient on its own, so multiple independent, complementary layers are stacked so that a weakness in any one doesn't fully compromise the whole system. Docker's defaults are a reasonable, genuinely protective starting point, not a finished production security posture.