DEV Community

Cover image for Why Images Need Hardening + Getting Started with Docker Hardened Images
Koti Vellanki
Koti Vellanki

Posted on

Why Images Need Hardening + Getting Started with Docker Hardened Images

Docker Hardened Images Series — Blog 1

What We Are Building

By the end of this blog you will understand the real problem with typical container images, know what a Docker Hardened Image (DHI) actually is, authenticate to dhi.io, pull your first hardened image, run it, and compare it side-by-side with a normal official image.

You will leave with a clear “why” and a working first image.

Why This Matters

Most teams still start with official images like python:3.13 or node:22. These images are convenient, but they usually contain:

  • Many packages you never use
  • Shells, package managers and debugging tools
  • Known CVEs that keep appearing in scans
  • A larger attack surface than your application needs

When a vulnerability is disclosed, you spend time triaging, rebuilding and redeploying — often for packages that should never have been in the runtime image in the first place.

A hardened image is deliberately minimised and continuously maintained so that the number of known vulnerabilities stays near zero and the attack surface is dramatically smaller.

Docker Hardened Images (DHI) are Docker’s official implementation of this idea. The Community tier is free and open under Apache 2.0.

What You Should Know Before Starting

  • Basic Docker knowledge (docker pull, docker run, docker images)
  • A free Docker account
  • Docker Desktop or Docker Engine with the Scout CLI plugin (comes with Docker Desktop)

Important Distinctions (Do Not Confuse These)

Term What it means Automatically secure?
Small / Slim Fewer packages, smaller size No
Minimal Only what is needed to run Better, still not enough
Distroless No shell, no package manager Good reduction
Hardened (DHI) Minimal + continuous CVE patching + signed SBOM + SLSA provenance + non-root by default Closest to “secure by default”

Smaller does not automatically mean secure. Hardening is about continuous maintenance, provenance and reduced attack surface together.

Before vs After — Attack Surface

before vs after

Explanation

Left side shows a typical official image full of extra tools and packages.

Right side shows a hardened image that keeps only what is required to run the application. Fewer components = fewer places for vulnerabilities.

Step 1 — See the Problem Yourself

Pull a normal official image and check its size and vulnerabilities (example with Python):

docker pull python:3.13
docker images python:3.13
Enter fullscreen mode Exit fullscreen mode

Output

➜  dhi docker pull python:3.13
3.13: Pulling from library/python
018e5aeb5455: Pull complete 
fcff83b0426f: Pull complete 
6e8333d59c37: Pull complete 
50fe3346a36b: Pull complete 
cecdaccf3d35: Pull complete 
7c92d7371fba: Pull complete 
4d3df26e3af2: Pull complete 
ae85bf126208: Download complete 
1635e0a2f722: Download complete 
Digest: sha256:e16ab55c341bfd0e7da665bc2d48939cff890b43a41867fe6e1f0690638ceb7c
Status: Downloaded newer image for python:3.13
docker.io/library/python:3.13

What's next:
    View a summary of image vulnerabilities and recommendations → docker scout quickview python:3.13
➜  dhi 
➜  dhi docker images python:3.13
                                                                                                                                                                                           i Info →   U  In Use
IMAGE         ID             DISK USAGE   CONTENT SIZE   EXTRA
python:3.13   e16ab55c341b       1.62GB          420MB        
➜  dhi 
Enter fullscreen mode Exit fullscreen mode

If you have Docker Scout:

docker scout cves python:3.13 --platform linux/amd64
Enter fullscreen mode Exit fullscreen mode

