Photo Container Security Audit

Automating Container Security Audits in GitHub Actions with Trivy and Grype

So, you’re looking to automate container security audits in your GitHub Actions workflow? That’s a smart move. The short answer is: yes, you absolutely can, and it’s quite achievable using popular tools like Trivy and Grype. By integrating these open-source scanners into your CI/CD pipeline, you can catch vulnerabilities early, streamline your security processes, and avoid those last-minute panics when something slips through the cracks. Think of it as building security right into your development process, rather than tacking it on at the end.

Why Automate Container Security Audits?

Let’s be honest, manually checking every container image for vulnerabilities is a tedious and error-prone task. As your project grows and you have more containers to manage, the sheer volume becomes overwhelming. This is where automation shines.

The Manual Audit Nightmare

Remember those times when you had to pull an image, run a scanner manually, sift through pages of results, and then remember to do it again for the next build? It’s a recipe for burnout and missed vulnerabilities. Plus, the human element means inconsistencies – different team members might use different scanner configurations or simply forget a step.

The Benefits of an Automated Approach

Automating these checks in your GitHub Actions workflow brings several key advantages:

  • Early Vulnerability Detection: Catching issues when code is first committed or a container is built is far cheaper and easier to fix than finding them in production.
  • Consistency and Reliability: Automated scans run the same way every time, ensuring a consistent security posture across all your builds. No more “it worked on my machine” excuses for security findings.
  • Developer Empowerment: Developers get immediate feedback on the security of their code and images, allowing them to address issues proactively.
  • Reduced Operational Burden: Free up your security team to focus on more strategic tasks instead of repetitive scanning.
  • Compliance and Governance: Automated audits help meet regulatory requirements and internal security policies.

In the realm of enhancing software security, the article on automating container security audits in GitHub Actions using Trivy and Grype provides valuable insights into streamlining security processes. For those interested in how technology can improve connectivity and functionality in various devices, a related article discusses the impact of smartwatches on enhancing connectivity. You can read more about it here: How Smartwatches Are Enhancing Connectivity. This connection between security automation and the advancements in wearable technology highlights the importance of integrating robust security measures in all aspects of tech development.

Introducing Trivy and Grype

Trivy and Grype are two fantastic open-source vulnerability scanners that are well-suited for container security audits. They both focus on different aspects and have their strengths, making them a powerful combination.

Trivy: Your All-in-One Container Scanner

Trivy is developed by Aqua Security and is known for its simplicity and comprehensive scanning capabilities. It can scan container images, filesystems, and Git repositories for vulnerabilities in operating system packages and application dependencies.

Key Features of Trivy
  • Broad Vulnerability Database: Trivy pulls from a vast and regularly updated database of known vulnerabilities (CVEs).
  • Multiple Scan Targets: It’s not just for containers! Trivy can scan IaC (Infrastructure as Code) files, Kubernetes configurations, and more.
  • Easy to Use: Installation is straightforward, and its command-line interface is intuitive.
  • Speed: Trivy is generally very fast, which is crucial for CI/CD pipelines.
  • Output Formats: Supports various output formats like JSON, which is excellent for programmatic parsing in your GitHub Actions.
Grype: Focusing on Application Dependencies

Grype, on the other hand, is part of the Anchore ecosystem. While it can also scan container images, it often excels at providing a deeper dive into application dependencies and software bill of materials (SBOM).

Key Features of Grype
  • Deep Dependency Analysis: Grype is particularly strong at identifying vulnerabilities within the libraries and packages that your applications use.
  • SBOM Generation: It can generate detailed Software Bills of Materials (SBOMs), which are essential for understanding your software’s composition.
  • Maturity and Ecosystem: Grype benefits from the mature ecosystem around Anchore, which offers comprehensive lifecycle security management.
  • Integration Potential: Works well with other Anchore tools for more advanced policy enforcement.

Choosing Between Trivy and Grype (or Using Both)

The “best” tool often depends on your specific needs.

  • For general-purpose, fast container image scanning: Trivy is an excellent starting point. It’s often the go-to for quick checks on OS packages and common application dependencies.
  • For in-depth application dependency analysis and SBOM generation: Grype offers a more granular view. If you need to understand the precise versions of every library your application is using and their associated CVEs, Grype is a strong contender.
  • The Power of Combined Scanning: Many teams find that using both Trivy and Grype provides the most comprehensive coverage. Trivy can give you a quick overview of critical vulnerabilities, while Grype can then drill down into specific application libraries for more detailed analysis.

