Trivy: Complete Container and Infrastructure Security Scanner Guide
Trivy is a comprehensive, open-source security scanner by Aqua Security that detects vulnerabilities, misconfigurations, secrets, and licenses in container images, filesystems, git repositories, Kubernetes clusters, and Infrastructure as Code. As the most popular container security scanner in the CNCF ecosystem, Trivy is essential for any DevSecOps pipeline.
What is Trivy?
Trivy is an all-in-one security scanner that covers:
Key Features
- Container Image Scanning: Detect OS and language package vulnerabilities
- Filesystem Scanning: Scan local project directories
- IaC Scanning: Analyze Terraform, CloudFormation, Kubernetes manifests
- Kubernetes Scanning: Scan running clusters for misconfigurations
- SBOM Generation: Create Software Bill of Materials (CycloneDX, SPDX)
- Secret Detection: Find leaked credentials and API keys
- License Scanning: Identify package license compliance issues
Trivy vs. Other Security Scanners
| Feature | Trivy | Grype | Snyk | Clair | Docker Scout |
|---|---|---|---|---|---|
| Cost | Free/OSS | Free/OSS | Freemium | Free/OSS | Freemium |
| Container Images | Yes | Yes | Yes | Yes | Yes |
| Filesystem | Yes | Yes | Yes | No | No |
| IaC Scanning | Yes | No | Yes | No | No |
| K8s Cluster Scan | Yes | No | Yes | No | No |
| Secret Detection | Yes | No | Yes | No | No |
| SBOM | Yes | Yes | Yes | No | Yes |
| License Scanning | Yes | No | Yes | No | Yes |
| CI/CD Integration | Excellent | Good | Excellent | Limited | Docker only |
| Offline Mode | Yes | Yes | No | No | No |
| Speed | Fast | Fast | Moderate | Slow | Fast |
| License | Apache 2.0 | Apache 2.0 | Proprietary | Apache 2.0 | Proprietary |
Installation
# macOSbrew install trivy
# Linux (Debian/Ubuntu)sudo apt-get install wget apt-transport-https gnupg lsb-releasewget -qO - https://aquasecurity.github.io/trivy-repo/deb/public.key | gpg --dearmor | sudo tee /usr/share/keyrings/trivy.gpg > /dev/nullecho "deb [signed-by=/usr/share/keyrings/trivy.gpg] https://aquasecurity.github.io/trivy-repo/deb $(lsb_release -sc) main" | sudo tee /etc/apt/sources.list.d/trivy.listsudo apt-get update && sudo apt-get install trivy
# Dockerdocker run --rm aquasec/trivy:latest image alpine:3.19
# Helm (Trivy Operator for Kubernetes)helm repo add aqua https://aquasecurity.github.io/helm-charts/helm install trivy-operator aqua/trivy-operator \ --namespace trivy-system --create-namespaceContainer Image Scanning
# Scan a container imagetrivy image nginx:1.25
# Scan with severity filtertrivy image --severity HIGH,CRITICAL nginx:1.25
# Scan and fail on critical vulnerabilitiestrivy image --exit-code 1 --severity CRITICAL nginx:1.25
# Scan a local Docker imagetrivy image --input myapp.tar
# Scan with JSON outputtrivy image --format json --output results.json nginx:1.25
# Scan ignoring unfixed vulnerabilitiestrivy image --ignore-unfixed nginx:1.25
# Scan specific types only (os, library)trivy image --vuln-type os nginx:1.25trivy image --vuln-type library node:20Sample Output
nginx:1.25 (debian 12.4)=========================Total: 42 (HIGH: 8, CRITICAL: 2)
┌──────────────────┬────────────────┬──────────┬────────────┬───────────────┬──────────────────────────────┐│ Library │ Vulnerability │ Severity │ Installed │ Fixed Version │ Title │├──────────────────┼────────────────┼──────────┼────────────┼───────────────┼──────────────────────────────┤│ libssl3 │ CVE-2024-0727 │ CRITICAL │ 3.0.11-1 │ 3.0.13-1 │ OpenSSL: denial of service ││ curl │ CVE-2023-46218 │ HIGH │ 7.88.1-10 │ 7.88.1-10+d12 │ curl: cookie injection │└──────────────────┴────────────────┴──────────┴────────────┴───────────────┴──────────────────────────────┘Filesystem and Repository Scanning
# Scan current directorytrivy fs .
# Scan a specific pathtrivy fs /path/to/project
# Scan a git repositorytrivy repo https://github.com/org/project
# Scan for secretstrivy fs --scanners secret .
# Scan for licensestrivy fs --scanners license .
# Scan for vulnerabilities and secretstrivy fs --scanners vuln,secret .Infrastructure as Code Scanning
# Scan Terraform filestrivy config ./terraform/
# Scan Kubernetes manifeststrivy config ./k8s/
# Scan Dockerfilestrivy config --file-patterns "Dockerfile" .
# Scan Helm chartstrivy config ./charts/myapp/
# Scan with specific severitytrivy config --severity HIGH,CRITICAL ./terraform/
# Custom policy scanningtrivy config --policy ./custom-policies/ ./terraform/Sample IaC Finding
Dockerfile (dockerfile)========================Tests: 23 (SUCCESSES: 20, FAILURES: 3)Failures: 3 (HIGH: 2, CRITICAL: 1)
CRITICAL: Specify a tag in the 'FROM' statement for image 'node'═══════════════════════════════════════════════════════════════════Using the latest tag can lead to unpredictable builds.
HIGH: 'RUN' instruction using 'sudo'═══════════════════════════════════════Avoid using 'sudo' as it can lead to unpredictable behavior.Kubernetes Cluster Scanning
# Scan the entire clustertrivy k8s --report summary cluster
# Scan specific namespacetrivy k8s --namespace production --report all
# Scan for vulnerabilities in running imagestrivy k8s --scanners vuln cluster
# Scan for misconfigurationstrivy k8s --scanners misconfig cluster
# Scan specific workloadtrivy k8s --namespace production deployment/myapp
# Generate compliance report (NSA, CIS)trivy k8s --compliance k8s-nsa clustertrivy k8s --compliance k8s-cis clusterTrivy Operator (Continuous Scanning)
trivy: ignoreUnfixed: true severity: HIGH,CRITICAL timeout: 10m0s
operator: scanJobTolerations: - key: "node-role.kubernetes.io/control-plane" operator: "Exists" effect: "NoSchedule" vulnerabilityScannerEnabled: true configAuditScannerEnabled: true exposedSecretScannerEnabled: true scanJobsConcurrentLimit: 10 scanJobsRetryDelay: 30s
compliance: cron: "0 */6 * * *" reportType: - k8s-nsa - k8s-cis# Check vulnerability reportskubectl get vulnerabilityreports -A
# Check config audit reportskubectl get configauditreports -A
# Check exposed secret reportskubectl get exposedsecretreports -A
# Detailed report for a specific workloadkubectl get vulnerabilityreport -n production \ -l trivy-operator.resource.name=myapp -o yamlSBOM Generation
# Generate CycloneDX SBOMtrivy image --format cyclonedx --output sbom.json nginx:1.25
# Generate SPDX SBOMtrivy image --format spdx-json --output sbom-spdx.json nginx:1.25
# Scan an existing SBOMtrivy sbom sbom.json
# Generate SBOM for filesystemtrivy fs --format cyclonedx --output fs-sbom.json .CI/CD Integration
GitHub Actions
name: Security Scanon: push: branches: [main] pull_request: branches: [main]
jobs: trivy-scan: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4
- name: Build image run: docker build -t myapp:${{ github.sha }} .
- name: Trivy vulnerability scan uses: aquasecurity/trivy-action@master with: image-ref: myapp:${{ github.sha }} format: sarif output: trivy-results.sarif severity: HIGH,CRITICAL exit-code: 1
- name: Upload scan results uses: github/codeql-action/upload-sarif@v3 if: always() with: sarif_file: trivy-results.sarif
- name: Trivy IaC scan uses: aquasecurity/trivy-action@master with: scan-type: config scan-ref: . severity: HIGH,CRITICAL exit-code: 1
- name: Trivy filesystem scan uses: aquasecurity/trivy-action@master with: scan-type: fs scan-ref: . scanners: vuln,secret severity: HIGH,CRITICALGitLab CI
trivy-scan: stage: security image: name: aquasec/trivy:latest entrypoint: [""] script: - trivy image --exit-code 1 --severity HIGH,CRITICAL --format json --output gl-container-scanning-report.json $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA - trivy fs --exit-code 1 --severity HIGH,CRITICAL --scanners vuln,secret . artifacts: reports: container_scanning: gl-container-scanning-report.json allow_failure: falseConfiguration
trivy.yaml
# trivy.yaml (project root)severity: - HIGH - CRITICAL
vulnerability: type: - os - library ignore-unfixed: true
misconfiguration: severity: - HIGH - CRITICAL
secret: config: trivy-secret.yaml
scan: skip-dirs: - node_modules - vendor - .git skip-files: - "**/*_test.go"
db: skip-update: false download-only: false
cache: dir: /tmp/trivy-cacheIgnore File
vulnerabilities: - id: CVE-2023-12345 statement: "Not exploitable in our context" expires: 2026-06-01
- id: CVE-2023-67890 paths: - "usr/lib/libfoo.so" statement: "Mitigated by WAF"
misconfigurations: - id: DS002 statement: "healthcheck handled by Kubernetes" paths: - "Dockerfile"Production Best Practices
Checklist
- Scan images in CI/CD pipeline before deployment (fail on CRITICAL)
- Use Trivy Operator for continuous cluster scanning
- Generate SBOMs for all production images
- Scan IaC (Terraform, Kubernetes manifests) in pull requests
- Enable secret detection in filesystem scans
- Configure
.trivyignore.yamlwith documented exceptions and expiry dates - Monitor compliance reports (CIS, NSA) on a schedule
- Integrate scan results with security dashboards (Grafana, DefectDojo)
- Use
--ignore-unfixedto focus on actionable vulnerabilities - Keep Trivy DB updated (auto-update in CI, air-gapped mirror for offline)
- Set severity thresholds per environment (CRITICAL for prod, HIGH for staging)
- Review and rotate ignore entries regularly
- Scan base images separately from application layers
- Use SARIF output for GitHub Security tab integration
Secure Your Container Pipeline
Building a comprehensive container security strategy requires expertise in vulnerability management, IaC scanning, and compliance. At chavkov.com, I deliver hands-on security training that equips your team with production-ready DevSecOps skills.
Contact me to discuss security training options for your team.