Securikube Part 1: Linting and Vulnerability Checking

( this post carries on from Securikube Part 0) It’s all good to secure your servers, be they Kubernetes or anything else. Sometimes the applications make that job harder: the applications will break if you stop them doing insecure things, like running as root. In this post we’ll look at two approaches: linting Dockerfiles, and scanning Docker images for vulnerabilities.

We want to stop bad things from happening early, not pick them up after publishing or deployment.

Insecure containers expose the system to application vulnerabilities. Let’s go find some!

Linting

You want to know if you’re building containers with weak security. How do you find out? By Linting the Dockerfile before you build it. I chose Hadolint as the tool to do this on a sample application, and added it to the Makefile:

lint:
	docker run --rm -i hadolint/hadolint < Dockerfile

docker: app.war lint
	docker build --platform linux/amd64 --build-arg JAR_FILE=build/libs/\demo-$(VERSION).war -t demo:$(VERSION) .

Hadolint found issues with my 6 line Dockerfile, some of which could have impacted security: for example you shouldn’t leave package cache files sitting around if you happened to install a package in your Docker build.

Scanning

Any good container repository should let you scan for vulnerabilities: Azure and AWS Container repositories do, the Docker service also does. But why wait? I added Trivy (hat tip to Phil) in order to expose any issues. Oh my Lord there were issues:

demo:1.0.0 (alpine 3.14.0)

Total: 36 (UNKNOWN: 0, LOW: 0, MEDIUM: 6, HIGH: 26, CRITICAL: 4)

┌──────────────┬────────────────┬──────────┬───────────────────┬───────────────┬─────────────────────────────────────────────────────────────┐
│   Library    │ Vulnerability  │ Severity │ Installed Version │ Fixed Version │                            Title                            │
├──────────────┼────────────────┼──────────┼───────────────────┼───────────────┼─────────────────────────────────────────────────────────────┤
│ apk-tools    │ CVE-2021-36159 │ CRITICAL │ 2.12.5-r1         │ 2.12.6-r0     │ libfetch before 2021-07-26, as used in apk-tools, xbps, and │
│              │                │          │                   │               │ other products, mishandles...                               │
│              │                │          │                   │               │ https://avd.aquasec.com/nvd/cve-2021-36159                  │
├──────────────┼────────────────┼──────────┼───────────────────┼───────────────┼─────────────────────────────────────────────────────────────┤
│ busybox      │ CVE-2021-42378 │ HIGH     │ 1.33.1-r2         │ 1.33.1-r6     │ busybox: use-after-free in awk applet leads to denial of    │
│              │                │          │                   │               │ service and possibly...                                     │
│              │                │          │                   │               │ https://avd.aquasec.com/nvd/cve-2021-42378                  │
│              ├────────────────┤          │                   │               ├─────────────────────────────────────────────────────────────┤
│              │ CVE-2021-42379 │          │                   │               │ busybox: use-after-free in awk applet leads to denial of    │

There were so many issues found in the Docker image and the Java app inside it, that I had to pause writing and go fix it. Even then I couldn’t find a clean Docker image, and there are still transitive dependencies from Spring Boot that cause noise. That’s a challenge managing vulnerabilities in a live project, so I configured it to exclude unfixed findings, and only fail at a threshold. Right now it fails the build if there are Critical vulnerabilities discovered.

docker: app.war lint
	docker build --platform linux/amd64 --build-arg JAR_FILE=build/libs/\demo-$(VERSION).war -t demo:$(VERSION) .
	trivy image demo:${VERSION} --exit-code 1  --ignore-unfixed  --severity CRITICAL #,HIGH

It takes about 2 seconds to build and check the Docker image (excluding building the toy Spring Boot app). See below for details. Doing this for all your container images gives a high ROI for your time: you’ll reduce your exposure to application and container vulnerabilities.

time make docker
docker run --rm -i hadolint/hadolint < Dockerfile
docker build --platform linux/amd64 --build-arg JAR_FILE=build/libs/\demo-1.0.0.war -t demo:1.0.0 .
[+] Building 1.0s (7/7) FINISHED
 => [internal] load build definition from Dockerfile                                                                                                                                     0.0s
 => => transferring dockerfile: 37B                                                                                                                                                      0.0s
 => [internal] load .dockerignore                                                                                                                                                        0.0s
 => => transferring context: 2B                                                                                                                                                          0.0s
 => [internal] load metadata for docker.io/library/openjdk:18                                                                                                                            0.9s
 => [internal] load build context                                                                                                                                                        0.0s
 => => transferring context: 104B                                                                                                                                                        0.0s
 => [1/2] FROM docker.io/library/openjdk:18@sha256:ac8bc800c76446207675f93939a8977e032043a182c1a6be23c6cdd300db0cc5                                                                      0.0s
 => CACHED [2/2] COPY build/libs/demo-1.0.0.war /app.war                                                                                                                                 0.0s
 => exporting to image                                                                                                                                                                   0.0s
 => => exporting layers                                                                                                                                                                  0.0s
 => => writing image sha256:8ff141dc971724c6602aa51bb709b6ae804c720cdfa44e19fc866a4ffe214a8a                                                                                             0.0s
 => => naming to docker.io/library/demo:1.0.0                                                                                                                                            0.0s
trivy image demo:1.0.0 --exit-code 1  --ignore-unfixed  --severity CRITICAL #,HIGH
2022-10-24T12:45:49.662+1300	INFO	Vulnerability scanning is enabled
2022-10-24T12:45:49.662+1300	INFO	Secret scanning is enabled
2022-10-24T12:45:49.662+1300	INFO	If your scanning is slow, please try '--security-checks vuln' to disable secret scanning
2022-10-24T12:45:49.662+1300	INFO	Please see also https://aquasecurity.github.io/trivy/v0.32/docs/secret/scanning/#recommendation for faster secret detection
2022-10-24T12:45:49.692+1300	INFO	Detected OS: oracle
2022-10-24T12:45:49.692+1300	INFO	Detecting Oracle Linux vulnerabilities...
2022-10-24T12:45:49.699+1300	INFO	Number of language-specific files: 1
2022-10-24T12:45:49.699+1300	INFO	Detecting jar vulnerabilities...

demo:1.0.0 (oracle 8.6)

Total: 0 (CRITICAL: 0)


real	0m2.011s
user	0m0.439s
sys	0m0.095s
DevOps New Zealand