Module 12.5: Trivy - The Swiss Army Knife of Security Scanning
Complexity: [MEDIUM]
Section titled “Complexity: [MEDIUM]”Time to Complete: 45-50 minutes
Section titled “Time to Complete: 45-50 minutes”Prerequisites
Section titled “Prerequisites”Before starting this module, you should have completed:
- DevSecOps Discipline - Security scanning concepts
- Container fundamentals (images, Dockerfiles)
- Basic Kubernetes knowledge
- CI/CD basics
What You’ll Be Able to Do
Section titled “What You’ll Be Able to Do”After completing this module, you will be able to:
- Deploy Trivy for comprehensive vulnerability scanning of container images, filesystems, and Git repositories
- Configure Trivy in CI/CD pipelines with severity thresholds and ignore policies for practical scanning
- Implement Trivy Operator for continuous Kubernetes cluster scanning with vulnerability and config audit reports
- Compare Trivy’s open-source scanning against commercial alternatives for enterprise security requirements
Why This Module Matters
Section titled “Why This Module Matters”The Open Source Security Scanner That Does Everything
The security architect stared at her spreadsheet in disbelief. After three months of evaluating security tools, she had mapped out what her fintech startup needed to meet SOC2 requirements: Grype for container scanning ($0, but no IaC), Checkov for Terraform ($0, but no containers), Syft for SBOMs ($0, but separate from scanning), Gitleaks for secrets ($0, but another integration), and Snyk for the dashboard ($15,000/year for 30 developers).
“That’s five tools, five CI integrations, five different output formats, and $15K,” she reported to the CISO. “And we still need someone to correlate all the findings.”
“What about that Trivy thing Harbor uses?” the CISO asked.
She hadn’t seriously considered it—surely a free tool couldn’t do everything. But after a two-hour proof of concept, she deleted her spreadsheet. Trivy did container scanning, IaC scanning, SBOM generation, secret detection, and Kubernetes cluster scanning. One tool. One configuration. One output format.
The fintech passed their SOC2 audit with zero additional tooling costs. The security architect became Trivy’s biggest internal advocate—and eventually, an Aqua Security customer success story.
Trivy isn’t the deepest scanner in any single category, but it’s remarkably good across all of them. It’s completely free, backed by Aqua Security, and it’s become the default scanner in Harbor, AWS Inspector, and countless CI pipelines.
Did You Know?
Section titled “Did You Know?”-
Trivy started as a weekend project and became a CNCF project in 3 years — Teppei Fukuda, an Aqua Security engineer, built Trivy in 2019 because existing scanners were too slow and required too much setup. He optimized the vulnerability database download and caching until first scan ran in under 15 seconds. By 2022, Trivy had 15,000+ GitHub stars and joined the CNCF sandbox. Today it’s the most-starred container security project on GitHub.
-
AWS built Inspector on Trivy because they couldn’t beat it — When AWS launched the new Inspector in 2021, security researchers noticed something interesting: the vulnerability signatures matched Trivy exactly. AWS confirmed they use Trivy’s engine under the hood, adding their own database updates. Even Amazon couldn’t build a better scanner—so they adopted the open source one.
-
Harbor chose Trivy after a year-long evaluation that tested 8 scanners — The Harbor team evaluated Clair, Anchore, Aqua Scanner, and five others before selecting Trivy as the default. The deciding factors: scan speed (10x faster than Clair), accuracy (lowest false positive rate), and operational simplicity (single binary, no database server required).
-
The Log4Shell incident made Trivy famous overnight — On December 9, 2021, the Log4j vulnerability (CVE-2021-44228) was disclosed. Within 4 hours, Trivy had detection rules. Within 24 hours, thousands of companies had run
trivy fs --scanners vuln .for the first time. Trivy downloads spiked 400% that week—and many of those emergency users became permanent adopters. -
In March 2026, Trivy itself was compromised in the TeamPCP supply chain attack — Threat actor TeamPCP rewrote Git tags in the
trivy-actionGitHub Action repository, pointing tagv0.69.4to a malicious release. The compromised action exfiltrated CI/CD secrets from any pipeline that usedtrivy-action@latestor an unpinned tag. The most high-profile victim was LiteLLM (3.4M daily PyPI downloads), whose stolenPYPI_PUBLISHtoken was used to push backdoored packages that deployed persistent pods into victim Kubernetes clusters. The incident proved that even trusted security tools can become attack vectors — and that pinning GitHub Actions to commit SHAs (not tags) is not optional. See Module 4.4: Supply Chain Security for the full postmortem.
What Trivy Scans
Section titled “What Trivy Scans”TRIVY CAPABILITIES─────────────────────────────────────────────────────────────────
┌─────────────────────────────────────────────────────────────────┐│ TRIVY TARGETS │├─────────────────────────────────────────────────────────────────┤│ ││ CONTAINER IMAGES ││ ┌───────────────────────────────────────────────────────────┐ ││ │ • OS packages (Alpine, Debian, Ubuntu, RHEL, etc.) │ ││ │ • Language packages (npm, pip, gem, etc.) │ ││ │ • Licenses │ ││ │ • Secrets embedded in images │ ││ │ • Misconfigurations │ ││ └───────────────────────────────────────────────────────────┘ ││ ││ FILESYSTEMS & REPOSITORIES ││ ┌───────────────────────────────────────────────────────────┐ ││ │ • Dependencies (package-lock.json, go.sum, etc.) │ ││ │ • Secrets in code │ ││ │ • IaC misconfigurations │ ││ │ • License compliance │ ││ └───────────────────────────────────────────────────────────┘ ││ ││ KUBERNETES ││ ┌───────────────────────────────────────────────────────────┐ ││ │ • Cluster misconfigurations │ ││ │ • Workload vulnerabilities │ ││ │ • RBAC analysis │ ││ │ • Network policies │ ││ │ • Secrets in cluster │ ││ └───────────────────────────────────────────────────────────┘ ││ ││ INFRASTRUCTURE AS CODE ││ ┌───────────────────────────────────────────────────────────┐ ││ │ • Terraform │ ││ │ • CloudFormation │ ││ │ • Kubernetes YAML │ ││ │ • Helm charts │ ││ │ • Docker Compose │ ││ │ • Ansible │ ││ └───────────────────────────────────────────────────────────┘ ││ ││ SBOM ││ ┌───────────────────────────────────────────────────────────┐ ││ │ • Generate CycloneDX │ ││ │ • Generate SPDX │ ││ │ • Scan existing SBOMs │ ││ │ • Attestations │ ││ └───────────────────────────────────────────────────────────┘ ││ │└─────────────────────────────────────────────────────────────────┘Installation
Section titled “Installation”# macOS (Homebrew)brew install trivy
# Linux (apt)sudo apt-get install wget apt-transport-https gnupg lsb-releasewget -qO - https://aquasecurity.github.io/trivy-repo/deb/public.key | sudo apt-key add -echo deb https://aquasecurity.github.io/trivy-repo/deb $(lsb_release -sc) main | sudo tee -a /etc/apt/sources.list.d/trivy.listsudo apt-get updatesudo apt-get install trivy
# Linux (script)curl -sfL https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/install.sh | sh -s -- -b /usr/local/bin
# Docker (no installation)docker run aquasec/trivy image nginx:latest
# Verify installationtrivy versionContainer Scanning
Section titled “Container Scanning”Basic Usage
Section titled “Basic Usage”# Scan an imagetrivy image nginx:latest
# Scan local image (not from registry)trivy image --input myapp.tar
# Scan with severity filtertrivy image --severity HIGH,CRITICAL nginx:latest
# Scan only OS packagestrivy image --vuln-type os nginx:latest
# Scan only language packagestrivy image --vuln-type library nginx:latest
# Output as JSONtrivy image --format json --output results.json nginx:latest
# Output as SARIF (for GitHub Security)trivy image --format sarif --output trivy.sarif nginx:latestUnderstanding Results
Section titled “Understanding Results”TRIVY CONTAINER SCAN OUTPUT─────────────────────────────────────────────────────────────────
$ trivy image nginx:1.21
nginx:1.21 (debian 11.2)========================Total: 142 (UNKNOWN: 0, LOW: 98, MEDIUM: 31, HIGH: 11, CRITICAL: 2)
┌───────────────────┬──────────────────┬──────────┬────────────────┐│ Library │ Vulnerability │ Severity │ Fixed Version │├───────────────────┼──────────────────┼──────────┼────────────────┤│ curl │ CVE-2023-38545 │ CRITICAL │ 7.74.0-1.3+deb ││ │ │ │ 11u10 │├───────────────────┼──────────────────┼──────────┼────────────────┤│ openssl │ CVE-2023-5678 │ HIGH │ 1.1.1n-0+deb11 ││ │ │ │ u5 │├───────────────────┼──────────────────┼──────────┼────────────────┤│ ... │ ... │ ... │ ... │└───────────────────┴──────────────────┴──────────┴────────────────┘
Node.js (package.json)======================Total: 5 (HIGH: 3, MEDIUM: 2)
┌───────────────────┬──────────────────┬──────────┬────────────────┐│ Library │ Vulnerability │ Severity │ Fixed Version │├───────────────────┼──────────────────┼──────────┼────────────────┤│ lodash │ CVE-2021-23337 │ HIGH │ 4.17.21 ││ axios │ CVE-2021-3749 │ HIGH │ 0.21.2 │└───────────────────┴──────────────────┴──────────┴────────────────┘Scanning Configuration
Section titled “Scanning Configuration”scan: # Skip update of vulnerability database skip-db-update: false
# Scanners to use scanners: - vuln - secret - misconfig
severity: - CRITICAL - HIGH - MEDIUM
# Ignore unfixed vulnerabilitiesignore-unfixed: true
# Timeouttimeout: 10m
# Cache directorycache-dir: /tmp/trivy-cache
# Exit code when vulnerabilities foundexit-code: 1# Use config filetrivy image --config trivy.yaml nginx:latestFilesystem Scanning
Section titled “Filesystem Scanning”Scanning Source Code
Section titled “Scanning Source Code”# Scan current directorytrivy fs .
# Scan specific directorytrivy fs /path/to/project
# Include secrets scanningtrivy fs --scanners vuln,secret,misconfig .
# Scan for specific package typestrivy fs --pkg-types npm,pip .Scanning Git Repositories
Section titled “Scanning Git Repositories”# Scan remote repositorytrivy repo https://github.com/aquasecurity/trivy
# Scan specific branchtrivy repo --branch develop https://github.com/myorg/myrepo
# Scan with commit (for reproducibility)trivy repo --commit abc123 https://github.com/myorg/myrepoInfrastructure as Code Scanning
Section titled “Infrastructure as Code Scanning”Terraform
Section titled “Terraform”# Scan Terraform filestrivy config ./terraform/
# Scan with specific severitytrivy config --severity HIGH,CRITICAL ./terraform/Example Terraform Findings
Section titled “Example Terraform Findings”TRIVY IAC SCAN - TERRAFORM─────────────────────────────────────────────────────────────────
$ trivy config ./terraform/
main.tf (terraform)===================Tests: 45 (SUCCESSES: 38, FAILURES: 7, EXCEPTIONS: 0)Failures: 7 (HIGH: 3, MEDIUM: 4)
HIGH: S3 bucket does not have encryption enabled──────────────────────────────────────────────────────────────────A server-side encryption is not configured for S3 bucket.
File: main.tfLine: 25-30
25 │ resource "aws_s3_bucket" "data" { 26 │ bucket = "my-data-bucket" 27 │ acl = "private" 28 │ }
See: https://avd.aquasec.com/misconfig/avd-aws-0088
──────────────────────────────────────────────────────────────────HIGH: Security group allows ingress from 0.0.0.0/0──────────────────────────────────────────────────────────────────Security group rule allows all traffic from 0.0.0.0/0
File: security.tfLine: 12-20
12 │ resource "aws_security_group_rule" "ssh" { 13 │ type = "ingress" 14 │ from_port = 22 15 │ to_port = 22 16 │ protocol = "tcp" 17 │ cidr_blocks = ["0.0.0.0/0"] # BAD! 18 │ }Kubernetes Manifests
Section titled “Kubernetes Manifests”# Scan Kubernetes YAMLtrivy config ./k8s/
# Scan Helm charttrivy config ./helm/mychart/Example Kubernetes Findings
Section titled “Example Kubernetes Findings”TRIVY K8S CONFIG SCAN─────────────────────────────────────────────────────────────────
deployment.yaml (kubernetes)============================Tests: 23 (SUCCESSES: 18, FAILURES: 5)
HIGH: Container runs as root──────────────────────────────────────────────────────────────────Running as root gives the container full access to the host
File: deployment.yamlLine: 25
23 │ containers: 24 │ - name: app 25 │ securityContext: 26 │ runAsUser: 0 # BAD!
Recommendation: securityContext: runAsNonRoot: true runAsUser: 1000
──────────────────────────────────────────────────────────────────MEDIUM: Container has no resource limits──────────────────────────────────────────────────────────────────Resource limits prevent container from consuming excess resources
File: deployment.yamlLine: 24-30
Recommendation: resources: limits: cpu: "500m" memory: "512Mi" requests: cpu: "100m" memory: "128Mi"Secret Detection
Section titled “Secret Detection”# Scan for secrets in filesystemtrivy fs --scanners secret .
# Scan container image for secretstrivy image --scanners secret nginx:latest
# Scan Git repository historytrivy repo --scanners secret https://github.com/myorg/myrepoExample Secret Findings
Section titled “Example Secret Findings”SECRET SCAN RESULTS─────────────────────────────────────────────────────────────────
$ trivy fs --scanners secret .
Secrets Found: 3
─────────────────────────────────────────────────────────────────HIGH: AWS Access Key IDCategory: AWSFile: config/prod.envLine: 5
5 │ AWS_ACCESS_KEY_ID=AKIAIOSFODNN7EXAMPLE
─────────────────────────────────────────────────────────────────HIGH: Private KeyCategory: Asymmetric Private KeyFile: certs/server.keyLine: 1
1 │ -----BEGIN RSA PRIVATE KEY-----
─────────────────────────────────────────────────────────────────MEDIUM: Generic API KeyCategory: GenericFile: src/api.jsLine: 23
23 │ const API_KEY = "sk_live_abcd1234567890";SBOM Generation
Section titled “SBOM Generation”Creating SBOMs
Section titled “Creating SBOMs”# Generate CycloneDX SBOMtrivy image --format cyclonedx --output sbom.json nginx:latest
# Generate SPDX SBOMtrivy image --format spdx-json --output sbom.spdx.json nginx:latest
# Generate SBOM for filesystemtrivy fs --format cyclonedx --output sbom.json .
# Generate SBOM with VEX (Vulnerability Exploitability eXchange)trivy image --format cyclonedx --output sbom.json --vex vex.json nginx:latestScanning Existing SBOMs
Section titled “Scanning Existing SBOMs”# Scan a CycloneDX SBOM for vulnerabilitiestrivy sbom sbom.json
# Scan SPDX SBOMtrivy sbom sbom.spdx.jsonKubernetes Cluster Scanning
Section titled “Kubernetes Cluster Scanning”Trivy Operator
Section titled “Trivy Operator”# Install Trivy Operatorhelm repo add aqua https://aquasecurity.github.io/helm-charts/helm repo update
helm install trivy-operator aqua/trivy-operator \ --namespace trivy-system \ --create-namespace \ --set trivy.ignoreUnfixed=true
# View vulnerability reportskubectl get vulnerabilityreports -Akubectl get configauditreports -Akubectl get exposedsecretreports -AManual Cluster Scanning
Section titled “Manual Cluster Scanning”# Scan cluster (requires kubeconfig)trivy k8s cluster
# Scan specific namespacetrivy k8s --namespace production cluster
# Scan specific resourcestrivy k8s --include-namespaces default deployment/nginx
# Generate reporttrivy k8s cluster --report summaryExample Cluster Report
Section titled “Example Cluster Report”KUBERNETES CLUSTER SCAN─────────────────────────────────────────────────────────────────
$ trivy k8s cluster --report summary
Summary Report==============
Namespace: default┌────────────────┬───────────┬──────────┬──────────┬──────────┐│ Resource │ Critical │ High │ Medium │ Low │├────────────────┼───────────┼──────────┼──────────┼──────────┤│ nginx-deploy │ 0 │ 3 │ 12 │ 45 ││ redis │ 2 │ 5 │ 8 │ 23 ││ postgres │ 1 │ 7 │ 15 │ 34 │└────────────────┴───────────┴──────────┴──────────┴──────────┘
Misconfigurations:┌────────────────┬───────────┬──────────┬──────────┬──────────┐│ Resource │ Critical │ High │ Medium │ Low │├────────────────┼───────────┼──────────┼──────────┼──────────┤│ nginx-deploy │ 0 │ 2 │ 3 │ 1 ││ redis │ 1 │ 1 │ 2 │ 0 │└────────────────┴───────────┴──────────┴──────────┴──────────┘CI/CD Integration
Section titled “CI/CD Integration”GitHub Actions
Section titled “GitHub Actions”name: Security Scan
on: push: branches: [main] pull_request: branches: [main]
jobs: scan: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4
- name: Trivy filesystem scan uses: aquasecurity/trivy-action@master with: scan-type: 'fs' scan-ref: '.' severity: 'CRITICAL,HIGH' format: 'sarif' output: 'trivy-fs.sarif'
- name: Build image run: docker build -t myapp:${{ github.sha }} .
- name: Trivy image scan uses: aquasecurity/trivy-action@master with: image-ref: 'myapp:${{ github.sha }}' format: 'sarif' output: 'trivy-image.sarif' severity: 'CRITICAL,HIGH' exit-code: '1' # Fail on findings
- name: Trivy config scan uses: aquasecurity/trivy-action@master with: scan-type: 'config' scan-ref: './terraform' severity: 'CRITICAL,HIGH' format: 'sarif' output: 'trivy-config.sarif'
- name: Upload to GitHub Security uses: github/codeql-action/upload-sarif@v2 with: sarif_file: '.'GitLab CI
Section titled “GitLab CI”stages: - scan
trivy-scan: stage: scan image: name: aquasec/trivy:latest entrypoint: [""] script: # Filesystem scan - trivy fs --exit-code 0 --severity HIGH,CRITICAL .
# Image scan - trivy image --exit-code 1 --severity CRITICAL $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
# Config scan - trivy config --exit-code 0 --severity HIGH,CRITICAL ./terraform/ artifacts: reports: container_scanning: gl-container-scanning-report.jsonJenkins Pipeline
Section titled “Jenkins Pipeline”pipeline { agent any
stages { stage('Security Scan') { steps { sh ''' # Install Trivy curl -sfL https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/install.sh | sh -s -- -b /usr/local/bin
# Scan filesystem trivy fs --severity HIGH,CRITICAL --exit-code 0 .
# Build and scan image docker build -t myapp:${BUILD_NUMBER} . trivy image --severity CRITICAL --exit-code 1 myapp:${BUILD_NUMBER}
# Scan IaC trivy config --severity HIGH,CRITICAL ./terraform/ ''' } } }
post { always { archiveArtifacts artifacts: '**/trivy-*.json', allowEmptyArchive: true } }}Ignoring Findings
Section titled “Ignoring Findings”Using .trivyignore
Section titled “Using .trivyignore”# Ignore specific CVECVE-2023-12345
# Ignore with expirationCVE-2023-67890 exp:2024-12-31
# Ignore by packagepkg:npm/lodash@4.17.20
# Ignore misconfig by IDAVD-AWS-0088Using VEX (Vulnerability Exploitability eXchange)
Section titled “Using VEX (Vulnerability Exploitability eXchange)”{ "@context": "https://openvex.dev/ns/v0.2.0", "@id": "https://example.com/vex/myapp", "author": "Security Team", "timestamp": "2024-01-15T00:00:00Z", "statements": [ { "vulnerability": { "@id": "CVE-2023-12345" }, "products": [ { "@id": "pkg:docker/myapp@1.0.0" } ], "status": "not_affected", "justification": "vulnerable_code_not_in_execute_path", "impact_statement": "The vulnerable function is not called in our code" } ]}# Use VEX filetrivy image --vex vex.json myapp:latestWar Story: The Registry Gate
Section titled “War Story: The Registry Gate”How a healthcare company saved $2.1M in compliance costs with a free tool
The Situation
Section titled “The Situation”A 200-person healthcare company processing $340M in annual claims was facing a crisis. Their HIPAA compliance audit was in 90 days, and the auditor’s preliminary report was damning: “No documented evidence that container images are scanned before production deployment. No software bill of materials. No vulnerability tracking.”
The estimated cost to fix this with commercial tools:
- Snyk Enterprise: $180K/year (200 developers × $75/month)
- Additional SBOM tooling: $40K/year
- Compliance dashboard: $35K/year
- Integration consulting: $100K one-time
The CISO looked at the $455K first-year estimate and wondered if there was another way.
The Architecture
Section titled “The Architecture”SECURE IMAGE PIPELINE─────────────────────────────────────────────────────────────────
┌─────────────────────────────────────────────────────────────────┐│ DEVELOPER PUSHES CODE │└────────────────────────────┬────────────────────────────────────┘ │ ▼┌─────────────────────────────────────────────────────────────────┐│ CI PIPELINE (GitHub Actions) ││ ┌───────────────────────────────────────────────────────────┐ ││ │ 1. Build image │ ││ │ 2. Trivy scan (fail on CRITICAL) │ ││ │ 3. Generate SBOM │ ││ │ 4. Sign with Cosign │ ││ │ 5. Push to staging registry │ ││ └───────────────────────────────────────────────────────────┘ │└────────────────────────────┬────────────────────────────────────┘ │ ▼┌─────────────────────────────────────────────────────────────────┐│ HARBOR REGISTRY ││ ┌───────────────────────────────────────────────────────────┐ ││ │ • Trivy scanner enabled │ ││ │ • Block images with CRITICAL vulns │ ││ │ • Verify Cosign signatures │ ││ │ • Store SBOM with image │ ││ └───────────────────────────────────────────────────────────┘ │└────────────────────────────┬────────────────────────────────────┘ │ ▼┌─────────────────────────────────────────────────────────────────┐│ KUBERNETES ADMISSION ││ ┌───────────────────────────────────────────────────────────┐ ││ │ Kyverno policy: │ ││ │ • Only allow images from Harbor │ ││ │ • Require signature verification │ ││ │ • Require scan timestamp < 24h │ ││ └───────────────────────────────────────────────────────────┘ │└────────────────────────────┬────────────────────────────────────┘ │ ▼┌─────────────────────────────────────────────────────────────────┐│ PRODUCTION CLUSTER ││ ┌───────────────────────────────────────────────────────────┐ ││ │ Trivy Operator: │ ││ │ • Continuous scanning of running images │ ││ │ • Alert on new vulnerabilities │ ││ │ • Generate compliance reports │ ││ └───────────────────────────────────────────────────────────┘ │└─────────────────────────────────────────────────────────────────┘The Implementation
Section titled “The Implementation”# CI: GitHub Actionsname: Secure Build
on: [push]
jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4
- name: Build image run: docker build -t ${{ env.IMAGE }}:${{ github.sha }} .
- name: Trivy scan uses: aquasecurity/trivy-action@master with: image-ref: '${{ env.IMAGE }}:${{ github.sha }}' exit-code: '1' severity: 'CRITICAL' format: 'json' output: 'trivy-results.json'
- name: Generate SBOM run: | trivy image --format cyclonedx \ --output sbom.json \ ${{ env.IMAGE }}:${{ github.sha }}
- name: Sign image run: | cosign sign --key env://COSIGN_KEY \ ${{ env.IMAGE }}:${{ github.sha }}
- name: Attach SBOM run: | cosign attach sbom --sbom sbom.json \ ${{ env.IMAGE }}:${{ github.sha }}
- name: Push to Harbor run: | docker push ${{ env.IMAGE }}:${{ github.sha }}# Kyverno admission policyapiVersion: kyverno.io/v1kind: ClusterPolicymetadata: name: require-scanned-imagesspec: validationFailureAction: enforce rules: - name: check-trivy-scan match: resources: kinds: - Pod verifyImages: - imageReferences: - "harbor.example.com/*" attestations: - predicateType: cosign.sigstore.dev/attestation/vuln/v1 conditions: - all: # No critical vulnerabilities - key: "{{ scanner.result.criticalCount }}" operator: Equals value: "0" # Scan within last 24 hours - key: "{{ time_since('', scanner.scanTime, '', 'h') }}" operator: LessThan value: "24"Results
Section titled “Results”| Metric | Before | After |
|---|---|---|
| Critical vulns in prod | Unknown | 0 |
| Mean time to patch | 2 weeks | 4 hours |
| Compliance audit prep | 2 weeks | Automated |
| Images blocked/month | 0 | ~50 |
| Developer friction | None | Minimal (clear feedback) |
Financial Impact (5-Year TCO):
| Category | Commercial Approach | Trivy Approach |
|---|---|---|
| Year 1 tooling + setup | $455,000 | $25,000 (Harbor + Kyverno setup) |
| Years 2-5 licensing | $1,020,000 ($255K × 4) | $0 |
| Ongoing maintenance | $120,000 | $45,000 |
| 5-Year Total | $1,595,000 | $70,000 |
| Savings | $1,525,000 |
The HIPAA audit passed with zero findings. The company used the savings to fund a dedicated platform security engineer who expanded the Trivy implementation to their data science infrastructure.
Three years later, the same setup—with zero licensing costs—had processed 2.3 million container scans, generated 890,000 SBOMs, and blocked 4,200 vulnerable images from production.
Lessons Learned
Section titled “Lessons Learned”- Shift left, but also shift right - Scan in CI AND continuously in cluster
- Block critical only - High/Medium in CI would cause too much friction
- SBOM enables future scans - When new CVE drops, scan existing SBOMs
- Signatures prevent bypass - Can’t skip CI and push directly
- Clear feedback matters - Developers need actionable results, not just “blocked”
Trivy vs Alternatives
Section titled “Trivy vs Alternatives”SCANNER COMPARISON─────────────────────────────────────────────────────────────────
Trivy Grype Clair Snyk─────────────────────────────────────────────────────────────────TARGETSContainer images ✓✓ ✓✓ ✓ ✓Filesystems ✓ ✓ ✗ ✓Git repos ✓ ✗ ✗ ✓IaC scanning ✓✓ ✗ ✗ ✓K8s clusters ✓✓ ✗ ✗ ✗SBOM generation ✓✓ ✓ (Syft) ✗ ✓Secret scanning ✓ ✗ ✗ ✗
FEATURESSpeed Fast Fastest Medium MediumOffline mode ✓ ✓ ✗ ✗Custom policies ✓ (Rego) ✗ ✗ ✓CI integration ✓✓ ✓ ✓ ✓✓IDE integration ✓ ✗ ✗ ✓✓Auto-fix ✗ ✗ ✗ ✓✓
PRICINGFree ✓ ✓ ✓ TieredCommercial support Aqua Anchore CoreOS Snyk
BEST FOR:─────────────────────────────────────────────────────────────────Trivy: All-in-one, Kubernetes-native, freeGrype: Speed-focused, SBOM ecosystem (with Syft)Clair: Legacy, Quay registry integrationSnyk: Developer experience, auto-fix, IDECommon Mistakes
Section titled “Common Mistakes”| Mistake | Why It’s Bad | Better Approach |
|---|---|---|
| Blocking on all severities | Everything blocked, developers bypass | Block CRITICAL only, alert on HIGH |
| No .trivyignore | Same false positives repeatedly | Document accepted risks |
| Scanning without caching | Slow CI, redundant downloads | Use Trivy cache, GitHub cache action |
| Only scanning in CI | New CVEs affect running containers | Deploy Trivy Operator |
| Ignoring IaC findings | Misconfigs as dangerous as vulns | Include config scanning |
| No SBOM generation | Can’t track what’s deployed | Generate SBOM with every build |
| Human review of all findings | Doesn’t scale | Automated policies, exceptions |
| Different tools per target | Inconsistent results, more work | Trivy handles most targets |
Hands-On Exercise
Section titled “Hands-On Exercise”Task: Implement Full Trivy Pipeline
Section titled “Task: Implement Full Trivy Pipeline”Objective: Set up Trivy for comprehensive security scanning across code, containers, and config.
Success Criteria:
- Filesystem scan running
- Container image scan with SBOM
- IaC scan for Terraform/Kubernetes
- .trivyignore configured for accepted risks
# 1. Create test projectmkdir trivy-lab && cd trivy-lab
# 2. Create vulnerable Dockerfilecat > Dockerfile << 'EOF'FROM node:16WORKDIR /appCOPY package*.json ./RUN npm installCOPY . .CMD ["node", "server.js"]EOF
# 3. Create package.json with vulnerable depscat > package.json << 'EOF'{ "name": "trivy-lab", "version": "1.0.0", "dependencies": { "express": "4.17.1", "lodash": "4.17.20" }}EOF
# 4. Create Terraform with misconfigmkdir terraformcat > terraform/main.tf << 'EOF'resource "aws_s3_bucket" "data" { bucket = "my-data-bucket"}
resource "aws_security_group" "web" { name = "web-sg"
ingress { from_port = 22 to_port = 22 protocol = "tcp" cidr_blocks = ["0.0.0.0/0"] }}EOF
# 5. Create Kubernetes manifestmkdir k8scat > k8s/deployment.yaml << 'EOF'apiVersion: apps/v1kind: Deploymentmetadata: name: webspec: replicas: 1 selector: matchLabels: app: web template: metadata: labels: app: web spec: containers: - name: web image: nginx:latest securityContext: runAsUser: 0 privileged: trueEOF
# 6. Install Trivybrew install trivy # or your preferred method
# 7. Run filesystem scantrivy fs --scanners vuln,secret .
# 8. Build and scan imagedocker build -t trivy-lab:latest .trivy image trivy-lab:latest
# 9. Generate SBOMtrivy image --format cyclonedx --output sbom.json trivy-lab:latest
# 10. Scan IaCtrivy config ./terraform/trivy config ./k8s/
# 11. Create .trivyignore for accepted riskscat > .trivyignore << 'EOF'# Accept this CVE until patch availableCVE-2023-12345 exp:2024-06-30
# False positive in our contextAVD-AWS-0088EOF
# 12. Re-run with ignore filetrivy config ./terraform/ # Should skip AVD-AWS-0088Verification
Section titled “Verification”# Verify findings were detectedtrivy fs . --severity CRITICAL,HIGH | grep -c "vulnerability"
# Verify SBOM was createdcat sbom.json | jq '.components | length'
# Verify IaC issues foundtrivy config ./terraform/ | grep -c "FAIL"Question 1
Section titled “Question 1”What types of targets can Trivy scan?
Show Answer
Container images, filesystems, Git repos, Kubernetes clusters, IaC, and SBOMs
Trivy is an all-in-one scanner that covers:
- Container images (OS packages + language packages)
- Filesystems and Git repositories
- Infrastructure as Code (Terraform, CloudFormation, K8s, Helm)
- Running Kubernetes clusters
- Existing SBOMs (CycloneDX, SPDX)
This eliminates the need for multiple specialized tools.
Question 2
Section titled “Question 2”What is the Trivy Operator?
Show Answer
A Kubernetes operator for continuous security scanning of cluster workloads
The Trivy Operator:
- Automatically scans new workloads when deployed
- Creates VulnerabilityReports as Kubernetes CRDs
- Scans for misconfigurations (ConfigAuditReports)
- Detects exposed secrets (ExposedSecretReports)
- Enables continuous monitoring, not just CI/CD scanning
Question 3
Section titled “Question 3”What formats does Trivy support for SBOM generation?
Show Answer
CycloneDX and SPDX
# CycloneDXtrivy image --format cyclonedx myapp:latest
# SPDXtrivy image --format spdx-json myapp:latestSBOMs can also be scanned for vulnerabilities, allowing you to check existing software bills of materials.
Question 4
Section titled “Question 4”How does .trivyignore work?
Show Answer
A file listing CVEs or misconfig IDs to skip during scans
CVE-2023-12345 # Ignore this CVECVE-2023-67890 exp:2024-12-31 # Ignore until dateAVD-AWS-0088 # Ignore this misconfigEntries can have expiration dates to ensure temporary exceptions are reviewed.
Question 5
Section titled “Question 5”What’s the difference between trivy fs and trivy repo?
Show Answer
fs scans local filesystems; repo scans remote Git repositories
trivy fs .- Scans the current directorytrivy fs /path/to/code- Scans a specific pathtrivy repo https://github.com/org/repo- Clones and scans remote repotrivy repo --branch dev https://...- Scans specific branch
repo is useful for scanning third-party code without cloning it first.
Question 6
Section titled “Question 6”How do you make Trivy fail a CI build on critical vulnerabilities?
Show Answer
Use --exit-code 1 with --severity CRITICAL
trivy image --exit-code 1 --severity CRITICAL myapp:latestThe command returns exit code 1 if any CRITICAL vulnerabilities are found, failing the CI step. You can also use:
--exit-code 0- Always succeed (report only)--ignore-unfixed- Skip vulnerabilities with no fix available
Question 7
Section titled “Question 7”What is VEX and how does Trivy use it?
Show Answer
Vulnerability Exploitability eXchange - a standard for documenting vulnerability applicability
VEX allows you to document that a CVE:
- Doesn’t affect your product
- Is not reachable in your code
- Has been mitigated
trivy image --vex vex.json myapp:latestTrivy respects VEX statements to suppress irrelevant findings with documented justification.
Question 8
Section titled “Question 8”Why use Trivy over specialized tools like Checkov (IaC) or Grype (containers)?
Show Answer
Single tool, unified configuration, consistent output across all targets
Benefits of Trivy’s all-in-one approach:
- One tool to install and maintain
- One configuration file format
- One output format (JSON, SARIF, table)
- Consistent severity ratings
- Simpler CI/CD integration
Specialized tools might be deeper in one area, but Trivy is “good enough” for most use cases with less operational overhead.
Key Takeaways
Section titled “Key Takeaways”- All-in-one scanner - Containers, filesystems, IaC, secrets, SBOM
- Free and open source - CNCF project, no licensing costs
- Fast and lightweight - Single binary, minimal dependencies
- Built into Harbor - Default scanner for enterprise registries
- Kubernetes-native - Operator for continuous cluster scanning
- SBOM generation included - CycloneDX and SPDX
- VEX support - Document vulnerability applicability
- Multiple output formats - JSON, SARIF, table, template
- Ignore files for exceptions - Document accepted risks
- Exit codes for CI gates - Fail on specific severities
Next Steps
Section titled “Next Steps”- Related: Module 13.1: Harbor - Registry with Trivy integration
- Related: Module 4.4: Supply Chain Security - SBOM and signing
- Related: Module 12.4: Snyk - Compare with commercial alternative
Further Reading
Section titled “Further Reading”- Trivy Documentation
- Trivy GitHub Repository
- Trivy Operator
- Aqua Vulnerability Database
- VEX Specification
“The best scanner is the one you actually run. Trivy makes security scanning so easy there’s no excuse not to do it everywhere.”