Trivy Container-Sicherheitsscan hat sich zum De-facto-Standard für die Erkennung von Schwachstellen in Docker-Images entwickelt, bevor sie die Produktion erreichen. Wenn du dich jemals gefragt hast, wie Angreifer bekannte CVEs in Basis-Images wie ubuntu:20.04 oder node:18 ausnutzen, oder ob dein Dockerfile Secrets preisgibt, liefert Trivy die Antwort in Sekunden. Diese Anleitung behandelt Installation, Scan-Strategien, CI/CD-Integration und wie du Trivy-Befunde interpretierst und darauf reagierst — ohne in falschen Positiven zu ertrinken.
Voraussetzungen
- Docker installiert und laufend (Docker 20.10+)
- Linux-, macOS- oder Windows-Arbeitsstation (WSL2)
- Grundlegende Vertrautheit mit Docker-Images und Dockerfiles
- Eine CI/CD-Plattform (GitHub Actions, GitLab CI oder Jenkins) für Pipeline-Integration
- Root- oder sudo-Zugriff für systemweite Trivy-Installation (oder Binär-Installation verwenden)
Trivy installieren
Trivy wird als einzelnes statisches Binär ohne externe Abhängigkeiten ausgeliefert. Der schnellste Weg unter Linux:
curl -sfL https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/install.sh | sh -s -- -b /usr/local/bin
trivy --version
Unter Ubuntu/Debian kannst du das Aqua Security apt-Repository für verwaltete Updates hinzufügen:
sudo apt-get install wget apt-transport-https gnupg lsb-release -y
wget -qO - https://aquasecurity.github.io/trivy-repo/deb/public.key | gpg --dearmor | sudo tee /usr/share/keyrings/trivy.gpg > /dev/null
echo "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.list
sudo apt-get update && sudo apt-get install trivy -y
Unter macOS mit Homebrew: brew install trivy
Trivy lädt seine Schwachstellendatenbank beim ersten Aufruf herunter. Erzwinge ein Datenbankupdate jederzeit mit trivy image --download-db-only.
Docker-Images auf Schwachstellen scannen
Der Kernbefehl ist unkompliziert:
trivy image nginx:latest
Trivy lädt das Image herunter, falls es nicht lokal gecacht ist, entpackt die Schichten und prüft jedes installierte OS-Paket und jede Sprachabhängigkeit gegen seine Schwachstellendatenbank (NVD, GitHub Advisory, Alpine secdb und andere). Die Ausgabe zeigt CVE-IDs, Schweregrad, installierte Version und die korrigierte Version, wenn verfügbar.
Nach Schweregrad filtern
Standardmäßig zeigt Trivy alle Schweregrade von UNKNOWN bis CRITICAL. In der Praxis solltest du dich auf umsetzbare Befunde konzentrieren:
trivy image --severity HIGH,CRITICAL nginx:latest
Nicht behobene Schwachstellen ignorieren
Viele CVEs haben noch keine verfügbare Korrektur. Nutze --ignore-unfixed, um sie zu überspringen und dich auf das zu konzentrieren, was du tatsächlich beheben kannst:
trivy image --severity HIGH,CRITICAL --ignore-unfixed nginx:latest
Ausgabeformate
Trivy unterstützt mehrere Ausgabeformate für verschiedene Anwendungsfälle:
# Menschenlesbare Tabelle (Standard)
trivy image nginx:latest
# JSON für programmatische Verarbeitung
trivy image --format json --output results.json nginx:latest
# SARIF für GitHub Security Tab Integration
trivy image --format sarif --output results.sarif nginx:latest
# CycloneDX SBOM
trivy image --format cyclonedx --output sbom.json nginx:latest
Das SARIF-Format integriert sich direkt mit dem GitHub Security Tab und zeigt Schwachstellen-Annotationen inline in Pull Requests an.
Dockerfiles und IaC-Fehlkonfigurationen scannen
Trivys config-Scanner prüft Dockerfiles, Kubernetes-Manifeste, Terraform und Helm-Charts auf Sicherheitsfehlkonfigurationen, bevor sie deployed werden:
# Dockerfile scannen
trivy config ./Dockerfile
# Ganzes Verzeichnis scannen (Kubernetes-Manifeste, Terraform)
trivy config ./k8s/
# Helm-Charts scannen
trivy config --helm-values values.yaml ./charts/myapp
Häufige Dockerfile-Befunde umfassen: Ausführung als Root, ADD statt COPY, fehlendes HEALTHCHECK, Exposition sensibler Ports und fehlende Pinning von Basis-Image-Digests.
Secrets und sensible Daten erkennen
Trivy kann Image-Schichten und Dateisysteme auf versehentlich eingebaute Secrets scannen:
# Secret-Scan für ein Image aktivieren
trivy image --scanners secret nginx:latest
# Lokales Verzeichnis auf Secrets scannen
trivy fs --scanners secret ./src/
Trivy erkennt AWS-Schlüssel, GitHub-Tokens, private SSH-Schlüssel, Datenbankverbindungsstrings und Hunderte andere Secret-Muster. Das ist besonders wertvoll, um Secrets abzufangen, die im Quellcode committed wurden und in einer Docker-Schicht gelandet sind.
Vergleich mit Alternativen
| Funktion | Trivy | Grype | Snyk | Clair |
|---|---|---|---|---|
| OS-Paket-CVEs | Ja | Ja | Ja | Ja |
| Sprachabhängigkeiten | Ja | Ja | Ja | Nein |
| IaC-Fehlkonfigurationen | Ja | Nein | Ja | Nein |
| Secret-Scanning | Ja | Nein | Ja | Nein |
| SBOM-Generierung | Ja | Ja | Ja | Nein |
| Lizenz | Apache 2.0 | Apache 2.0 | Proprietär | Apache 2.0 |
| CI/CD-Integration | Nativ | Nativ | Nativ | Begrenzt |
| Offline-Modus | Ja | Ja | Nein | Teilweise |
Trivys Vorteil ist die Breite — es kombiniert Schwachstellen-Scanning, Fehlkonfigurationserkennung, Secret-Scanning und SBOM-Generierung in einem einzigen Binär ohne laufenden Server oder Datenbank.
Trivy in CI/CD-Pipelines integrieren
GitHub Actions
name: Container-Sicherheitsscan
on:
push:
branches: [main]
pull_request:
jobs:
trivy-scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Docker-Image bauen
run: docker build -t myapp:${{ github.sha }} .
- name: Trivy Schwachstellen-Scanner ausführen
uses: aquasecurity/trivy-action@master
with:
image-ref: myapp:${{ github.sha }}
format: sarif
output: trivy-results.sarif
severity: HIGH,CRITICAL
exit-code: 1
ignore-unfixed: true
- name: Trivy-Scan-Ergebnisse zum GitHub Security Tab hochladen
uses: github/codeql-action/upload-sarif@v3
if: always()
with:
sarif_file: trivy-results.sarif
Die Einstellung exit-code: 1 lässt die Pipeline fehlschlagen, wenn kritische oder hohe CVEs gefunden werden. if: always() beim SARIF-Upload stellt sicher, dass Ergebnisse sichtbar sind, auch wenn der Scan-Schritt fehlschlägt.
GitLab CI
trivy-scan:
image: aquasec/trivy:latest
stage: test
script:
- trivy image --exit-code 1 --severity CRITICAL --ignore-unfixed $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
allow_failure: false
Praxisbeispiel
Du hast eine Produktionsanwendung, die node:16 als Basis-Image verwendet. Dein Sicherheitsteam stellt fest, dass die CI/CD-Pipeline Container-Images vor dem Deployment nie validiert. Du hast 48 Stunden, um ein Scan-Gate zu implementieren.
Schritt 1 — Aktuelles Image prüfen:
trivy image node:16 --severity HIGH,CRITICAL --ignore-unfixed
Das zeigt 47 HIGH- und 12 CRITICAL-CVEs im Basis-Image — die meisten durch Upgrade auf node:18-alpine behoben.
Schritt 2 — Dockerfile aktualisieren:
# Vorher
FROM node:16
# Nachher
FROM node:18-alpine
Schritt 3 — Erneut scannen zur Bestätigung:
trivy image node:18-alpine --severity HIGH,CRITICAL --ignore-unfixed
Die Alpine-Variante reduziert die CVE-Anzahl von 59 auf 3 (alle ohne Korrektur).
Schritt 4 — CI-Gate hinzufügen:
Füge den GitHub Actions Workflow oben hinzu. Alle zukünftigen PRs werden blockiert, wenn CRITICAL-CVEs eingeführt werden.
Schritt 5 — Auch IaC scannen:
trivy config ./k8s/ --severity HIGH,CRITICAL
Das zeigt zwei Probleme: Ein Deployment läuft als Root und eine readOnlyRootFilesystem Security-Context-Einstellung fehlt.
Stolperfallen und Sonderfälle
Veraltete Schwachstellendatenbank: Trivy cached seine Datenbank lokal. In CI-Umgebungen führe trivy image --download-db-only als separaten Cache-Schritt aus, um redundante Downloads zu vermeiden.
Authentifizierung bei privaten Registries: Exportiere Credentials als Umgebungsvariablen vor dem Scan:
export TRIVY_USERNAME=meinbenutzer
export TRIVY_PASSWORD=meinpasswort
trivy image meine-registry.beispiel.com/meine-app:latest
Falsch-Positive: Einige CVEs werden in Bibliotheken gemeldet, die deine Anwendung nie aufruft. Nutze .trivyignore, um bekannte Falsch-Positive zu unterdrücken:
# .trivyignore
CVE-2022-12345 # Nicht ausnutzbar — Bibliothek wird zur Laufzeit nicht aufgerufen
Alpine musl vs glibc: Alpine-basierte Images melden weniger CVEs, weil Alpine musl libc verwendet und das Alpine-Sicherheitsteam aggressiv patcht. Das ist keine “fehlende” Abdeckung — es spiegelt echte Unterschiede im Bibliotheks-Ökosystem wider.
Multi-Arch-Images: Gib beim Scannen von Multi-Arch-Images immer die Plattform an: trivy image --platform linux/amd64 myapp:latest.
Trivy vs. Laufzeit-Sicherheit: Trivy findet Schwachstellen zur Build-Zeit. Es ersetzt keine Laufzeit-Sicherheitstools wie Falco, die unerwartetes Verhalten in laufenden Containern erkennen.
Fehlerbehebung
Fehler “No such image”: Trivy kann das Image weder lokal finden noch herunterladen. Überprüfe Image-Name, Tag und Registry-Credentials.
Datenbankdownload-Fehler in air-gapped Umgebungen: Lade das Datenbankpaket auf einer internetfähigen Maschine herunter mit trivy image --download-db-only, dann übertrage das Verzeichnis ~/.cache/trivy/ auf den isolierten Host.
Hoher Speicherverbrauch bei großen Images: Nutze --parallel 1, um die gleichzeitige Schichtverarbeitung zu reduzieren: trivy image --parallel 1 myapp:latest.
Exit-Code 1, aber keine kritischen CVEs angezeigt: Prüfe, ob --ignore-unfixed fehlt — nicht behobene kritische CVEs können den Exit-Code auslösen, auch wenn du nur behebbare Probleme erwartet hast.
Scan-Timeout in CI: Setze TRIVY_TIMEOUT=10m, um den Standard-Timeout von 5 Minuten für große Images zu verlängern.
Zusammenfassung
- Trivy ist ein Ein-Binär-Scanner für CVEs, Fehlkonfigurationen, Secrets und SBOM-Generierung
- Führe
trivy image --severity HIGH,CRITICAL --ignore-unfixed myapp:latestals Basisscan aus - Nutze
--exit-code 1in CI/CD, um Deployments mit kritischen Schwachstellen zu blockieren - Kombiniere
trivy image(Laufzeit) mittrivy config(Dockerfile/IaC) für vollständige Abdeckung - Alpine-basierte Images reduzieren die CVE-Angriffsfläche drastisch
- Nutze
.trivyignore, um bestätigte Falsch-Positive zu unterdrücken und Alert-Fatigue zu reduzieren - Lade SARIF-Ergebnisse zum GitHub Security Tab hoch für Inline-Annotationen in PRs
- Trivy ersetzt keine Laufzeit-Sicherheit — kombiniere es mit Falco für Defense-in-Depth