DevSecOps 101 Part 4: Scanning Docker Images With Trivy
This article is part of a series about integrating security tooling in the development process. You can find the rest of the articles here:
- Part 1: Detecting Insecure Dependencies (SCA)
- Part 2: Detecting Insecure Source Code (SAST)
- Part 3: Scanning Live Web Applications (DAST)
Note: This tutorial is based on the repository resulting from part 3. If you haven't achieved it yet, no worries! You can directly fetch the result from GitHub. If you already have done the three first parts of the tutorial, you can switch to the next section.
First, fork https://github.com/glimow/dvpwa
Then, clone your newly forked repository and switch to the right branch:
git clone -b tutorial-part-3 git@github.com:<your-username>/dvpwa.git
Docker Security, As Simple As It Should Be. 💫
In the last tutorial, we used nuclei to search for known security bad practices in our live application.
But nuclei can only detect the tip of the iceberg: the vulnerabilities existing in your live web app for which the community has created custom, handmade tests.
What if the various packages or files you use in your docker images for deploying into production contain vulnerabilities themselves?
Could those vulnerabilities be used by an evil attacker? Sometimes, they can.
Fortunately, thanks to trivy, one can scan its docker images to know literally in seconds if they contain packages with known vulnerabilities. Even cooler, trivy is free, open-source, and well maintained.
As you know, our vulnerable python app, dvpwa, comes with a Dockerfile for both development and production. Let's scan it and hunt for vulnerabilities 👀
Running trivy on a Docker Image 🐳
First, let's install trivy
Fortunately, they have a unique script to install it on macOS or your favorite Linux distro:
curl -sfL https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/install.sh | sh -s -- -b /usr/local/bin v0.21.0
and then
trivy
Which should get you something like:
Our trivy install is up and running, cool! Now let's scan our Dockerfile 🐳
First, go into your local dvpwa directory.
You will notice there are two Dockerfiles: one for the app itself, and one for the database. The priority is to scan the app's Dockerfile itself because it's directly exposed to the internet through the app's web server.
First, let's build our Docker image:
docker build . --file Dockerfile.app -t dvpwa.app
You should obtain a result ending with the following:
Our image is ready to be scanned! 💥
Now it's very simple, just run:
trivy image dvpwa.app:latest
If you are lucky, you should almost instantly see a (huge!) list of vulnerabilities
If you go through the results, you will notice that there is also a Python section, which contains PyYAML critical vulnerabilities:
Wait, haven't we seen that somewhere already? Yes, those are the same vulnerabilities we detected in DevSecOps part 1!
Again, more than just telling you about the vulnerabilities, trivy even tells you the version of each package that fixes them 🤩
Now, as a developer, appsec, or an engineering manager, wouldn't it be cool if we could avoid deploying code if all critical vulnerabilities aren't fixed?
Let's do that with our old friend GitHub Actions.
Integrating trivy in GitHub Actions 🔨
Integrating trivy in GitHub Actions is very simple because aquasecurity, its authors, have published a GitHub Action template for it.
Just add the following at the end of your .github/workflows/main.yaml
container_scanning:
name: Scan Container for Security Issues
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v2
- name: Build an image from Dockerfile
run: |
docker build --file Dockerfile.app -t dvpwa.app:${{ github.sha }} .
- name: Run Trivy vulnerability scanner
uses: aquasecurity/trivy-action@master
with:
image-ref: 'dvpwa.app:${{ github.sha }}'
format: 'table'
exit-code: '1'
ignore-unfixed: true
vuln-type: 'os,library'
severity: 'CRITICAL'
As you can see, in the last part we tell trivy to return a non-zero exit code if it finds critical vulnerabilities in the OS packages or the software libraries.
Now, just commit and push the new config:
git add .github
git commit -m "Add container security scanning"
git push origin master
After a few minutes, you should see the result in your GitHub Actions panel:
Again, our action failed, which is exactly what you would want for a real-world application that contains critical vulnerabilities.
Conclusion! 😎
In just a few minutes, we set up a tool that automatically detects vulnerable packages inside our docker images, directly in the CI/CD.
Since the beginning of this tutorial series, we built a full security pipeline in the CI/CD by checking
With GraphQL being a new technology it lacked the proper tooling needed for security,so many teams just skipped security entirely...
That's why we built Escape, our comprehensive solution can quickly identify issues across your API endpoints and provide remediation snippets—all in as little as 15 minutes, without complex integrations or traffic monitoring.
Bonus: Scanning Dockerfiles using Trivy 🎁
In fact, trivy can scan way more than only docker images: filesystems, requirements.txt, package.json, and even Dockerfiles and Kubernetes configs!
For instance, in our dvpwa repository, we can scan our Dockerfiles just by running
trivy config .
Which will scan automatically our two Dockerfiles Dockerfile.app
and Dockerfile.db
:
💡Want to learn more? Check out the following articles:
- Top 7 DevSecOps Best Practices
- DevOps vs DevSecOps: exploring the key differences and how to make the shift
- Writing custom security tests with Nuclei and Escape
- 9 GraphQL Security Best Practices
- How to test your GraphQL API?