Building Zero CVE Images, the Right Way

Prem ChavhanPrem Chavhan
3 min read

Nowadays, companies are extensively using microservices architecture and running applications on containerized platforms. However, most of the time, what people do is simply pull Docker base images from the Docker registry or any public registry, without considering the vulnerabilities and security risks that come along with them.

This is where DevSecOps comes into play.

Let's understand how we can get near-zero CVE images for applications the right way.

The Issue: Vulnerabilities in Docker Base Images

In an ideal application Docker image, most vulnerabilities typically stem from the base image or the dependencies we add with the application.

So, let's focus on the base image first.

For example, let’s take the Python 3.10 image, which is commonly used from the Docker registry. Most developers might be using it in their Dockerfiles.

Now, let's scan the image using Trivy:

So, we have a lot of vulnerabilities, and some are even unknown. So what are our options for base images to reduce the vulnerabilities?

What Are Our Options to Reduce Vulnerabilities?

1. Scratch Images

One option is using scratch Docker images. Scratch images are minimal and ideally used for building base images like Debian or Ubuntu, or other super-minimal images.

However, because these images are minimal, we need to set up each tool from scratch, including basic utilities, which can come with its own set of drawbacks.

2. Distroless Images

Another option is distroless images. Distroless images contain only your application and its runtime dependencies. They do not include package managers, shells, or any other programs you would expect to find in a standard Linux distribution.

But the downside of distroless images is that they are hard to debug, as they don't contain package managers or a shell.

Is There Another Option?

Yes, there is Wolfi. Wolfi is a Linux distribution specifically designed for containers. It can be used to create a secure base layer for your containers.

So, let's scan Wolfi using Trivy:

So, as we can see, the Wolfi base image doesn't have any vulnerabilities.

Replacing Python Base Image with Wolfi

So, how does this replace the Python base image in my Dockerfile?

Currently, my Dockerfile looks like this:

So, after some minimal changes, here is the Dockerfile that uses Wolfi as the base image:

Note: Using a non-root user is not a requirement for using the Wolfi image. Non-root user is a common practice for security reasons. This means that the container's processes will not have elevated privileges and therefore have a smaller potential attack surface.

After the build, we are getting reduced vulnerabilities, as we only need to deal with package-level vulnerabilities. Even for that, Trivy can help, it suggests which version we should upgrade a particular package to, in order to resolve certain vulnerabilities.

Another thing I noticed is the reduced application image size. If we compare both Python and Wolfi images, there is a huge difference, so that is a plus point.

So, this is how we achieve near-zero CVE images, though we still need to take care of application package-level vulnerabilities.

Is Wolfi Base Image Safe to Use?

The Wolfi project was initiated by Chainguard to build zero-CVE images, which Chainguard provides.

We can verify this by checking the Software Bill of Materials (SBOM) to see exactly what packages are included in the image. This can be done using the Trivy command:
trivy image --format spdx-json --output result.json cgr.dev/chainguard/wolfi-base:latest

Or you can check them here: https://images.chainguard.dev/directory/image/wolfi-base/sbom
SBOM itself is a separate topic to discuss. I might post an article on that, stay tuned..

2
Subscribe to my newsletter

Read articles from Prem Chavhan directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Prem Chavhan
Prem Chavhan