From Zero to Security Scanning in 15 Minutes with GitHub Actions and Trivy

by Yuval Oren, Co-Founder / CEO

TLDR: In this post, I’ll be adding security scans for a Spring Boot project with Github Actions and Trivy.

I had a conversation with a friend who runs an early-stage startup.

He was asking for security advice after noticing a couple of things:

  1. They started seeing an increase in hacker noise.
  2. Some of their bigger clients were asking them to comply with regulations.

These are good problems to have – It means that they are gaining traction. And it’s also great that the startup is looking at security this early and not kicking the can down the road.

Because most of their architecture is based on serverless workloads, my focus was on their code, so I suggested that they implement security scanning right away.

It’s a very quick win that will give them a better understanding of where they stand, offer immediate action items, and help check off a few boxes.

Implementing security scanning with Trivy and GitHub Actions

Trivy is an open-source project by Aqua Security that offers security scanning for:

  • Code
  • Containers
  • Secrets
  • IaC
  • SBOM

And while later down the road, you may want to look at other solutions, this is a great tool to get you going.

Vulnerability, Configuration, and Secrets Scanning

First, let’s do a quick scan to cover the basics. This includes vulnerability, configuration (as in IaC, docker files, etc), and secret scanning.

By running these scans, you will:

  1. Have enough for the next week.
  2. Have basic coverage of your application’s dependencies and misconfiguration.

To get started, I added the following GitHub workflow file to the repo:

.github/workflows/security-scans.yml

name: Security Scans

on:
  push:
    branches: [ "main" ]
  pull_request:
    branches: [ "main" ]


jobs:
  build:
    name: build
    runs-on: ubuntu-20.04
    steps:
      - name: Checkout code
        uses: actions/checkout@v3

      - name: Run static analysis
        uses: aquasecurity/trivy-action@master
        with:
          scan-type: 'fs'
          security-checks: 'vuln,secret,config'
          ignore-unfixed: true
          format: 'sarif'
          output: 'trivy-results.sarif'
          severity: 'CRITICAL'


      - name: Upload Trivy scan results to GitHub Security tab
        uses: github/codeql-action/upload-sarif@v2
        with:
          sarif_file: 'trivy-results.sarif'
          category: 'code'

A few things to note:

→ This job will run when the code is pushed to the main branch or if there is a Pull Request to the main branch. Running both is redundant, but I wanted to keep it for reference. Because we are in a “don’t overthink it” mode, just pick one.

→ The scan type “fs” which means it will scan the code itself. Later we will see another type of scan.

→ security-checks are set to ‘vuln,secret,config’.

→ The last step uploads the results to GitHub’s Security tab.

Add this to your repo and give it a try. Once you push it to the master branch (or if committed to a different branch), head over to Github Actions. You can follow the workflow and see what it does.

Once the scan is completed, head over to the Security tab and click “Code scanning alerts”.

In this demo repo, the list is very short, and I imagine that yours will be much longer. Don’t panic.

GitHub Security Tab

You can now drill down and see more details about the issues:

GitHub Security Tab Details

If you are running a serverless app, you can skip the next section.

Scanning container images

If you are using containers and want to take it up a notch, Trivy allows you to scan your images.

To add image scanning, we will have to add a few steps:

  1. Build the code. In this example, using maven.
  2. Build a docker image.
  3. Run the image scan.

I added the following section to the job:

      - name: Set up JDK 11
        uses: actions/setup-java@v3
        with:
          java-version: '11'
          distribution: 'adopt'
      - name: Build with Maven
        run: mvn --batch-mode --update-snapshots package
      - name: Build an image from Dockerfile
        run: |
          docker build --build-arg JAR_FILE=target/*.jar  -t docker.io/pwdemo/demo-scanning-spring-boot:${{ github.sha }} .

      - name: Image Scan
        uses: aquasecurity/trivy-action@master
        with:
          image-ref: 'docker.io/pwdemo/demo-scanning-spring-boot:${{ github.sha }}'
          format: 'sarif'
          output: 'trivy-image-results.sarif'
#          exit-code: '1'
          ignore-unfixed: true
          vuln-type: 'os,library'
          severity: 'CRITICAL,HIGH'


      - name: Upload Trivy Image scan results to GitHub Security tab
        uses: github/codeql-action/upload-sarif@v2
        with:
          sarif_file: 'trivy-image-results.sarif'
          category: 'image'

A few things worth noting:

→ You can see that I commented out the exit-code parameter. If you want to fail your build if the scanner finds anything, just uncomment it. For now, I think it’s ok to continue the build until you manage to fix existing issues.

→ Note that we are writing the output to a different file and then uploading it with a different category.

If I already have a GitHub Actions Workflow

Just add these steps to your workflow where you see fit. Unless they take too much time to run. In that case, I would consider running it as a different workflow or at a stage that runs less frequently.

Great, I have a list of issues. What now?

The results of the first scan can be a bit overwhelming if your code base is large and not very up-to-date. My suggestion is to sort the issues and start tackling the Critical, then High issues.

It would be daunting at first, but with every fixed issue, your application will be in much better shape.

Use the Create Issue button to add these issues to your work plan. Some will be easy fixes, and others could require more work.

The bad news is that new issues will keep coming in. So from now on, you will have to have a process around fixing these issues. Anything you add is better than nothing, so don’t be discouraged.

More articles

Our Approach to Onboarding New DevOps Hires

What's the best way to onboard a new DevOps hire? Instead of having them aimlessly go through Confluence we have a better approach.

Read more

How we implement AWS WAF in our projects

In this article, we will discuss how we implement AWS WAF in our projects while avoiding common pitfalls.

Read more

Tell us about your project