Zum Hauptinhalt springen
S-EDV news
← Alle Anleitungen
📘 Anleitung Docker 04.06.2026 · 9 min Lesezeit

Docker-Images auf Schwachstellen scannen mit Trivy: CVE-Check, SBOM und automatische Scans im KMU-Workflow

Docker-Images mit Trivy auf Schwachstellen scannen: Severity-Filter für CI/CD, Risikoakzeptanz in .trivyignore.yaml, SBOM, tägliche Rescans und sicher gepinnte GitHub Action.

Geprüft am 30.09.2026

WerbelinksMit * markierte Links sind Werbelinks: Bei einem Kauf erhalten wir eine Provision, der Preis bleibt gleich. Als Amazon-Partner verdiene ich an qualifizierten Verkäufen. Mehr dazu

Gestapelte Schiffscontainer im Morgenlicht, im Vordergrund eine Lupe auf einer Holzkiste

Wer Docker-Images in Produktion betreibt, trägt die Verantwortung für bekannte Sicherheitslücken in allen enthaltenen Paketen, auch wenn das Base-Image vom offiziellen Hub stammt. Trivy von Aqua Security ist ein verbreiteter Open-Source-Scanner: eine Go-Binärdatei ohne Daemon, die CVEs in OS-Paketen und Sprachbibliotheken findet, Secrets aufdeckt und SBOM-Dokumente exportiert. Diese Anleitung zeigt Trivy als laufenden Prozess im KMU-Alltag, nicht als einmaligen Build-Check.

Voraussetzungen

  • Docker oder Podman installiert und lauffähig (Images müssen lokal vorhanden oder pullbar sein)
  • Trivy-Binärdatei (nicht v0.69.4 bis v0.69.6, siehe Schritt 5): brew install trivy (macOS), apt install trivy über das Aqua-Repository (Debian/Ubuntu) oder Download von github.com/aquasecurity/trivy/releases
  • Internetzugang für den DB-Download (Standard: mirror.gcr.io/aquasec/trivy-db, Fallback ghcr.io/aquasecurity/trivy-db) oder ein interner OCI-Mirror
  • Optional: CI/CD-System (GitHub Actions, GitLab CI, Jenkins)
  • Archivspeicher für SBOM-Dateien und Scan-Logs (NAS, S3 mit Object Lock oder Artefakt-Registry wie Harbor/Nexus)

Schritt 1: Erster Scan mit Severity-Filter

Der einfachste Befehl trivy image nginx liefert so viele LOW- und MEDIUM-Findings, dass der Überblick verloren geht. Für KMU-Umgebungen gilt: CI/CD-Break nur bei HIGH und CRITICAL, LOW/MEDIUM nur in Reports ohne Exit-Code 1. Das Flag --ignore-unfixed blendet Schwachstellen ohne verfügbaren Patch aus und reduziert das Rauschen erheblich.

# Basis-Scan mit Severity-Filter und CI/CD-Exit-Code
trivy image --severity HIGH,CRITICAL --exit-code 1 myapp:latest

# Mit --ignore-unfixed: nur fixbare Schwachstellen zeigen
trivy image --severity HIGH,CRITICAL --ignore-unfixed --exit-code 1 myapp:latest

Mit --exit-code 1 endet Trivy mit Code 1, sobald ein Finding der gewählten Stufen auftritt; das bricht die Pipeline ab. Ohne das Flag endet Trivy mit Code 0, auch bei kritischen Lücken.

Die Schwachstellendatenbank lädt Trivy beim ersten Scan nach ~/.cache/trivy und aktualisiert sie bei späteren Scans automatisch, wenn sie veraltet ist. Für Java-Images lädt Trivy zusätzlich die separate trivy-java-db.

Verifizieren: trivy --version zeigt Programm- und DB-Version; echo $? direkt nach dem Scan gibt 1 aus, wenn HIGH- oder CRITICAL-Findings vorliegen, sonst 0.

Schritt 2: Risikoakzeptanz mit .trivyignore.yaml dokumentieren

Manche CVEs lassen sich kurzfristig nicht beheben: der Upstream-Patch fehlt, das Base-Image wird erst im nächsten Sprint aktualisiert, oder die Schwachstelle ist im konkreten Deployment nicht erreichbar. Statt den Scan abzuschalten, dokumentieren Sie die Risikoakzeptanz in einer .trivyignore.yaml mit Begründung (statement) und Ablaufdatum (expired_at).

Wichtig: Das YAML-Format ist laut Dokumentation experimentell und wird nicht automatisch geladen; übergeben Sie --ignorefile .trivyignore.yaml explizit. Die Textdatei .trivyignore lädt Trivy automatisch, sie bietet aber keine Dokumentationsfelder.

