On the Supply Chain Security Trail with Docker Scout

On the Supply Chain Security Trail with Docker Scout

I believe Docker Scout is one of the best supply-chain security and scanning tools available for the container ecosystem. Before we get into details, I want to make clear that I’m a Docker Captain, so I’m not entirely unbiased here! And Scout itself has a free tier, but if you want to monitor multiple repositories, then you’ll need to purchase a subscription. Now that that’s clear, please read on to understand why I like Scout and what separates it from other solutions.

The first thing to be aware of is that Scout isn’t just a vulnerability scanner, and Docker’s marketing materials tend to avoid that term. Scout takes a holistic approach to supply chain security. It starts by analysing containers and extracting or creating a complete Software Bill of Materials (SBOM) for images. With the Hub integration, these can be monitored over time for compliance to policies. Policies include – predictably – flagging images with high or critical vulnerabilities, but there are also policies such as “avoiding copy-left licences” and verifying “supply chain attestations”.

Other features that go beyond simple vulnerability scanning include the ability to provide recommendations for mitigations and improvements and an already impressive list of integrations (not just with the Docker Hub, but also other registries, code editors, CI/CD platforms and build tooling).

There are two main parts to Scout: a web application that you can see in the below image, and a CLI tool that I will use throughout the rest of this article.

To dig a bit deeper, let’s try analysing a few images. We said already that the starting point for everything is the SBOM, so let’s try generating one. Interestingly, Scout has its own sbom command, separate from docker sbom which is powered by syft. I assume the Scout version will eventually replace docker sbom. Here’s the SBOM for the official Redis image:

docker scout sbom –format list redis
{“level”:”info”,”msg”:”SBOM of image already cached, 133 packages indexedn”,”time”:”2024-06-12T14:50:48+01:00″}

Name Version Type
acl 2.3.1-3 deb

gosu (devel) golang

redis 7.2.5 generic
stdlib go1.18.2 golang
stdlib 1.18.2 golang
sys 0.13.0 golang
sys 0.1.0 golang

The majority of the output is deb packages, most of which I’ve clipped to reduce the size of the output. Scout has found these packages by reading the package manager database. This is as far as some other tooling goes, but we can see it’s also picked up a few more things. Scout has found the binaries for two more applications – redis and gosu – that were downloaded directly from a website rather than being installed via the package manager. It’s also analysed the gosu binary and found the libraries it links against. The effectiveness of supply chain tooling is strongly tied to its performance in identifying contents – if Scout had failed to find these binaries, it would not be able to scan them for vulnerabilities or ensure they match any policies.

In the equivalent Chainguard Image we can see everything is installed via the apk package manager:

$ docker scout sbom –format list cgr.dev/chainguard/redis
{“level”:”info”,”msg”:”SBOM of image already cached, 18 packages indexedn”,”time”:”2024-06-12T15:05:03+01:00″}

Name Version Type
bash 5.2.21-r4 apk
busybox 1.36.1-r10 apk
ca-certificates 20240315-r3 apk
ca-certificates-bundle 20240315-r3 apk
glibc 2.39-r6 apk
glibc-locale-posix 2.39-r6 apk
ld-linux 2.39-r6 apk
libcrypt1 2.39-r6 apk
libcrypto3 3.3.0-r9 apk
libssl3 3.3.0-r9 apk
libxcrypt 4.4.36-r7 apk
ncurses 6.4_p20231125-r3 apk
ncurses-terminfo-base 6.4_p20231125-r3 apk
openssl 3.3.0-r9 apk
posix-libc-utils 2.39-r6 apk
redis-7.2 7.2.5-r2 apk
redis-cli-7.2 7.2.5-r2 apk
wolfi-baselayout 20230201-r11 apk

This is the full output – clearly demonstrating how much leaner Chainguard Images are.

An interesting question is what happens to containers you build yourself with a multi-stage process – will it pick everything up? As a test, I used an example Go application with a multi-stage build:

$ docker scout sbom test –format=list
{“level”:”info”,”msg”:”SBOM of image already cached, 7 packages indexedn”,”time”:”2024-06-12T15:46:18+01:00″}

