Are you writing secure Dockerfiles? Are you scanning for security vulnerabilities of the base images you use? Use hadolint and trivy to upgrade your container security!
We are going to explore two tools for writing better and more secure images: hadolint (code here on github) and trivy (code here on github).
To show both tools we are integrating them in a project from a previous post on travis-ci. The complete code is found here.
Secure Dockerfiles
Linters are an effective way to catch (security) bugs early on in your development process. For most programming languages using linters is pretty standard. Hadolint is a linter for your Dockerfiles and is found on github here.
We can run hadolint manual on a Dockerfile. Here is how I install it on my mac.
brew install hadolint
Then the command hadolint checks the Dockerfile on code smells.

If you don’t want to install hadolint you can also use the hadolint Docker image.

But the most effective way to use linting is while you write the code. For VS Code there is a plugin available that underlines your errors.

And gives some pointers on how to fix them.

Following the suggestions I updated my Dockerfile to the following.

Treat your Dockerfiles as code and use hadolint for better and secure images!
Container dependecies
Docker images are build in layers on top of each other. Most of the time we use a base image to build our own layers from. As of all software these base images can contain vulnerabilities that we should monitor. Trivy is a tool to scan for these vulnerabilities.
To install on macOS I used the following
brew install trivy
Now a manual scan of an image results in a list of all vulnerabilities with there assigned weight. Here is an example of the openjdk:13-slim image.

Trivy fetches the information from a remote source and caches it locally for a speedup in the future.
The real power of these tools is of course the integration in your build pipeline. Here we are going to extend our travis-ci build with the trivy scan.
First we install trivy before the build scripts.
install:
- ...
- export TRIVY_VERSION=$(curl --silent "https://api.github.com/repos/aquasecurity/trivy/releases/latest" | grep '"tag_name":' | sed -E 's/.*"v([^"]+)".*/\1/')
- wget https://github.com/aquasecurity/trivy/releases/download/v${TRIVY_VERSION}/trivy_${TRIVY_VERSION}_Linux-64bit.tar.gz
- tar zxvf trivy_${TRIVY_VERSION}_Linux-64bit.tar.gz
The actual scan is done after the new image is pushed to the registry.
script:
- ...
- heroku container:push web --app gardenplanner-api
- ./trivy --exit-code 0 --severity HIGH --no-progress
registry.heroku.com/gardenplanner-api/web
- ./trivy --exit-code 1 --severity CRITICAL --no-progress
registry.heroku.com/gardenplanner-api/web
Note that the exit-code arguments indicates whether to fail the build (on CRITICAL vulnerabilities) or not to fail the build (on HIGH vulnerabilities).
Finally we add the cache directory to speed up later builds.
cache:
directories:
- $HOME/.cache/trivy
- ...
Now your travis build will output HIGH vulnerabilities

and fail on CRITICAL vulnerabilities (if any).

Hopefully you are ready to use hadolint and trivy in your projects and upgrade your container security. Happy scanning!