# .trivyignore.yaml (YAML-Format mit vollständiger Dokumentation)
vulnerabilities:
  - id: CVE-2023-3817
    statement: "OpenSSL-Timing-Angriff, kein öffentlicher Endpunkt exponiert, akzeptiert bis Upstream-Patch"
    expired_at: 2027-03-31
    paths:
      - "usr/local/lib/python3.11"

  - id: CVE-2024-5678
    statement: "Nur in Dev-Images, nie in Produktion deployed"
    expired_at: 2026-12-31
# Trivy mit .trivyignore.yaml aufrufen
trivy image --severity HIGH,CRITICAL \
  --ignorefile .trivyignore.yaml \
  --ignore-unfixed \
  --exit-code 1 \
  myapp:latest

# Suppressed Findings trotzdem anzeigen (für Audit-Logs)
trivy image --severity HIGH,CRITICAL \
  --ignorefile .trivyignore.yaml \
  --show-suppressed \
  myapp:latest

Nach Ablauf von expired_at erscheint das Finding wieder und erzwingt eine neue Bewertung; so sammeln sich keine vergessenen Ausnahmen an.

Verifizieren: Der Scan mit --show-suppressed listet die akzeptierten CVEs in einem eigenen Abschnitt „Suppressed Vulnerabilities“ mit Ihrer Begründung.

Schritt 3: SBOM für Compliance-Nachweise erzeugen

Eine Software Bill of Materials (SBOM) listet alle Komponenten eines Images mit Versionen. NIS2 verlangt ein Management von Lieferkettenrisiken (Art. 21), die DSGVO dem Stand der Technik entsprechende Sicherheit (Art. 32); eine regelmäßig erzeugte und archivierte SBOM ist dafür ein nachvollziehbarer Beleg, gesetzlich vorgeschrieben ist sie für Betreiber nicht.

# SBOM als CycloneDX JSON (inkl. CVE-Daten) – für NIS2/DSGVO empfohlen
trivy image --scanners vuln --format cyclonedx --output sbom-cyclonedx.json myapp:latest

# SBOM als SPDX JSON (breitere Toolchain-Kompatibilität)
trivy image --format spdx-json --output sbom-spdx.json myapp:latest

# SBOM als SPDX Tag-Value
trivy image --format spdx --output sbom.spdx myapp:latest

# Mit Datum und Digest im Dateinamen archivieren
DIGEST=$(docker inspect --format='{{index .RepoDigests 0}}' myapp:latest | cut -d@ -f2 | cut -c1-12)
trivy image --scanners vuln --format cyclonedx \
  --output "sbom-myapp-$(date +%Y%m%d)-${DIGEST}.json" \
  myapp:latest

Kritischer Fallstrick:trivy image --format cyclonedxohne--scanners vuln erzeugt nur ein Paketinventar ohne CVE-Verlinkungen. Kombinieren Sie beide Flags, wenn die SBOM Schwachstellendaten enthalten soll.

Archivieren Sie unveränderlich, z. B. in S3 mit Object Lock, auf einem NAS mit WORM-Freigabe oder in Harbor/Nexus mit Retention-Policy. Datum und Image-Digest im Dateinamen machen den gescannten Stand nachvollziehbar. Lokal gebaute Images ohne Push haben keinen RepoDigest; die Variable bleibt dann leer.

Verifizieren: jq '.components | length, (.vulnerabilities | length)' sbom-cyclonedx.json gibt zwei Zahlen aus; die zweite fehlt, wenn --scanners vuln vergessen wurde.

Schritt 4: Laufende Container täglich rescannen per Cron

Ein Scan beim Build ist eine Momentaufnahme; ein damals sauberes Image kann zwei Wochen später kritische Lücken haben. Scannen Sie laufende Container daher regelmäßig neu.

#!/bin/bash
# /usr/local/bin/trivy-rescan.sh
# Täglich alle laufenden Container-Images scannen

LOGDIR=/var/log/trivy-scans
mkdir -p "$LOGDIR"

# DB vor dem Scan aktualisieren
trivy image --download-db-only

for IMAGE in $(docker ps --format '{{.Image}}' | sort -u); do
  SAFE_NAME=$(echo "$IMAGE" | tr '/:' '__')
  trivy image --severity HIGH,CRITICAL --ignore-unfixed \
    --skip-db-update --format json \
    --output "${LOGDIR}/${SAFE_NAME}-$(date +%Y%m%d).json" \
    "$IMAGE"
done
# /etc/cron.d/trivy-rescan
# Täglich um 03:00 Uhr, Ergebnisse nach /var/log/trivy-scans/
0 3 * * * root /usr/local/bin/trivy-rescan.sh >> /var/log/trivy-rescan.log 2>&1