Setting Up GitHub Actions for Container Audits

Now, let’s get practical. We’ll walk through how to integrate Trivy and Grype into your GitHub Actions workflow. The core idea is to have your workflow build your container image and then pass that image to the security scanner.

Prerequisites

Before you dive in, make sure you have:

  • A GitHub repository with your containerized application code.
  • A Dockerfile to build your container images.
  • A GitHub Actions workflow file (e.g., .github/workflows/security-scan.yml).

Using Trivy in GitHub Actions

Trivy has excellent community support and can be easily integrated. A common pattern is to use the aquasec/action-trivy GitHub Action.

Workflow Example: Trivy Scan on Push

Here’s a basic example of a workflow that scans a Docker image every time you push to the main branch.

“`yaml

name: Container Security Scan (Trivy)

on:

push:

branches:

  • main

jobs:

scan-image:

runs-on: ubuntu-latest

steps:

  • name: Checkout code

uses: actions/checkout@v4

  • name: Set up Docker Buildx

uses: docker/setup-buildx-action@v3

  • name: Log in to Docker Hub (or other registry)

uses: docker/login-action@v3

with:

username: ${{ secrets.DOCKERHUB_USERNAME }}

password: ${{ secrets.DOCKERHUB_TOKEN }}

  • name: Build and push Docker image

id: docker_build

uses: docker/build-push-action@v5

with:

context: .

push: true

tags: your-dockerhub-username/your-app-name:latest

cache-from: type=gha

cache-to: type=gha,mode=max

  • name: Run Trivy vulnerability scan

uses: aquasec/action-trivy@master

with:

image-ref: your-dockerhub-username/your-app-name:latest # Use the image you just built

format: ‘table’ # Or ‘json’ for programmatic parsing

ignore-unfixed: true # Optionally ignore vulnerabilities without a fix

exit-code: ‘1’ # Exit with non-zero code if vulnerabilities are found

More options available, see Trivy action documentation

“`

Explanation of the Trivy Workflow
  1. on: push: This triggers the workflow when code is pushed to the main branch. You can adjust this to trigger on pull requests, tags, etc.
  2. runs-on: ubuntu-latest: Specifies the runner environment.
  3. actions/checkout@v4: Checks out your repository code.
  4. docker/setup-buildx-action@v3: Sets up Docker Buildx, which is essential for building modern Docker images and can improve build performance.
  5. docker/login-action@v3: Logs you into your container registry (e.g., Docker Hub). You’ll need to store your registry username and token as GitHub Secrets.
  6. docker/build-push-action@v5: This step builds your Docker image and pushes it to your registry. Crucially, the tags should match what Trivy will scan.
  7. aquasec/action-trivy@master: This is the core step.
  • image-ref: This is the name and tag of the Docker image you want to scan. It must match the image you built and pushed.
  • format: table is human-readable in the logs. For more complex automation (e.g., creating issues based on findings), json is better.
  • ignore-unfixed: This is a common setting to avoid noise from vulnerabilities that have no available fix yet.
  • exit-code: Setting this to '1' means the workflow will fail if Trivy finds any vulnerabilities (unless you specify severity filters). This is a powerful way to enforce security standards.

Using Grype in GitHub Actions

Grype can also be integrated, often by running it directly within a job that has Docker available or by using a dedicated GitHub Action if one is maintained. A common approach is to run Grype as a command-line tool.

Workflow Example: Grype Scan on Push

This example shows how to build an image, pull it down, and then run Grype against it.

“`yaml

name: Container Security Scan (Grype)

on:

push:

branches:

  • main

jobs:

scan-image:

runs-on: ubuntu-latest

steps:

  • name: Checkout code

uses: actions/checkout@v4

  • name: Set up Docker Buildx

uses: docker/setup-buildx-action@v3

  • name: Log in to Docker Hub (or other registry)

uses: docker/login-action@v3

with:

username: ${{ secrets.DOCKERHUB_USERNAME }}

password: ${{ secrets.DOCKERHUB_TOKEN }}

  • name: Build and push Docker image

id: docker_build

uses: docker/build-push-action@v5

with:

context: .

push: true

tags: your-dockerhub-username/your-app-name:latest

  • name: Pull Docker image for scanning

run: docker pull your-dockerhub-username/your-app-name:latest

  • name: Install Grype

run: |

curl -sfL https://raw.githubusercontent.com/anchore/grype/main/install.sh | sh -s — -b /usr/local/bin

  • name: Run Grype vulnerability scan

run: |

grype your-dockerhub-username/your-app-name:latest \

–fail-on high \

–fail-on critical \

–output table # Or json

For more advanced control, consider using Grype with a specific configuration file:

– name: Run Grype with configuration

run: |

echo ‘{ “failCondition”: “eq(vulns.HIGH, 0) && eq(vulns.CRITICAL, 0)” }’ > grype-config.json

grype your-dockerhub-username/your-app-name:latest -c grype-config.json

“`

