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
Dockerfileto 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
on: push: This triggers the workflow when code is pushed to themainbranch. You can adjust this to trigger on pull requests, tags, etc.runs-on: ubuntu-latest: Specifies the runner environment.actions/checkout@v4: Checks out your repository code.docker/setup-buildx-action@v3: Sets up Docker Buildx, which is essential for building modern Docker images and can improve build performance.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.docker/build-push-action@v5: This step builds your Docker image and pushes it to your registry. Crucially, thetagsshould match what Trivy will scan.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:tableis human-readable in the logs. For more complex automation (e.g., creating issues based on findings),jsonis 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
- Checkout, Buildx, Login: Similar to the Trivy workflow, these steps prepare your environment and build/push your image.
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.Install Grype: This uses a convenient script provided by Anchore to download and install Grype into your runner’s PATH.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 jsonif 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
--severityflag (e.g.,--severity HIGH,CRITICAL). - Grype: Use the
--fail-onflag (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-vulnerabilityor--ignore-policy. - Grype: Use
--ignore-vulnor 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.

