Skip to content
Notifications
Clear all

Showcase: Automating Aqua image scans with GitHub Actions and Slack alerts.

2 Posts
2 Users
0 Reactions
6 Views
(@pipeline_pepper)
Eminent Member
Joined: 2 months ago
Posts: 14
Topic starter   [#15]

I've been integrating Aqua Security's scanner into our GitHub Actions workflows for a few months now, focusing on shifting security left. The goal was to catch vulnerabilities in container images at the build stage and notify the right teams without blocking developer velocity unnecessarily.

Here's the core workflow I settled on. It triggers on pushes to main and on pull requests, builds a Docker image, scans it with Aqua's `trivy` action, and then conditionally sends findings to a Slack channel.

```yaml
name: Build, Scan, and Alert
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]

jobs:
build-and-scan:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Build Docker image
run: docker build -t my-app:${{ github.sha }} .

- name: Aqua Trivy Scan
uses: aquasecurity/trivy-action@master
with:
image-ref: 'my-app:${{ github.sha }}'
format: 'sarif'
output: 'trivy-results.sarif'
severity: 'CRITICAL,HIGH'

- name: Upload SARIF results
uses: github/codeql-action/upload-sarif@v3
if: always()
with:
sarif_file: 'trivy-results.sarif'
```

The key piece is the Slack alerting, which runs in a separate job. I only want alerts for new critical/high findings on the main branch, not for every PR.

```yaml
slack-alert:
runs-on: ubuntu-latest
needs: build-and-scan
if: github.event_name == 'push' && failure()
steps:
- name: Parse and send Slack alert
env:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_SECURITY_ALERTS }}
run: |
# Simplified example: Check scan results and format message
if grep -q '"level":"error"' trivy-results.sarif; then
curl -X POST -H 'Content-type: application/json'
--data "{"text":"🚨 Aqua scan detected HIGH/CRITICAL vulnerabilities in image for ${{ github.repository }} @ ${{ github.sha }}"}"
$SLACK_WEBHOOK_URL
fi
```

A few gotchas I encountered:
* The `if: failure()` condition on the alert job is crucial. The Trivy action fails the job if it finds vulnerabilities at or above the specified severity threshold. This means the alert job only runs when there's something to report.
* You need to pass the scan results artifact between jobs if you want to parse them for detailed alerts. I used `actions/upload-artifact` and `actions/download-artifact`.
* Tuning the `severity` input and deciding when to fail the build (`exit-code` input) is a team policy decision. We started with failing on CRITICAL only.

This setup has given our security team visibility and allowed developers to get fast feedback in their PRs. Has anyone else built similar pipelines? I'm particularly curious about how you handle baseline management or suppressing false positives in an automated way.

- pipeline_pepper


Build fast, fail fast, fix fast.


   
Quote
(@sre_tales_new)
Eminent Member
Joined: 3 months ago
Posts: 17
 

Nice integration, and I like the use of SARIF for the GitHub integration. We went a similar route, but we hit a scaling issue you might want to watch for. Sending Slack alerts on every PR scan for `CRITICAL,HIGH` led to alert fatigue for our platform team when a vulnerable base image propagated across a dozen microservices. The channel became noise.

We added a severity threshold check *before* the Slack step to only alert if the count of `CRITICAL` findings was >0 *or* `HIGH` findings exceeded, say, 10. We used `trivy`'s `--exit-code` initially but now parse the JSON report with `jq` to get the counts and include them in the Slack message. That way the alert itself contains the metric that triggered it, e.g., "Scan found 14 HIGH severity CVEs".

Also, consider adding the image tag to your Slack message. When an alert fires on `main` post-merge, you need to know exactly which image hash to roll back or patch.


-- sre_tales


   
ReplyQuote