Explanation of the Grype Workflow
  1. Checkout, Buildx, Login: Similar to the Trivy workflow, these steps prepare your environment and build/push your image.
  2. docker pull: Explicitly pull the image that was just pushed. While the runner might have it cached, pulling ensures you’re scanning the exact pushed version.
  3. Install Grype: This uses a convenient script provided by Anchore to download and install Grype into your runner’s PATH.
  4. Run Grype vulnerability scan:
  • grype your-dockerhub-username/your-app-name:latest: This is the core command. It tells Grype which image to scan.
  • --fail-on high --fail-on critical: This is a crucial part for automation. It instructs Grype to exit with a non-zero status code (failing the job) if it finds any vulnerabilities with a severity of “high” or “critical”. You can adjust these levels.
  • --output table: For readable logs. Use --output json if you need to process the results further.
  • The commented-out section shows how you could use a configuration file for more granular control over failure conditions.

Combining Trivy and Grype for Comprehensive Coverage

You can easily run both scanners in the same workflow. You might choose to have one fail the build based on stricter criteria and the other provide a more detailed report.

Workflow Example: Trivy and Grype Combined

“`yaml

name: Comprehensive Container Security Scan

on:

push:

branches:

  • main

jobs:

scan-images:

runs-on: ubuntu-latest

steps:

  • name: Checkout code

uses: actions/checkout@v4

  • name: Set up Docker Buildx

uses: docker/setup-buildx-action@v3

  • name: Log in to Docker Hub (or other registry)

uses: docker/login-action@v3

with:

username: ${{ secrets.DOCKERHUB_USERNAME }}

password: ${{ secrets.DOCKERHUB_TOKEN }}

  • name: Build and push Docker image

id: docker_build

uses: docker/build-push-action@v5

with:

context: .

push: true

tags: your-dockerhub-username/your-app-name:latest

Trivy Scan

  • name: Run Trivy vulnerability scan

uses: aquasec/action-trivy@master

with:

image-ref: your-dockerhub-username/your-app-name:latest

format: ‘table’

ignore-unfixed: true

exit-code: ‘1’ # Fail on any vulnerability found by Trivy

severity: ‘HIGH,CRITICAL’ # Only fail on HIGH and CRITICAL for Trivy

Grype Scan

  • name: Pull Docker image for Grype

run: docker pull your-dockerhub-username/your-app-name:latest

  • name: Install Grype

run: |

curl -sfL https://raw.githubusercontent.com/anchore/grype/main/install.sh | sh -s — -b /usr/local/bin

  • name: Run Grype vulnerability scan

run: |

grype your-dockerhub-username/your-app-name:latest \

–fail-on medium \

–fail-on high \

–fail-on critical \

–output table

You could also output Grype results to a file for later analysis

– name: Output Grype JSON report

run: grype your-dockerhub-username/your-app-name:latest –output json > grype-report.json

continue-on-error: true # Allow Grype to run even if it fails the job

“`

In this combined example, Trivy is configured to fail the build on any HIGH or CRITICAL vulnerability. Grype is also configured to fail on MEDIUM, HIGH, and CRITICAL, providing an even more stringent check. The continue-on-error: true on an output step can be useful if you want to capture a report even if the scan itself fails the job, allowing you to review the findings manually.

Advanced Configuration and Best Practices

Beyond basic scans, there are ways to refine your security audits for maximum impact.

Filtering Vulnerabilities

It’s rare to fix every single vulnerability. You’ll likely want to focus on the most critical ones. Both Trivy and Grype offer ways to filter results.

Severity Levels
  • Trivy: Use the --severity flag (e.g., --severity HIGH,CRITICAL).
  • Grype: Use the --fail-on flag (e.g., --fail-on high, --fail-on critical).
Ignoring Specific Vulnerabilities