Die JSON-Ausgabe lässt sich direkt in ein SIEM (Graylog, Elastic) oder ein Monitoring-System wie Grafana mit Loki einspeisen. So erhalten Sie Alarme bei neuen HIGH/CRITICAL-Findings. Grundlage dafür ist die Anleitung Logs zentralisieren mit Grafana Loki.

Verifizieren: sudo chmod +x /usr/local/bin/trivy-rescan.sh && sudo /usr/local/bin/trivy-rescan.sh einmal manuell starten; danach liegt je laufendem Image eine JSON-Datei mit aktuellem Datum in /var/log/trivy-scans/.

Schritt 5: GitHub Actions Integration mit SARIF

Für GitHub gibt es die offizielle trivy-action. Im SARIF-Format erscheinen die Ergebnisse unter „Security“ → „Code scanning“ und als Hinweise in Pull Requests.

# .github/workflows/trivy-scan.yml (Ausschnitt)
- name: Trivy vulnerability scan
  uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25  # v0.36.0, Commit-SHA pinnen
  with:
    image-ref: 'myapp:latest'
    format: 'sarif'
    output: 'trivy-results.sarif'
    severity: 'CRITICAL,HIGH'
    ignore-unfixed: true
    trivyignores: '.trivyignore.yaml'

- name: Upload SARIF to GitHub Security Tab
  uses: github/codeql-action/upload-sarif@v3
  with:
    sarif_file: 'trivy-results.sarif'

Sicherheitshinweis: Am 19. März 2026 veröffentlichten Angreifer mit gestohlenen Zugangsdaten das manipulierte Release Trivy v0.69.4 und überschrieben 76 von 77 Tags der trivy-action mit Schadcode; am 22. März folgten manipulierte Docker-Hub-Images v0.69.5 und v0.69.6 (Advisory GHSA-69fq-xp46-6x23). Pinnen Sie die Action daher auf einen Commit-SHA statt auf einen Tag, und prüfen Sie, ob Ihre Pipelines im betroffenen Zeitraum liefen. Den SHA eines Releases finden Sie im offiziellen Repository.

Verifizieren: Nach dem nächsten Workflow-Lauf zeigt der Tab „Security“ → „Code scanning“ Einträge mit dem Tool „Trivy“.

Schritt 6: Offline-Betrieb und DB-Caching

In Air-Gapped-Umgebungen oder bei vielen parallelen Jobs halten Sie die Datenbank lokal vor:

# DB einmalig herunterladen (speichert nach ~/.cache/trivy)
trivy image --download-db-only

# Java-DB separat herunterladen (für Java-Images)
trivy image --download-java-db-only

# Folge-Scans ohne DB-Update
trivy image --skip-db-update --severity HIGH,CRITICAL myapp:latest

# Alternativer DB-Mirror (z.B. interner Harbor-Mirror)
trivy image --db-repository harbor.intern.example.com/trivy/trivy-db:2 myapp:latest

# DB-Cache-Pfad anpassen (z.B. für CI-Artifact-Caching)
trivy image --cache-dir /opt/trivy-cache --skip-db-update myapp:latest

In CI/CD lädt ein eigener Cache-Job die DB einmal herunter und gibt sie als Artefakt weiter; alle anderen Jobs scannen mit --skip-db-update. Das vermeidet Rate-Limits bei parallelen Läufen. Für Offline-Scans von Java-Images ergänzen Sie --skip-java-db-update.

Verifizieren: Ein Scan mit --skip-db-update ohne Netzwerk läuft durch und meldet keinen Download-Fehler; ls ~/.cache/trivy/db zeigt trivy.db und metadata.json.

Trivy, Grype und Docker Scout im Vergleich

KriteriumTrivyGrypeDocker Scout
LizenzApache 2.0Apache 2.0Proprietär, Funktionsumfang abhängig vom Docker-Abo
SBOM-ExportCycloneDX JSON, SPDX JSON, SPDX Tag-ValueCycloneDX, SPDXSPDX, CycloneDX
EPSS/KEV-DatenNein (nur CVSS)Ja, ab v6 nativTeilweise
IaC/Kubernetes-ScanJa (Helm, Terraform, K8s)NeinNein
Secret-ScanJa (eingebaut)NeinNein
Offline-BetriebJa (vollständig)JaNein (cloud-abhängig)
GitHub-Integrationtrivy-action (SARIF)anchore/scan-actionDocker Desktop nativ

