G
GuideDevOps
Lesson 8 of 13

Container Security & Image Scanning

Part of the Security & DevSecOps tutorial series.

The Containerization Security Problem

When developers moved from Virtual Machines to Docker containers, application deployment became incredibly fast. But this speed introduced a severe security blind spot.

A Docker image is effectively a tiny, pre-packaged Linux operating system containing your code and all its dependencies.

Developers frequently create images using broad instructions:

# Start from the full Ubuntu OS
FROM ubuntu:latest
 
# Install everything we might need
RUN apt-get update && apt-get install -y python3 curl wget nmap netcat
 
COPY . /app
CMD ["python3", "/app/main.py"]

Why is this dangerous?

  1. Bloated Base Images: The ubuntu:latest image contains hundreds of pre-installed background libraries. If any one of those libraries has a CVE (vulnerability), your entire application container is vulnerable—even if your Python code is perfectly secure.
  2. Hacker Tools Included: By installing tools like curl, wget, and netcat, the developer just handed tools directly to the hacker. If an attacker breaches the Python app and gains terminal access to the container, they can use wget to download cryptocurrency miners or malware immediately.
  3. Running as Root: By default, Docker containers run as the massive root user. If an attacker breaks out of the container bounds, they become the root user of the entire underlying host server.

Static Image Scanning (Shift-Left)

Before a Docker image is ever deployed to production, it must be scanned for CVEs (Common Vulnerabilities and Exposures).

During the CI/CD pipeline, immediately after the docker build command successfully creates the image, you must inject entirely automated Image Scanning.

How Image Scanners Work

Image scanners crack open the compiled Docker image and read the deeply embedded package manifests (like dpkg, apk, or rpm databases). They compare every installed binary against global vulnerability databases (like the NVD).

If the scanner finds a critical vulnerability (e.g., Log4j or Heartbleed) inside the container filesystem, the CI pipeline fails and the image push to the registry is explicitly blocked.

Popular Image Scanners:

  • Trivy (Aqua Security): Open-source, incredibly fast, and the industry standard for CI pipelines.
  • Clair (Quay): Open-source scanner highly integrated with registries.
  • Grype (Anchore): Specialist at digging deep into container layers.

Best Practices for Writing Secure Dockerfiles

You can solve 90% of container security issues by strictly enforcing these Dockerfile practices during code review:

1. Use Minimal Base Images

Do not use entire operating systems like ubuntu or centos. Use alpine (a roughly 5MB micro-OS) or Google's Distroless images. Distroless images are stripped bare—they do not even contain a shell (/bin/sh). If a hacker breaks into a Distroless container, they can't type any terminal commands because a terminal literally does not exist!

2. Never Run as Root

Always create a dedicated, low-privilege user at the end of your Dockerfile.

FROM alpine:latest
COPY . /app
 
# Create a user group and standard user
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
 
# Tell Docker to use this user instead of root
USER appuser
 
CMD ["node", "/app/server.js"]

3. Multi-Stage Builds

If your application needs compiling (like Go, Rust, or C++), you obviously need compilers like gcc installed. But you should never ship gcc to the production environment!

Use Multi-stage builds to compile the code in one massive container, and then deliberately copy only the final, tiny, compiled binary into a brand-new, empty Distroless container.


Runtime Container Security (Shift-Right)

Static scanning only catches known, documented CVEs in libraries. What if a hacker uses a zero-day exploit against your proprietary code?

You must implement Runtime Security to monitor the live container while it is executing in production (e.g., on Kubernetes).

Runtime security tools operate by profoundly monitoring the Linux kernel (often using modern eBPF technology) to watch what the container is attempting to do in real-time.

Runtime tools can instantly kill a container if it forcefully breaks behavioral rules:

  • "Warning: The frontend-web container just attempted to open a network connection to a Bitcoin mining rig in Russia. Unacceptable. Kill the container."
  • "Warning: The database container just executed the /bin/bash terminal command. Databases don't use bash. An attacker has breached it. Kill the container."

Popular Runtime Security Tools:

  • Falco: CNCF incubating project, the standard for Kubernetes runtime security.
  • Tetragon (Cilium): Advanced eBPF-based enforcement.