Sometimes, a known vulnerability might have a low actual risk in your specific context, or there might be no immediate fix available and you’ve accepted the risk.

  • Trivy: Use --ignore-vulnerability or --ignore-policy .
  • Grype: Use --ignore-vuln or specify exclusions in a configuration file.
Example: Ignoring a Trivy Vulnerability

“`yaml

  • name: Run Trivy with ignored vulnerability

uses: aquasec/action-trivy@master

with:

image-ref: your-dockerhub-username/your-app-name:latest

exit-code: ‘1’

ignore-unfixed: true

ignore-vulnerability: ‘CVE-2023-12345’ # Replace with actual CVE

“`

Using Configuration Files

For more complex policies, ignoring numerous vulnerabilities, or defining specific output formats, using configuration files is highly recommended.

Trivy Configuration

Trivy can be configured via a YAML file. You can specify ignored vulnerabilities, severity filters, and more.

“`yaml

trivy-config.yaml

ignore-unfixed: true

ignore-vulnerabilities:

  • “CVE-2023-XXXXX” # Example of ignoring a specific CVE
  • “CVE-2023-YYYYY”

severity:

  • HIGH
  • CRITICAL

“`

And in your workflow:

“`yaml

  • name: Run Trivy with configuration file

uses: aquasec/action-trivy@master

with:

image-ref: your-dockerhub-username/your-app-name:latest

config-path: trivy-config.yaml # Path to your config file in the repo

exit-code: ‘1’

“`

Grype Configuration

Grype also supports configuration files, which are powerful for defining failCondition or ignorance rules.

“`yaml

grype-config.yaml

failCondition: “eq(vulns.MEDIUM, 0) && eq(vulns.HIGH, 0) && eq(vulns.CRITICAL, 0)”

ignorance:

  • vulnerability: “CVE-2023-XXXXX” # Example of ignoring a specific CVE

fix: “None”

“`

And in your workflow:

“`yaml

  • name: Run Grype with configuration file

run: |

grype your-dockerhub-username/your-app-name:latest -c grype-config.yaml

“`

Scanning Different Image Types

While we’ve focused on Docker images pushed to a registry, these tools can also scan images locally built by your workflow.

Scanning Locally Built Images

If you don’t want to push every image to a registry for scanning, you can perform the scan directly after building.

“`yaml

name: Local Container Scan

on:

push:

branches:

  • main

jobs:

scan-local-image:

runs-on: ubuntu-latest

steps:

  • name: Checkout code

uses: actions/checkout@v4

  • name: Build Docker image locally

id: docker_build

run: docker build -t my-local-app:latest .

  • name: Run Trivy on local image

uses: aquasec/action-trivy@master

with:

image-ref: my-local-app:latest # Scan the locally built image

format: ‘table’

exit-code: ‘1’

Similarly for Grype

  • name: Install Grype

run: |

curl -sfL https://raw.githubusercontent.com/anchore/grype/main/install.sh | sh -s — -b /usr/local/bin

  • name: Run Grype on local image

run: grype my-local-app:latest –fail-on high

“`

This is often faster as it avoids registry operations. However, be mindful that this scans the image as it exists on the runner, not necessarily the exact version that would be deployed if you later push a different tag.

Integrating with Pull Requests

A more robust approach is to scan images on pull requests. This way, potential vulnerabilities are flagged before they are merged into your main branch.

Workflow for Pull Requests

“`yaml

name: Pull Request Container Scan

on:

pull_request:

branches:

  • main

jobs:

scan-pr-image:

runs-on: ubuntu-latest

steps:

  • name: Checkout code

uses: actions/checkout@v4

  • name: Set up Docker Buildx

uses: docker/setup-buildx-action@v3

You might not need to login/push if you’re just scanning a temporary image

built from the PR branch. However, if your Dockerfile depends on base images

from a private registry, you might still need to login.

  • name: Build Docker image locally

id: docker_build

run: docker build -t pr-app:latest .

  • name: Run Trivy vulnerability scan

uses: aquasec/action-trivy@master

with:

image-ref: pr-app:latest

format: ‘table’

exit-code: ‘1’

severity: ‘HIGH,CRITICAL’

Add Grype scan here as well if desired.

“`

Important Note for PR Scans: When scanning images on a pull request, you often don’t need to push to a public registry. You can build the image directly on the runner and scan it locally.

This saves time and resources.

Ensure your Dockerfile doesn’t rely on private base images that aren’t accessible to the runner without authentication.

