Module 3 · Containers & Kubernetes
Dockerfile hardening
16 / 38

Five changes separate a throwaway image from a liability.

Pin versions, multi-stage build, minimal base, non-root user, no baked-in secrets — the same before/after that best demonstrates real hardening knowledge.

Before
FROM ubuntu:latest
RUN apt-get update && apt-get install -y python3
COPY . /app
ENV AWS_SECRET_KEY=AKIA...
CMD ["python3", "app.py"]
After
FROM python:3.12.3-slim AS builder
# ...install deps in a build stage...
FROM python:3.12.3-slim
COPY --from=builder ...
RUN useradd --create-home appuser
USER appuser
# secrets injected at runtime, never baked in
ChangeWhy it matters
Non-root USERIf exploited, the attacker runs unprivileged, not root.
Pinned versionThe same Dockerfile can't silently produce a different image later.
No baked-in secretsA secret in ENV is permanently embedded in the image's layer history.

The two changes with the biggest real-world impact: never run as root, and never bake secrets into image layers.