Quick Links

There are many factors that contribute towards your Docker security posture but using hardened images is one of the best steps you can take to protect yourself. Not all images have the same security characteristics and a poorly configured one could give an attacker the foothold they need.

What Is Image Hardening?

"Hardening" an image refers to analyzing its current security status and then making improvements to address any concerns. Picking a prebuilt base image like

        ubuntu:latest
    

may seem straightforward but using it as-is could expose you to lurking threats. It's a bit like provisioning a new bare metal server from the Ubuntu install image, then never updating it.

Like that install image, Images on Docker Hub can come with outdated software packages too. Images may also be misconfigured with insecure defaults that put your workload at risk.

By hardening the image, you can be confident it's suitable for your environment. A typical hardening process will address possible weaknesses by updating packages and actively looking for known vulnerabilities. It creates a new base image you can safely use within your pipelines.

Scanning Your Image

The first step is to analyze your chosen base image. Until you've run a security scan, you've no way of knowing whether your image is safe to use.

There are several tools capable of scanning a Docker image for vulnerabilities. They generally run similar assessments, usually based on lists of known CVEs, that produce a list of problems you can audit and remedy.

Screnshot of a Trivy report

Anchore is one such container scanning engine. It uses a client/server architecture but can be run inline in your terminal for one-off scans. Trivy is a similar option which uses its own vulnerability database and presents issues in a nicely formatted table. Another alternative is Docker Scan, an integration with the Snyk scanning engine that's included with recent Docker CLI versions.

Screenshot of "docker scan" output

Once you've selected a tool, run it against your image to ascertain which kinds of issue are present. This will define the baseline you're starting from before you begin to layer up additional protections. It's a good idea to keep a record of your scan results so you can reference addressed vulnerabilities in the future.

Review Your Analysis

Next you need to carefully review the scan results to determine which issues are genuine security concerns and which can be safely overlooked. Don't expect every problem to be a hair-raising vulnerability. The chances are that heavy base images, such as those for popular operating systems or programming frameworks, will present some CVEs. Not all of them will necessarily be relevant to a Dockerized environment or your workload so take the time to inspect each one and weigh it against your priorities.

If your tool reports CVE severities and CVSS scores, you can use those to weight each vulnerability. These scores can help you identify issues needing immediate resolution. Keep assessing each report against your security model and your knowledge of your environment.

It's safe to discard vulnerabilities which you're confident you're already protected against but you should still document this course of action. This will help any future newcomers to the project understand why a CVE report was left unresolved.

Implement Your Mitigation Layers

Now you've worked out what you're going to address, it's time to apply your protections to the Dockerfile. Create a new intermediary Dockerfile that sits between the base image you're hardening and your downstream application image:

FROM insecure-base-image:latest

RUN apt update -y && apt install -y unpatched-package

docker build -t secure-base-image:latest .

docker push example.com/secure-base-image:latest

Now modify your application's Dockerfile to reference the hardened version of the image:

--- FROM insecure-base-image:latest

+++ FROM secure-base-image:latest

Of course your hardening steps will be more involved in the real world. You'll need to update all outdated packages, patch any config file problems, and apply the mitigations you need to fully resolve CVEs. Simultaneously, make sure your changes don't introduce a version conflict that breaks your software's dependency stack. Test your application with the hardened image to make sure everything functions as it should.

Before you call it a day, scan your hardened image with the same security tool you used the first time around. Check the vulnerabilities you wanted to solve have dropped from the list, giving you peace of mind your workload is protected.

Addressing Vulnerabilities Scans Can't Find

A scan-based approach to hardening is effective at discovering known-to-the-community issues buried in your container's filesystem. Automated scanning can't find every problem though: some classes of vulnerability won't be matched by image analysis, so don't rely on scans as your only form of protection.

Malicious code can creep in when you're downloading binaries in your Dockerfile. Source code dependencies added via a package manager are another viable attack vector.

Image hardening involves an awareness of the threat entrypoints presented by Dockerfiles, not just use of a scanning tool. Regular manual reviews of your Dockerfile will help you reduce your susceptibility to supply chain attacks and other under the radar weaknesses.

Using Pre-Hardened Images

There are some pre-hardened images available when you don't want to formulate your own. The most high-profile set comes from the Center for Internet Security (CIS) and includes Debian, Ubuntu, CentOS, RHEL, SUSE, NGINX, PostgreSQL, and Windows Server options, among others. Each image is ready to deploy to popular cloud providers.

Using a pre-hardened image comes with one big caveat: you need to ask yourself whether you really trust it. You may still want to scan it for vulnerabilities before you launch an instance into production. Although there should be far fewer issues than in an off-the-shelf Docker Hub image, running an audit yourself gives you a report to point to in case of future doubts.

More to Think About

Image hardening is only one facet of Docker security. A hardened image on its own may not be enough to defend your installation. You must review the security of your entire environment, including the Docker daemon's runtime configuration and enabled OS-level protections.

Other tools are available to automate these procedures. Docker Bench is an official script to audit all aspects of your Docker installation, including daemon settings, Linux kernel security, and a basic check of your container images.

If you're publishing images for others to use, consider signing them so their integrity can be verified. This helps minimize the risk of users being tricked into downloading a malicious lookalike.

Conclusion

Hardening a Docker image involves scanning it for vulnerabilities, building a new image with additional mitigating protections, then using that version as the base for your application. Although popular images usually rebuild frequently, the versions on Docker Hub could still be sufficiently outdated to include young vulnerabilities.

Hardening is a continuous process; a hardened image won't stay that way forever. You need to scan and rebuild your images regularly, giving you confidence your production workloads are running the latest packages and patches.

It's best to incorporate hardening into your image build pipeline from the outset. Scanning base images and your build output within your CI system will give you insights into your changing security posture and let you review new vulnerabilities as they emerge. Catching "soft" spots early lets you quickly toughen your image back up, reducing your exposure to threats.