In the realm of DevSecOps, ensuring the security of containerized applications is crucial, and a recent article discusses the importance of integrating automated security audits into CI/CD pipelines. By utilizing tools like Trivy and Grype within GitHub Actions, developers can streamline their security processes effectively. For those interested in enhancing their skills in creating engaging training materials, you might find this article on the best software to create training videos particularly useful, as it provides insights that can complement your understanding of automation in software development.

Beyond Basic Scans: Next Steps

Once you have automated scanning in place, you can further enhance your container security posture.

Generating and Storing SBOMs

Software Bills of Materials (SBOMs) are becoming increasingly important for understanding what’s inside your containers. Grype is excellent for this.

Generating an SBOM with Grype

“`yaml

  • name: Generate SBOM with Grype

run: |

grype . –output sbom-json > sbom.json # Scans the filesystem for dependencies

  • name: Upload SBOM artifact

uses: actions/upload-artifact@v4

with:

name: sbom-report

path: sbom.json

“`

You can then configure your workflow to upload these SBOMs as artifacts, store them in an artifact repository, or even use them in subsequent policy checks.

Integrating with Security Dashboards and Alerts

The json output format from Trivy and Grype is your gateway to more sophisticated integrations.

Custom Scripting for Advanced Actions

You can write custom scripts in your workflow to:

  • Parse the JSON output.
  • Create GitHub Issues for critical vulnerabilities.
  • Send notifications to Slack or other communication platforms.
  • Trigger additional security tools.

For example, to create a GitHub issue on a critical find:

“`yaml

  • name: Parse Trivy JSON and create issue if needed

uses: aquasec/action-trivy@master

with:

image-ref: your-dockerhub-username/your-app-name:latest

format: ‘json’

exit-code: ‘0’ # Don’t fail the job here, we’ll handle it

ignore-unfixed: true

severity: ‘HIGH,CRITICAL’

id: trivy_scan

  • name: Check Trivy scan results and create issue

env:

TRIVY_RESULTS: ${{ steps.trivy_scan.outputs.result }}

run: |

This is a placeholder – you’d need a script to parse TRIVY_RESULTS JSON

and use the GitHub API to create an issue if vulnerabilities are found.

echo “Placeholder: Logic to parse Trivy JSON and create GitHub issues goes here.”

echo “$TRIVY_RESULTS”

“`

You’d typically need a more involved script using jq for JSON parsing and a tool like gh cli or GitHub’s API to create issues.

Policy as Code for Security

Tools like OPA (Open Policy Agent) can be integrated alongside Trivy and Grype. While Trivy and Grype identify vulnerabilities, OPA can enforce your organization’s specific security policies (e.g., “no containers running as root,” “require specific base image labels”). This moves you towards a more declarative security model.

Conclusion

Automating container security audits with Trivy and Grype in GitHub Actions is not just a good practice; it’s becoming a necessity. By integrating these powerful, open-source tools into your CI/CD pipeline, you gain early detection, consistency, and peace of mind. You can start with simple configurations and gradually layer in more advanced features like custom filtering, SBOM generation, and integration with other security tools. The key is to make security a seamless part of your development workflow, not an afterthought.

This proactive approach saves time, reduces risk, and ultimately leads to more secure applications.

FAQs

What is Trivy and Grype?

Trivy and Grype are open-source vulnerability scanners that are used to detect security issues in container images. Trivy focuses on scanning container images for vulnerabilities, while Grype is designed to identify vulnerabilities in software packages within container images.

What are GitHub Actions?

GitHub Actions is a feature of GitHub that allows users to automate tasks within their software development workflows. It enables the creation of custom workflows to build, test, and deploy code directly from GitHub repositories.

How can Trivy and Grype be integrated into GitHub Actions?

Trivy and Grype can be integrated into GitHub Actions by creating custom workflows that include steps to run the vulnerability scans on container images. This allows for automated security audits to be performed as part of the software development process.

What are the benefits of automating container security audits with Trivy and Grype in GitHub Actions?

Automating container security audits with Trivy and Grype in GitHub Actions helps to identify and address security vulnerabilities in container images early in the development process. This can lead to improved overall security and reduced risk of potential security breaches.

Are there any limitations to using Trivy and Grype for container security audits in GitHub Actions?

While Trivy and Grype are effective tools for identifying vulnerabilities in container images, it’s important to note that they are not a complete solution for container security. Additional security measures, such as secure coding practices and regular security updates, should also be implemented to ensure comprehensive security for containerized applications.

Tags: No tags