Name Version Type
ca-certificates 20240315-r3 apk
ca-certificates-bundle 20240315-r3 apk
learninglabsstatic (devel) golang
stdlib 1.22.4 golang
stdlib go1.22.4 golang
tzdata 2024a-r2 apk
wolfi-baselayout 20230201-r11 apk

This looks pretty good! It has found the binary, the libraries it links against and the handful of packages that are in the Chainguard static image. If you regularly use another scanner, I’d recommend running a test like this to make sure it’s aware of everything in your image. I’d also recommend running against a few different builds using different ecosystems to check that it properly identifies your Rust binaries or Java jars.

One of the best features in Scout is vulnerability scanning output. I often find it a struggle to get accurate high-level info from scanners, but it’s easy with Scout. The simple tweak of displaying summary output at the end, instead of before a huge list of issues that you have to scroll backwards through, is much appreciated. Here’s the output from scanning the current nginx:alpine image:

$ docker scout cves nginx:alpine
✓ SBOM of image already cached, 82 packages indexed
✗ Detected 2 vulnerable packages with a total of 5 vulnerabilities

## Overview

│ Analyzed Image
Target │ nginx:alpine
digest │ 4f49228258b6
platform │ linux/arm64
vulnerabilities │ 0C 0H 5M 0L
size │ 22 MB
packages │ 82

## Packages and Vulnerabilities

0C 0H 4M 0L busybox 1.36.1-r15

✗ MEDIUM CVE-2023-42366
Affected range : <1.36.1-r16
Fixed version : 1.36.1-r16

✗ MEDIUM CVE-2023-42365
Affected range : <1.36.1-r19
Fixed version : 1.36.1-r19

✗ MEDIUM CVE-2023-42364
Affected range : <1.36.1-r19
Fixed version : 1.36.1-r19

✗ MEDIUM CVE-2023-42363
Affected range : <1.36.1-r17
Fixed version : 1.36.1-r17

0C 0H 1M 0L curl 8.5.0-r0

✗ MEDIUM CVE-2024-0853
Affected range : <8.6.0-r0
Fixed version : not fixed

5 vulnerabilities found in 2 packages

What’s next:
View base image update recommendations → docker scout recommendations nginx:alpine

It’s also possible to only get the initial summary output by calling the quickview command.

In my testing, I’ve noticed that – compared to some other scanner tooling – Scout will report less CVEs. Docker claims this is because they are less vulnerable to false positives (where a CVE is wrongly attributed to an image). The primary reason they give for this is that Scout uses Package URLs or PURLs to match software, rather than CPEs.

On the other hand, Scout will report more matches than some tooling (I realise this is confusing, but I don’t want to name names without providing a full breakdown and analysis). This is because Scout uses a wide range of sources to build its vulnerability database – as well as the security data from Linux distributions, it includes NVD, GitHub and other advisory data. The more data sources that are used, the more likely you are to find matches.

The last sentence in the command output hints at another feature in Scout – the ability to recommend fixes. One of the biggest flaws with current scanning tools is that they often flag issues that you can do nothing about – vulnerabilities for which there is no newer package or fix available. Scout helps you both filter out issues that you can’t deal with and fix the ones you can.

Here’s the recommendations output for the Debian-based nginx:latest image, which suggests changing to a different tag to reduce CVEs, and gives details of the potential impact:

docker scout recommendations nginx
✓ SBOM of image already cached, 231 packages indexed

i Base image was auto-detected. To get more accurate recommendations, build images with max-mode provenance attestations.
Review docs.docker.com ↗ for more information.
Alternatively, use docker scout recommendations –tag <base image tag> to pass a specific base image tag.

Target │ nginx:latest
digest │ 705b7f60fea5

## Recommended fixes

Base image is debian:12-slim

Name │ 12-slim
Digest │ sha256:6dc38501802c1554f0fd858d1153a6f0e18c71006c6d0b31cf19fa778900e658
Vulnerabilities │ 0C 0H 0M 23L
Pushed │ 1 month ago
Size │ 29 MB
Packages │ 125
Flavor │ debian
OS │ 12
Slim │ ✓

