Lab 1: Dockerfile Hardening
Create a deliberately insecure Dockerfile
This Dockerfile has 7 security issues. We'll fix every one.
$ mkdir -p ~/bootcamp-docker && cd ~/bootcamp-docker $ cat > Dockerfile.insecure << 'EOF' FROM ubuntu:latest ENV DB_PASSWORD=supersecret123 ADD . /app RUN apt-get update && apt-get install -y python3 curl wget vim EXPOSE 8080 CMD ["python3", "/app/server.py"] EOF
Build the hardened version
Multi-stage build, non-root user, distroless base, no secrets, health check, pinned image.
$ cat > Dockerfile << 'EOF' # Pin base image by digest FROM python:3.12-slim@sha256:abcd1234... AS builder WORKDIR /app COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt COPY . . # Production stage — minimal image FROM gcr.io/distroless/python3-debian12:nonroot COPY --from=builder /app /app WORKDIR /app USER 1001 HEALTHCHECK --interval=30s CMD ["python3", "-c", "import urllib.request; urllib.request.urlopen('http://localhost:8080/health')"] EXPOSE 8080 CMD ["server.py"] EOF
Compare the two
The secure image is 8x smaller with a dramatically reduced attack surface.
$ docker build -f Dockerfile.insecure -t myapp:insecure . $ docker build -t myapp:secure . # Compare image sizes $ docker images myapp # insecure: ~400MB | secure: ~50MB # Check for root user $ docker inspect myapp:insecure --format '{{.Config.User}}' # (empty = root!) $ docker inspect myapp:secure --format '{{.Config.User}}' # 1001