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.

Screenshot 2020 04 20 at 13.09.15 1024x70 - CONTAINER SECURITY

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

run hadolint docker container 1024x70 - CONTAINER SECURITY

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.

docker file with warnings - CONTAINER SECURITY

And gives some pointers on how to fix them.

hadolint hover hint 1024x163 - CONTAINER SECURITY

Following the suggestions I updated my Dockerfile to the following.

docker file without warnings - CONTAINER SECURITY

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.

full trivy output 1024x527 - CONTAINER SECURITY

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

trivy output with issues 1024x280 - CONTAINER SECURITY

and fail on CRITICAL vulnerabilities (if any).

trivy output without issues 1024x92 - CONTAINER SECURITY

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