│ The base image is also available under the supported tag(s) 12.5-slim , bookworm-slim . If you want to display recommendations specifically
│ for a different tag, please re-run the command using the –tag flag.

Refresh base image
Rebuild the image using a newer base image version. Updating this may result in breaking changes.

Tag │ Details │ Pushed │ Vulnerabilities
12-slim │ Benefits: │ 11 hours ago │ 0C 0H 0M 23L
Newer image for same tag │ • Same OS detected │ │
Also known as: │ • Newer image for same tag │ │
• 12.5-slim │ • Tag was pushed more recently │ │
• bookworm-slim │ • Image has similar size │ │
• bookworm-20240612-slim │ • Image has same number of vulnerabilities │ │
│ • Image contains equal number of packages │ │
│ • Tag is using slim variant │ │
│ │ │
│ Image details: │ │
│ • Size: 29 MB │ │
│ • Flavor: debian │ │
│ • OS: 12 │ │
│ • Slim: ✓ │ │
│ │ │
│ │ │
│ │ │

Change base image
The list displays new recommended tags in descending order, where the top results are rated as most suitable.

Tag │ Details │ Pushed │ Vulnerabilities
stable-slim │ Benefits: │ 11 hours ago │ 0C 0H 0M 23L
Tag is preferred tag │ • Same OS detected │ │
Also known as: │ • Tag is preferred tag │ │
• stable-20240612-slim │ • Tag was pushed more recently │ │
│ • Image has similar size │ │
│ • Image has same number of vulnerabilities │ │
│ • Image contains equal number of packages │ │
│ • Tag is using slim variant │ │
│ • stable-slim was pulled 46K times last month │ │
│ │ │
│ Image details: │ │
│ • Size: 29 MB │ │
│ • Flavor: debian │ │
│ • OS: 12 │ │
│ • Slim: ✓ │ │
│ │ │
│ │ │
│ │ │
12 │ Benefits: │ 11 hours ago │ 0C 0H 0M 23L
Tag is latest │ • Same OS detected │ │
Also known as: │ • Tag was pushed more recently │ │
• 12.5 │ • Tag is latest │ │
• bookworm │ • Image has same number of vulnerabilities │ │
• bookworm-20240612 │ • Image contains equal number of packages │ │
• latest │ │ │
│ Image details: │ │
│ • Size: 50 MB │ │
│ • Flavor: debian │ │
│ • OS: 12 │ │
│ │ │
│ │ │
│ │ │

Finally, let’s take a look at the Chainguard nginx image.

docker scout cves chainguard/nginx
✓ SBOM obtained from attestation, packages found
✓ No vulnerable package detected

## Overview

│ Analyzed Image
Target │ chainguard/nginx:latest
digest │ 1ffdf2c788d4
platform │ linux/arm64
vulnerabilities │ 0C 0H 0M 0L
size │ 20 MB
packages │ 55

## Packages and Vulnerabilities

No vulnerable packages detected

As expected, there are no vulnerabilities, but also note the text at the start – “SBOM obtained from attestation, packages found”. Scout has used the SBOM that Chainguard provided for the image and used that to enumerate the software in the image. This level of integration and support for external tooling is essential for creating a holistic supply chain security solution – every organisation uses a different set of tools and software from various vendors and it’s imperative that we figure out how to get supply chain information from everyone in a verifiable and trustable manner.

Hopefully I’ve shown you why I like Docker Scout. It does a good job of finding all the packages in an image but also does a great job of reporting vulnerabilities. Vulnerabilities are less likely to be false positives through the use of PURLs and the summary output is easy to grab (which is great for videos!). Docker will tell you the real strengths lie in continuously monitoring repositories and reporting on progress towards supply chain policies, and I plan to create some further content on this in the future.

Please give Docker Scout a whirl (compare some Chainguard Images!) and let me know what you think.

Cover photo by Maël BALLAND on Unsplash