Troubleshooting / Typische Fehler

  • Veraltete DB (bekannte CVEs werden nicht gemeldet): Tritt bei dauerhaftem --skip-db-update mit altem Cache auf. Lösung: trivy image --download-db-only vorab ausführen und den CI-Cache mindestens täglich erneuern.
  • TOOMANYREQUESTS bei DB-Download: Viele parallele Jobs überschreiten das anonyme Rate-Limit der Registry. Lösung: DB einmal als Artefakt herunterladen und cachen oder --db-repository auf einen internen Mirror setzen.
  • CycloneDX ohne CVE-Daten:trivy image --format cyclonedx ohne --scanners vuln erzeugt nur ein Paketinventar. Lösung: immer --scanners vuln --format cyclonedx kombinieren.
  • .trivyignore.yaml wird ignoriert: YAML-Ignore-Dateien werden nicht automatisch geladen. Lösung: --ignorefile .trivyignore.yaml immer explizit übergeben.
  • Java-CVEs fehlen komplett: Die Java-DB ist nicht in der Standard-DB enthalten; offline fehlt sie. Lösung: trivy image --download-java-db-only vorab ausführen und mitcachen.
  • Image-Tag „latest“ führt zu inkonsistenten Ergebnissen: Mutable Tags können sich zwischen Scan und Deployment ändern. Lösung: Images mit SHA256-Digest pinnen: myapp@sha256:abc123... sowohl im Scan als auch im Deployment.
  • trivy-action auf @master gepinnt: Tags lassen sich überschreiben, wie im März 2026 geschehen. Lösung: auf einen Commit-SHA pinnen, Updates per Dependabot oder Renovate prüfen.

Häufige Fragen

Welche Severity soll ich für den CI/CD-Build-Break konfigurieren?

--severity HIGH,CRITICAL --exit-code 1 --ignore-unfixed bricht den Build nur bei behebbaren schweren Lücken ab; MEDIUM und LOW erfassen Sie in Reports ohne Exit-Code.

Wie unterscheidet sich Trivy von Grype und Docker Scout?

Trivy deckt zusätzlich IaC, Kubernetes und Secrets ab und arbeitet vollständig offline. Grype liefert EPSS- und KEV-Daten zur Priorisierung, Docker Scout ist in Docker Desktop und Docker Hub integriert. Details zeigt die Vergleichstabelle.

Wie erzeuge ich ein SBOM für NIS2/DSGVO-Nachweise?

Mit trivy image --scanners vuln --format cyclonedx --output sbom.json myapp:latest, siehe Schritt 3. Entscheidend ist die unveränderliche Ablage mit Datum und Image-Digest.

Was ist .trivyignore.yaml und wann brauche ich es statt .trivyignore?

Die YAML-Variante erlaubt strukturierte Dokumentation mit statement (Begründung), expired_at (Ablaufdatum) und paths/purls (betroffene Pakete). Damit ist jede Risikoakzeptanz begründet und befristet dokumentiert. Die Plain-Text-.trivyignore eignet sich nur für schnelle Ad-hoc-Ausnahmen ohne Dokumentationsbedarf und wird automatisch geladen, ohne --ignorefile.

Funktioniert Trivy ohne Internetverbindung (Air-Gapped)?

Ja, siehe Schritt 6: DB und Java-DB vorab laden oder aus einem internen OCI-Mirror beziehen, dann mit --skip-db-update und --skip-java-db-update scannen.

Wie reduziere ich CVE-Findings durch bessere Base-Images?

Distroless-Images enthalten weder Shell noch Paketmanager, Alpine-Images nur wenige Pakete. Beide senken die Zahl der Findings deutlich. Pinnen Sie Images per Digest, damit gescannter und ausgerollter Stand übereinstimmen.

Fazit

Trivy wirkt erst durch konsequente Integration: Severity-Filter auf HIGH/CRITICAL reduzieren den Lärm auf handhabbare Mengen, .trivyignore.yaml mit Begründung und Ablaufdatum macht Risikoakzeptanz audit-tauglich, und tägliche Cron-Rescans laufender Container schließen die Lücke zwischen Build-Zeit und Produktion. Archivierte SBOMs belegen den Stand für NIS2- und DSGVO-Nachweise.

Als nächste Schritte empfehlen sich die Absicherung der Docker-Hosts (siehe Linux-Server absichern mit UFW und Fail2ban) sowie die Integration von Container-Metriken in ein Monitoring-Dashboard (siehe cAdvisor und Prometheus für Docker-Container-Metriken).

Weiterführende Anleitungen und Quellen

Quellen: Advisory GHSA-69fq-xp46-6x23 (Supply-Chain-Vorfall März 2026) · Trivy Dokumentation – Filtering (trivy.dev) · Trivy Dokumentation – SBOM (trivy.dev) · Trivy Dokumentation – Container Image (trivy.dev) · GitHub – aquasecurity/trivy · Trivy DB Rate-Limit – GitHub Discussion #7699