Trivy for Security Scanning and SBOM Generation¶
Einordnung ins Overtime-Projekt
Overtime lädt laufend neue Abhängigkeiten, Container-Images und Infrastruktur-Manifeste in die Pipeline – ein übersehenes CVE oder ein hartkodiertes Secret kann so direkt in Produktion landen. Dieses ADR beschreibt, wie Trivy Schwachstellen-, Lizenz-, Secret- und Misconfiguration-Scanning sowie SBOM-Erzeugung in einem einzigen Werkzeug vereint.
1. Kontext & Problemstellung (Deutsch)¶
Moderne Cloud-Native-Anwendungen hängen von einer Vielzahl externer Open-Source-Komponenten ab. Für eine sichere und revisionssichere Bereitstellung unserer B2B-Plattform Overtime müssen verschiedene Angriffsvektoren abgedeckt werden:
- Das frühzeitige Abfangen bekannter Schwachstellen (CVEs) in den Quellcode-Abhängigkeiten (
uv.lock) vor dem eigentlichen Image-Build (Shift-Left). - Das Scannen des finalen, von Buildah gebauten Container-Images auf Betriebssystemebene.
- Das Blockieren von versehentlich im Repository eingebrannten Geheimnissen (Secrets wie API-Keys oder Passwörter).
- Das Erkennen von Fehlkonfigurationen (Misconfigurations) in unseren Dockerfiles und Kubernetes-Manifesten (
Kustomize). - Die Bereitstellung einer maschinenlesbaren System-Zutatenliste (SBOM).
2. Architecture Decision Record (English)¶
ADR-003: Vulnerability Scanning and SBOM Generation with Trivy¶
Status¶
Accepted
Context and Problem Statement¶
A compliant and secure software delivery pipeline must detect vulnerabilities, embedded secrets, and structural infrastructure misconfigurations at multiple stages of the lifecycle. Additionally, laws like Cyber Resilience Act (see BSI TR-03183) and modern procurement frameworks mandate the production of a verifiable Software Bill of Materials (SBOM). Using fractured single-purpose scanners increases maintenance overhead and pipeline complexity.
Decision Drivers¶
-
BSI Technical Guideline BSI TR-03183: Cyber Resilience Requirements for Manufacturers and Products, Part 2: Software Bill of Materials (SBOM): Native capability to produce standardized SBOMs in CycloneDX or SPDX format on demand.
-
Strict Pipeline Gating: The ability to enforce automated build failures (non-zero exit codes) upon detecting HIGH or CRITICAL severity vulnerabilities.
- Legal Risk Mitigation: Continuous automated detection of licenses incompatible with our software distribution model (e.g., GPL conflicts).
- Operational Efficiency: Minimizing tool sprawl within CI runner environments to streamline updates and dependency tracking via Renovate.
Considered Options¶
- Snyk — It requires a commercial SaaS subscription for advanced container features, automated license compliance enforcement, and introduces a hard external cloud dependency.
- Trivy (Aqua Security) — A unified, Apache 2.0-licensed security scanner that handles vulnerability scanning, license compliance, secret detection, and IaC misconfigurations out of the box. Operates as a single local binary with zero SaaS platform dependencies.
- Grype + Syft (Anchore) — An exceptional open-source combination where Syft compiles the SBOM and Grype processes the vulnerability matching. Highly capable, but splits the architecture into two distinct tools to update and configure.
Decision Outcome¶
Chosen: Trivy, because it satisfies all five foundational security requirements within a single binary footprint. License auditing and secret scrubbing are executed as additive configuration flags during the exact same scanning lifecycle.
I did not test Grype + Syft as Trivy fulfilled the requirements and remains a valid alternative.
Consequences & Trade-offs¶
Positive Consequences¶
- Single Tool Lifecycle: One single image coordinate (
aquasec/trivy:0.71.1) is pinned and automatically maintained via Renovate. - Automated Audit Trail: A CycloneDX SBOM (
bom.cdx.json) is continuously compiled and stored as a native pipeline artifact on every build execution. - High Developer Velocity: Security findings match standard GitLab UI widgets (Security Dashboard, Code Quality annotations, and HTML reports via
expose_as).
Negative Consequences / Trade-offs¶
- Database Synchronization: Trivy requires downloading its remote vulnerability database snapshot at runtime. In stateless environments, this causes overhead, which we mitigate by caching the
.trivycache/directory across GitLab jobs. - Template Drift: Upstream templates bundled inside the container image (
@contrib/*.tpl) are prone to breaking across version upgrades and I had trouble using/ customizing them at all. Custom templates (gitlab.tplandgitlab-codequality.tpl) must be explicitly embedded inline within thescan.ymltemplate structure.
3. Pipeline Implementation & Code Snippet¶
Die folgende Pipeline-Konfiguration integriert Trivy nahtlos in unsere CI/CD-Prozesse, um ein automatisiertes Security-Gating sicherzustellen. In der test-Phase wird zunächst das lokale Dateisystem auf Schwachstellen, hartkodierte Secrets und IaC-Fehlkonfigurationen geprüft (.trivy-deps-scan). Sobald das Container-Image gebaut ist, erfolgen in der scan-Phase tiefgehende Prüfungen des Images auf bekannte CVEs (.trivy-vuln-scan) und inkompatible Lizenzen (.trivy-license-scan). Parallel dazu wird vollautomatisch eine maschinenlesbare CycloneDX-SBOM erzeugt (.sbom) und ein aggregierter HTML-Report für das Entwicklerteam bereitgestellt (.trivy-html-report). Kritische Funde führen dabei stets zum sofortigen Abbruch der Pipeline (--exit-code 1)
The trivy scans can be found in the overtime-ci-templates/scan.yml template:
.trivy-deps-scan:
stage: test
image:
name: aquasec/trivy:0.71.1@sha256:53570e6911c2361ebe7995228088cf83a6b9b73e7f3cdca44bd8f8f425e80fa7
entrypoint: [""]
variables:
TRIVY_SEVERITY: "HIGH,CRITICAL"
TRIVY_LICENSE_FULL: "true"
script:
- |
cat << 'TRIVYTPL' > gitlab-codequality.tpl
...
TRIVYTPL
EXTRA_FLAGS=""
[ "${TRIVY_LICENSE_FULL}" = "true" ] && EXTRA_FLAGS="--license-full"
trivy fs --scanners secret --format sarif --output gl-secret-detection-report.json .
trivy fs --severity "${TRIVY_SEVERITY}" --scanners vuln,misconfig ${EXTRA_FLAGS} --format sarif --output gl-sast-report.json .
trivy fs --scanners secret,misconfig ${EXTRA_FLAGS} --format template --template "@gitlab-codequality.tpl" --output gl-codequality-report.json .
trivy fs --exit-code 1 --severity "${TRIVY_SEVERITY}" --scanners vuln,license,secret,misconfig ${EXTRA_FLAGS} .
artifacts:
reports:
secret_detection: gl-secret-detection-report.json
sast: gl-sast-report.json
codequality: gl-codequality-report.json
paths:
- gl-secret-detection-report.json
- gl-sast-report.json
- gl-codequality-report.json
when: always
.sbom:
stage: scan
dependencies: []
image:
name: aquasec/trivy:0.71.1@sha256:53570e6911c2361ebe7995228088cf83a6b9b73e7f3cdca44bd8f8f425e80fa7
entrypoint: [""]
variables:
TRIVY_USERNAME: $CI_REGISTRY_USER
TRIVY_PASSWORD: $CI_REGISTRY_PASSWORD
script:
- trivy image --format cyclonedx --scanners vuln,license --output bom.cdx.json "${IMAGE_NAME}:${IMAGE_TAG}"
artifacts:
paths:
- bom.cdx.json
when: always
.trivy-vuln-scan:
stage: scan
dependencies: []
image:
name: aquasec/trivy:0.71.1@sha256:53570e6911c2361ebe7995228088cf83a6b9b73e7f3cdca44bd8f8f425e80fa7
entrypoint: [""]
variables:
TRIVY_USERNAME: $CI_REGISTRY_USER
TRIVY_PASSWORD: $CI_REGISTRY_PASSWORD
TRIVY_SEVERITY: "HIGH,CRITICAL"
script:
- |
cat << 'TRIVYTPL' > gitlab.tpl
...
TRIVYTPL
trivy image --format template --template "@gitlab.tpl" --output gl-container-scanning-report.json --severity "${TRIVY_SEVERITY}" --scanners vuln "${IMAGE_NAME}:${IMAGE_TAG}"
trivy image --exit-code 1 --severity "${TRIVY_SEVERITY}" --scanners vuln "${IMAGE_NAME}:${IMAGE_TAG}"
artifacts:
reports:
container_scanning: gl-container-scanning-report.json
paths:
- gl-container-scanning-report.json
when: always
.trivy-license-scan:
stage: scan
dependencies: []
image:
name: aquasec/trivy:0.71.1@sha256:53570e6911c2361ebe7995228088cf83a6b9b73e7f3cdca44bd8f8f425e80fa7
entrypoint: [""]
variables:
TRIVY_USERNAME: $CI_REGISTRY_USER
TRIVY_PASSWORD: $CI_REGISTRY_PASSWORD
TRIVY_SEVERITY: "CRITICAL"
script:
- trivy image --scanners license --license-full --format table "${IMAGE_NAME}:${IMAGE_TAG}"
- trivy image --exit-code 1 --severity "${TRIVY_SEVERITY}" --scanners license --license-full --format table "${IMAGE_NAME}:${IMAGE_TAG}"
.trivy-html-report:
stage: scan
dependencies: []
image:
name: aquasec/trivy:0.71.1@sha256:53570e6911c2361ebe7995228088cf83a6b9b73e7f3cdca44bd8f8f425e80fa7
entrypoint: [""]
variables:
TRIVY_USERNAME: $CI_REGISTRY_USER
TRIVY_PASSWORD: $CI_REGISTRY_PASSWORD
script:
# 1. Generate a custom HTML template that supports CVEs, Licenses, Secrets & IaC
- |
cat << 'EOF' > custom-report.tpl
...
EOF
# 2. Run the scan explicitly enabling ALL FOUR scanners
- trivy image --scanners vuln,license,secret,misconfig --license-full --format template --template "@custom-report.tpl" --output trivy-report.html "${IMAGE_NAME}:${IMAGE_TAG}"
artifacts:
paths:
- trivy-report.html
expose_as: "Trivy Security and License Report"
when: always
4. Compliance Einordnung (Deutsch)¶
BSI IT-Grundschutz & TR Compliance¶
| Standard | Kriterium / Inhalt | Wie im Projekt adressiert |
|---|---|---|
| BSI IT-Grundschutz | SYS.1.6.A6 (B): Verwendung sicherer Images | Trivy scannt das compilierte OCI-Image nach dem Build und verhindert, dass veraltete Systempakete mit bekannten Sicherheitslücken in die Registry gelangen. |
| BSI IT-Grundschutz | SYS.1.6.A13 (S): Freigabe von Images | Der automatisierte Pipeline-Abbruch (--exit-code 1) bei Funden der Stufen HIGH oder CRITICAL dient als technisches Quality Gate im Freigabeprozess. |
| BSI IT-Grundschutz | APP.4.4.A10 (S): Absicherung von Prozessen der Automatisierung | Trivy scannt die eigenen CI/CD-Konfigurationen und Dockerfiles auf IaC-Fehlkonfigurationen, um das Einschleusen unsicherer Pipeline-Rechte zu blockieren. |
CIS Benchmark Compliance¶
| Standard | Kriterium / Inhalt | Wie im Projekt adressiert |
|---|---|---|
| CIS Docker Benchmark | Sektion 4.4: Ensure images are scanned and rebuilt to include security patches | Erfüllt. Die Integration von Trivy als zweistufiges Gate (Filesystem vor dem Build, Container-Image nach dem Build) stellt eine lückenlose CVE-Überwachung sicher. |
| CIS Docker Benchmark | Sektion 4.10: Ensure secrets are not stored in Dockerfiles | Erfüllt. Der integrierte Secret-Scanner identifiziert hartkodierte Passwörter, API-Keys oder Zertifikate im Quellcode und blockiert den Commit via Code Quality Widget. |
EU Cyber Resilience Act (CRA)¶
Wichtiger Hinweis zum Anwendungsbereich: Da Overtime als reines fiktives B2B-SaaS (Cloud-native) konzipiert ist und zentral von uns betrieben wird, fällt die Plattform als Ganzes nach aktueller Auslegung nicht direkt unter den Cyber Resilience Act (CRA), da keine physische Hardware oder eigenständige Softwareprodukte in den Verkehr gebracht werden.
Sollten im Zuge der Produkt-Roadmap lokale Komponenten an B2B-Kunden ausgeliefert werden (z. B. On-Premise-Gateways, CLI-Tools, dedizierte Desktop-Clients oder vom Kunden selbst gehostete Docker-Images), werden diese sofort als PwDE (Products with Digital Elements) CRA-pflichtig. Die Pipeline ist durch den Einsatz von Trivy bereits ab Tag 1 darauf vorbereitet.
| Standard | Kriterium / Inhalt | Wie im Projekt adressiert |
|---|---|---|
| Cyber Resilience Act | BSI TR-03183-2 Kapitel 4: SBOM formats | Über den Befehl trivy image --format cyclonedx wird bei jedem Build-Vorgang vollautomatisch eine konforme, maschinenlesbare SBOM im CycloneDX-Format oder SPDX erzeugt. |
| Cyber Resilience Act | BSI TR-03183-H Control 8.25 (d) Gewährleistung, dass Produkte (PwDE) nicht ohne Erfüllung der Sicherheitsanforderungen in den Markt/Produktion gelangen. | Der Parameter --exit-code 1 bei kritischen Funden fungiert als automatisierter Checkpoint, der den Build- und Deployment-Prozess blockiert. |
| Cyber Resilience Act | BSI TR-03183-H Control 8.25 (e) Durchführung von Code-Scans zur Verifizierung der Sicherheit vor dem Inverkehrbringen und während des Supports. | Kontinuierliche Überprüfung der Quellcode-Abhängigkeiten und des finalen Container-Images auf bekannte Sicherheitslücken (CVEs). |
| Cyber Resilience Act | BSI TR-03183-H Control 8.29 Implementierung von Sicherheitstests im Entwicklungszyklus zur Validierung vor dem Deployment in Produktion. | Die Multi-Stage-Teststrategie in der Pipeline stellt sicher, dass kein Code ungetestet die Stufen test und scan passiert. In diesem ADR wird die statische Codeanalyse ausgeführt. |