Hardening

Scanning tells you what problems exist. Hardening is about changing the defaults so fewer problems can appear in the first place, and so the impact of any remaining problem is limited.
Why defaults are the starting point
Docker’s out-of-the-box defaults are reasonable but not strict. A container runs as root inside the image unless you tell it not to. It gets a default set of Linux capabilities that includes more than most applications need. It can write to its filesystem. None of this is malicious: these defaults exist to make containers easy to start and use.
Hardening means reviewing each of these defaults and tightening the ones your application does not actually need.
Small base images
The fewer packages in an image, the fewer things to patch and the fewer CVEs a scanner can find. A full OS base like ubuntu:latest includes utilities, interpreters, and libraries that a containerised web service will never call. Starting from a minimal base like Alpine Linux or a distroless image removes that surface without changing how the application runs.
Smaller bases also reduce the work of keeping images current. Fewer packages means fewer updates needed after a CVE drops.
Running as non-root
Root inside a container is not the same as root on the host, but it is closer than it should be. If a vulnerability in the application allows code execution, a root process inside the container has far more options than a non-root one: it can write to system paths, manipulate other processes in the same namespace, and in combination with other weaknesses escape to the host. Adding a USER instruction to the Dockerfile is one line of change with meaningful impact.
Dropping capabilities
Linux capabilities are individual permissions like the ability to bind low-numbered ports, change file ownership, or load kernel modules. Docker grants a default set of about fifteen. Most applications need far fewer. Starting from --cap-drop=ALL and adding back only what is required means a compromised process has a much smaller set of tools available.
Keeping secrets out of the image
Secrets baked into an image layer are permanent. Even if you remove the environment variable in a later layer, the earlier layer still contains the value and is readable by anyone who pulls the image. The correct pattern is to pass secrets at runtime from an external store: environment variables injected at startup, files mounted from a secret manager, or a sidecar that provides credentials. The lab shows a simple version of this pattern.