Docker scout Output
(It's too lengthy output added the main summary for getting context)

313 vulnerabilities found in 52 packages
  CRITICAL     3   
  HIGH         42  
  MEDIUM       22  
  LOW          199 
  UNSPECIFIED  47  


What's next:
    View base image update recommendations → docker scout recommendations python:3.13

➜  dhi
Enter fullscreen mode Exit fullscreen mode

You will usually see a long list of CVEs and a relatively large image size. Note the numbers — we will compare them soon.

Step 2 — Browse the Hardened Images Catalog

Open the official catalog:

https://hub.docker.com/hardened-images/catalog

official catalogue

Search for python, node, golang, nginx, etc.

You will see variants (Debian/Alpine, runtime/dev, etc.) and security information.

python hardened image

Step 3 — Authenticate to dhi.io

Community images live on the dhi.io registry and require authentication (same Docker account you already have).

docker login dhi.io
Enter fullscreen mode Exit fullscreen mode

Output

➜  dhi docker login dhi.io
Authenticating with existing credentials... [Username: vellankikoti]

i Info → To login with a different account, run 'docker logout' followed by 'docker login'


Login Succeeded
➜  dhi
Enter fullscreen mode Exit fullscreen mode

Use your Docker Hub username and password (or a personal access token).

Step 4 — Pull and Run Your First DHI

docker pull dhi.io/python:3.13
Enter fullscreen mode Exit fullscreen mode

Output

➜  dhi docker pull dhi.io/python:3.13
3.13: Pulling from python
3969c08c9319: Pull complete 
a3577369b942: Pull complete 
267158a60674: Pull complete 
26a837766441: Pull complete 
61947a7c3e2f: Pull complete 
Digest: sha256:45c7b8b9a4edeb7b41ee8dfb1e902dd37782e9d78bef53ae31d01bcb6259b7bf
Status: Downloaded newer image for dhi.io/python:3.13
dhi.io/python:3.13

What's next:
    View a summary of image vulnerabilities and recommendations → docker scout quickview dhi.io/python:3.13
➜  dhi
Enter fullscreen mode Exit fullscreen mode

Run a simple command:

docker run --rm dhi.io/python:3.13 python -c "print('Hello from Docker Hardened Image')"
Enter fullscreen mode Exit fullscreen mode

Output

➜  dhi docker run --rm dhi.io/python:3.13 python -c "print('Hello from Docker Hardened Image')"
Hello from Docker Hardened Image
Enter fullscreen mode Exit fullscreen mode

Notice that many DHI runtime images are intentionally minimal — they may not contain a full shell or package manager. That is by design.

Check the size:

docker images dhi.io/python:3.13
Enter fullscreen mode Exit fullscreen mode
➜  dhi docker images dhi.io/python:3.13         
                                                                                                                                                                                           i Info →   U  In Use
IMAGE                ID             DISK USAGE   CONTENT SIZE   EXTRA
dhi.io/python:3.13   45c7b8b9a4ed        148MB           26MB        
➜  dhi docker images python:3.13                                                           
                                                                                                                                                                                           i Info →   U  In Use
IMAGE         ID             DISK USAGE   CONTENT SIZE   EXTRA
python:3.13   e16ab55c341b       1.62GB          420MB        
➜  dhi 
Enter fullscreen mode Exit fullscreen mode

Step 5 — Compare Side-by-Side with Docker Scout

docker scout compare dhi.io/python:3.13 \
  --to python:3.13 \
  --platform linux/amd64 \
  --ignore-unchanged
Enter fullscreen mode Exit fullscreen mode

Look at the Overview section. You will typically see:

  • Large reduction in image size
  • Many (sometimes almost all) CVEs removed
  • Clear difference in the number of packages

Your exact numbers will vary by tag and date, but the improvement is usually dramatic.

Comparison Flow

dhi comparison

Explanation

Scout analyses both images and shows the concrete differences in size, packages and known vulnerabilities. This is the fastest way to see the value of a hardened image.

What Just Happened Internally

  • You authenticated to the dedicated DHI registry (dhi.io)
  • You pulled a continuously maintained, minimal image built by Docker
  • The image is designed to run as non-root by default
  • It comes with signed SBOMs, SLSA Build Level 3 provenance and VEX data (we will inspect these in later blogs)
  • The comparison proves the reduction in attack surface with real numbers

Let’s Break It (Gently)

Try to run an interactive shell on a minimal runtime image:

docker run -it --rm dhi.io/python:3.13 bash
Enter fullscreen mode Exit fullscreen mode

Output

➜  dhi docker run -it --rm dhi.io/python:3.13 bash

What's next:
    Debug this container error with Gordon → docker ai "help me fix this container error"
docker: Error response from daemon: failed to create task for container: failed to create shim task: OCI runtime create failed: runc create failed: unable to start container process: error during container init: exec: "bash": executable file not found in $PATH

Run 'docker run --help' for more information
➜  dhi 
Enter fullscreen mode Exit fullscreen mode

It will often fail because many runtime variants intentionally do not include a shell.

That is expected. Use a -dev variant when you need a shell for building, and keep the runtime image minimal.

Production Thinking

In a real project I would:

  • Start every new service with a DHI base image from day one
  • Use multi-stage builds (dev variant for build, runtime variant for final image)
  • Treat the Scout comparison as part of the PR checklist
  • Prefer Community tier first; move to Select/Enterprise only when I need FIPS, SLA or customisation

Security Considerations

  • Near-zero known CVEs is a strong starting point, but it is not a complete security programme
  • A hardened base image does not make insecure application code safe
  • Always still scan your final application image
  • Non-root by default removes a whole class of privilege-escalation issues
  • Smaller attack surface means fewer packages that can be exploited

Common Mistakes

  • Expecting every DHI to have a shell and package manager
  • Forgetting docker login dhi.io
  • Comparing images without specifying --platform
  • Thinking “I pulled a small image, so I am secure”
  • Putting secrets or unnecessary tools into the final runtime image

Troubleshooting

Problem Check Fix
unauthorized when pulling docker login dhi.io Log in again with Docker Hub credentials
Image has no shell You pulled a runtime variant Use a -dev variant for build stages
Scout compare fails Scout plugin / login Ensure Docker Desktop + logged in
Numbers look different Tag or platform Always pin platform and compare same tags

Cleanup

docker rmi dhi.io/python:3.13 python:3.13 2>/dev/null || true
Enter fullscreen mode Exit fullscreen mode

What We Learned

  • Typical official images carry unnecessary packages and CVEs
  • Docker Hardened Images are minimal, continuously patched, non-root by default, and come with strong supply-chain metadata
  • Community tier is free; you only need docker login dhi.io
  • A simple Scout comparison immediately shows the practical benefit

You can now pull and run hardened images with confidence.

What’s Next?

In Blog 2 we look inside a hardened image (layers, distroless nature, non-root user) and start building real application images on top of DHI bases using multi-stage Dockerfiles.

References

All commands and behaviour verified against current official documentation (August 2026).

Top comments (0)