Unterschied zu Trivy und Integration ins Merge-Request-Widget
Ein Docker-Image ist nur so sicher wie sein Basis-Image und die darin installierten System-Pakete, und genau dort verstecken sich viele Schwachstellen, die weder SAST noch Dependency Scanning erfassen, weil beide sich auf Anwendungscode und Sprachpakete konzentrieren. GitLabs Container Scanning schliesst diese Luecke, indem es das fertig gebaute Image direkt in der Pipeline gegen eine Vulnerability-Datenbank prueft. Dieser Artikel zeigt die Integration, den Unterschied zu einem eigenstaendigen Tool wie Trivy und wie die Ergebnisse im Merge-Request-Widget landen.
Inhaltsverzeichnis
- 1. Warum Docker-Images eine eigene Scan-Kategorie brauchen
- 2. Das Container-Scanning-Template in eine bestehende Pipeline einbinden
- 3. Wie der Analyzer unter der Haube arbeitet
- 4. Unterschied zu Trivy als eigenstaendigem Tool
- 5. Ergebnisse im Merge-Request-Widget
- 6. Images aus externen Registries scannen
- 7. Die richtige Basis-Image-Strategie als wirksamster Hebel
- 8. Schwellenwerte, Ausnahmen und der Umgang mit unfixbaren Findings
- 9. Best Practices und Vergleich der Ansaetze
- 10. Zusammenfassung
- 11. FAQ
1. Warum Docker-Images eine eigene Scan-Kategorie brauchen
Ein typisches Produktions-Image besteht aus deutlich mehr als dem eigenen Anwendungscode: Es enthaelt ein Basis-Betriebssystem wie Debian oder Alpine, System-Bibliotheken, einen Paketmanager-Layer und haeufig zusaetzliche Tools, die waehrend des Build-Prozesses installiert, aber nie wieder entfernt wurden. Jede dieser Komponenten kann bekannte Sicherheitsluecken enthalten, unabhaengig davon, wie sauber der eigentliche Anwendungscode ist. SAST prueft nur eigenen Quellcode, Dependency Scanning nur Sprachpakete wie Composer- oder npm-Abhaengigkeiten, keines von beiden schaut in die Betriebssystem-Ebene des fertigen Images hinein.
Container Scanning setzt genau hier an und analysiert das gebaute Image als Ganzes, inklusive aller Layer, gegen eine kontinuierlich aktualisierte Datenbank bekannter CVEs fuer Betriebssystem-Pakete. Das ist besonders relevant, weil viele Basis-Images monatelang unveraendert in Produktion laufen, waehrend im Hintergrund neue Schwachstellen fuer genau die darin enthaltenen Paketversionen veroeffentlicht werden. Ein Image, das beim Bauen als sicher galt, kann wenige Wochen spaeter bereits mehrere bekannte, oeffentlich dokumentierte Schwachstellen enthalten, ohne dass sich am eigenen Code oder Dockerfile etwas geaendert haette.
2. Das Container-Scanning-Template in eine bestehende Pipeline einbinden
Die Integration erfolgt ueber include:template mit Jobs/Container-Scanning.gitlab-ci.yml und setzt voraus, dass das zu scannende Image bereits in einer vorherigen Stage gebaut und in eine Registry gepusht wurde, typischerweise die projekteigene GitLab Container Registry. Ueber die Variable CS_IMAGE wird dem Scanner mitgeteilt, welches konkrete Image analysiert werden soll, standardmaessig wird dabei auf den Wert von CI_APPLICATION_REPOSITORY und CI_APPLICATION_TAG zurueckgegriffen, die sich aus dem Projektnamen und der Commit-SHA ableiten, falls keine eigenen Werte gesetzt werden.
Der Scan-Job selbst benoetigt Zugriff auf die Registry, in der das Image liegt, was bei der projekteigenen GitLab Registry automatisch ueber die CI-Job-Token-Authentifizierung funktioniert, bei einer externen Registry aber explizit ueber CS_REGISTRY_USER und CS_REGISTRY_PASSWORD konfiguriert werden muss. Ein haeufiger Fehler ist, den Scan-Job vor dem eigentlichen Push des Images auszufuehren, wodurch der Scanner ein nicht existierendes oder veraltetes Image analysiert. Die needs-Direktive stellt sicher, dass der Scan-Job zuverlaessig erst nach dem erfolgreichen Build- und Push-Job startet.
# .gitlab-ci.yml
stages:
- build
- security
- deploy
build-image:
stage: build
script:
- docker build -t "$CI_REGISTRY_IMAGE:$CI_COMMIT_SHA" .
- docker push "$CI_REGISTRY_IMAGE:$CI_COMMIT_SHA"
include:
- template: 'Jobs/Container-Scanning.gitlab-ci.yml'
container_scanning:
stage: security
variables:
CS_IMAGE: "$CI_REGISTRY_IMAGE:$CI_COMMIT_SHA"
needs: ["build-image"]
3. Wie der Analyzer unter der Haube arbeitet
Standardmaessig nutzt GitLabs Container-Scanning-Template intern Trivy als Analyzer-Engine, seit GitLab von der frueheren Grype-Standardeinstellung umgestellt hat. Das Image wird dabei nicht ausgefuehrt, sondern statisch analysiert: Der Scanner extrahiert die Layer, identifiziert installierte Paketversionen ueber die jeweilige Paketmanager-Metadatenbank, etwa dpkg fuer Debian-basierte Images oder apk fuer Alpine, und gleicht diese Liste gegen die Vulnerability-Datenbank ab. Dieser Prozess laeuft vollstaendig innerhalb der Pipeline, ohne dass das Image irgendwo deployed oder gestartet werden muss.
Ergaenzend zur reinen Betriebssystem-Paketpruefung erkennt der Analyzer je nach Konfiguration auch Sprachpaket-Schwachstellen innerhalb des Images, etwa wenn eine composer.lock oder package-lock.json in das finale Image kopiert wurde, was bei mehrstufigen Docker-Builds gelegentlich unbeabsichtigt passiert. In solchen Faellen ueberschneidet sich Container Scanning teilweise mit Dependency Scanning, was in der Praxis meist unproblematisch ist, da beide auf dieselbe zugrunde liegende Schwachstelle hinweisen und die Ergebnisse im Security-Dashboard entsprechend zusammengefuehrt dargestellt werden.
4. Unterschied zu Trivy als eigenstaendigem Tool
Trivy laesst sich auch vollstaendig unabhaengig von GitLabs Templates als eigener CI-Job einsetzen, entweder als Docker-Image oder als direkt installiertes Binary, mit vollem Zugriff auf saemtliche Trivy-eigenen Konfigurationsoptionen, Ausgabeformate und Scan-Modi, die das GitLab-Template nicht alle exponiert. Fuer Teams, die bereits eine etablierte Trivy-basierte Toolchain haben oder spezielle Anforderungen wie das Scannen von Infrastructure-as-Code-Dateien im selben Werkzeug abdecken wollen, ist der eigenstaendige Einsatz oft die flexiblere Wahl.
Der entscheidende Vorteil des GitLab-Templates liegt dagegen in der nahtlosen Integration: Ergebnisse landen automatisch im Merge-Request-Widget und im Security-Dashboard, ohne dass ein eigenes Skript die Trivy-JSON-Ausgabe in das GitLab-Report-Format konvertieren muesste. Bei einem eigenstaendigen Trivy-Job muesste diese Konvertierung manuell erfolgen, etwa ueber trivy image --format template mit einem passenden GitLab-kompatiblen Template, was zusaetzlichen Pflegeaufwand bedeutet. Fuer die meisten Teams ueberwiegt dieser Integrationsvorteil den Flexibilitaetsgewinn eines eigenstaendigen Trivy-Setups deutlich.
# Eigenstaendiger Trivy-Job als Alternative (ohne GitLab-Report-Integration)
trivy image --format table --severity CRITICAL,HIGH \
--exit-code 1 "$CI_REGISTRY_IMAGE:$CI_COMMIT_SHA"
5. Ergebnisse im Merge-Request-Widget
Nach einem erfolgreichen Scan-Lauf legt der Job einen Container-Scanning-Report als Artifact ab, den GitLab automatisch erkennt und im Merge-Request-Widget als eigene Sektion neben SAST- und Dependency-Scanning-Findings anzeigt. Jedes gefundene CVE erscheint dort mit Schweregrad, betroffenem Paket, installierter Version und, sofern verfuegbar, der Version, in der die Schwachstelle behoben wurde, sodass Reviewer auf einen Blick sehen, ob ein einfaches Basis-Image-Update das Problem loesen wuerde.
Besonders wertvoll ist die Diff-Ansicht: GitLab vergleicht die Findings des aktuellen Merge Requests automatisch mit dem Scan-Ergebnis des Ziel-Branches und markiert, welche Schwachstellen neu hinzugekommen sind und welche bereits vorher im Basis-Image vorhanden waren. Das verhindert, dass ein Merge Request faelschlicherweise fuer Altlasten verantwortlich gemacht wird, die bereits lange vor der eigenen Aenderung im Image vorhanden waren, und lenkt die Aufmerksamkeit gezielt auf tatsaechlich neu eingefuehrte Risiken.
6. Images aus externen Registries scannen
Nicht jedes Team baut und lagert seine Images ausschliesslich in der projekteigenen GitLab Container Registry. Basis-Images stammen haeufig aus Docker Hub, produktiv genutzte Images liegen mitunter in Amazon ECR oder Google Artifact Registry, und Container Scanning muss auch mit solchen externen Quellen umgehen koennen. Fuer eine externe Registry werden die Zugangsdaten ueber CS_REGISTRY_USER und CS_REGISTRY_PASSWORD als geschuetzte CI/CD-Variablen hinterlegt, waehrend CS_IMAGE die vollstaendige Registry-URL inklusive Tag enthaelt, statt sich wie bei der projekteigenen Registry auf CI_REGISTRY_IMAGE zu verlassen.
Wichtig ist dabei, die Zugangsdaten mit moeglichst eingeschraenkten Rechten zu versehen, idealerweise ein reiner Lesezugriff auf genau das eine Repository, das gescannt werden soll, statt eines administrativen Zugangs auf die gesamte Registry. Bei selbst gehosteten, privaten Registries mit selbstsigniertem Zertifikat kann zusaetzlich die Variable DOCKER_INSECURE oder ein manuell hinterlegtes CA-Zertifikat noetig sein, damit der Scan-Job die TLS-Verbindung erfolgreich aufbauen kann, ohne die generelle Sicherheit der Pipeline durch pauschales Abschalten der Zertifikatspruefung zu untergraben.
# .gitlab-ci.yml: Image aus einer externen Registry scannen
container_scanning:
variables:
CS_IMAGE: "registry.example.com/team/app:1.4.2"
CS_REGISTRY_USER: "$EXTERNAL_REGISTRY_USER"
CS_REGISTRY_PASSWORD: "$EXTERNAL_REGISTRY_PASSWORD"
7. Die richtige Basis-Image-Strategie als wirksamster Hebel
Die mit Abstand wirksamste Massnahme gegen Container-Scanning-Findings ist nicht das Scannen selbst, sondern die bewusste Wahl und Pflege des Basis-Images. Schlanke, spezialisierte Images wie Alpine-basierte Varianten oder distroless Images von Google enthalten von vornherein deutlich weniger installierte Pakete und damit eine kleinere Angriffsflaeche als ein volles Ubuntu- oder Debian-Image mit allen Standardwerkzeugen. Wo immer die Anwendung es zulaesst, reduziert ein schlankeres Basis-Image die Zahl der Findings oft drastischer als jede nachtraegliche Konfiguration des Scanners.
Ebenso wichtig ist, Basis-Images regelmaessig zu aktualisieren, statt einmal einen funktionierenden Tag zu fixieren und diesen jahrelang unveraendert zu lassen. Ein woechentlicher, per Scheduled Pipeline ausgeloester Rebuild mit dem jeweils aktuellen Basis-Image-Patch-Level zieht automatisch alle seither veroeffentlichten Sicherheitsfixes des Betriebssystem-Layers, ohne dass eine Aenderung am eigenen Dockerfile noetig waere. Diese Kombination aus schlankem Basis-Image und regelmaessigem Rebuild reduziert die Zahl der Container-Scanning-Findings in der Praxis meist um eine Groessenordnung.
8. Schwellenwerte, Ausnahmen und der Umgang mit unfixbaren Findings
Nicht jede gemeldete Schwachstelle hat bereits eine verfuegbare Fix-Version, insbesondere bei aelteren oder weniger aktiv gepflegten Basis-Images. Fuer solche Faelle bietet GitLab die Moeglichkeit, Findings ueber eine .gitlab/security-policies-Datei oder direkt im Security-Dashboard als vorlaeufig akzeptiertes Risiko zu markieren, mit Ablaufdatum, damit die Ausnahme nicht dauerhaft unbemerkt bestehen bleibt, sondern regelmaessig neu bewertet werden muss.
Fuer produktionskritische Images empfiehlt sich zudem eine Scan Result Policy, die Deployments mit ungeloesten Critical-Findings ohne dokumentierte Ausnahme blockiert, kombiniert mit einer klar definierten Eskalationsfrist, etwa dass ein Critical-Finding innerhalb von 72 Stunden entweder behoben oder mit Begruendung als Ausnahme dokumentiert werden muss. Diese Kombination aus technischer Durchsetzung und organisatorischem Prozess verhindert, dass Container Scanning zu reiner Kosmetik im Merge-Request-Widget verkommt, ohne tatsaechliche Verhaltensaenderung zu bewirken.
# .gitlab-ci.yml: nur Critical- und High-Findings sollen den Job scheitern lassen
container_scanning:
variables:
CS_SEVERITY_THRESHOLD: "HIGH"
9. Best Practices und Vergleich der Ansaetze
In der Praxis bewaehrt sich, Container Scanning fest als Pflichtschritt zwischen Image-Build und Deploy-Stage zu verankern, statt es als optionalen, leicht uebersehbaren Zusatzjob zu behandeln. Kombiniert mit einer klaren Basis-Image-Strategie, regelmaessigen Rebuilds und einer dokumentierten Ausnahme-Regelung fuer unfixbare Findings entsteht ein Prozess, der Container-Schwachstellen systematisch statt zufaellig behandelt.
Die Wahl zwischen dem GitLab-Template und einem eigenstaendigen Trivy-Einsatz haengt letztlich davon ab, wie stark die native Merge-Request-Integration gewichtet wird gegenueber der vollen Konfigurationsflexibilitaet eines eigenstaendigen Tools. Die folgende Tabelle stellt beide Ansaetze anhand ihrer wichtigsten Eigenschaften gegenueber, um die Entscheidung fuer das eigene Projekt zu erleichtern.
| Kriterium | GitLab Container Scanning Template | Eigenstaendiges Trivy |
|---|---|---|
| Einrichtung | Ein include:template Eintrag | Eigener Job inklusive Ausgabekonvertierung |
| MR-Widget-Integration | Automatisch | Nur mit manueller Report-Konvertierung |
| Konfigurationsflexibilitaet | Eingeschraenkt auf CS_ Variablen | Voller Zugriff auf alle Trivy-Optionen |
| Security-Dashboard | Automatisch aggregiert | Nicht ohne Zusatzaufwand |
| IaC-Scanning im selben Tool | Nicht enthalten | Moeglich ueber trivy config |
Mironsoft
CI/CD-Pipelines, Zero-Downtime-Deployments und Release-Automatisierung
Deployments, die ohne Ausfallzeit und ohne Nervenkitzel laufen?
Wir prüfen bestehende GitLab-Pipelines auf fragile Deployment-Schritte und fehlende Absicherung und bauen daraus einen Release-Prozess mit Zero-Downtime-Deployments, automatisierten Checks und einem Rollback, dem ihr im Ernstfall vertrauen könnt.
Pipeline-Review
Bestehende .gitlab-ci.yml auf Fragilität, fehlende Stages und Sicherheitslücken prüfen.
Zero-Downtime-Deployment
Symlink-Releases, Health-Checks und Rollback-Strategien für Magento-Shops aufbauen.
CI/CD-Automatisierung
Tests, Security-Scans und Deployments zu einer zuverlässigen Pipeline verbinden.
10. Zusammenfassung
GitLab Container Scanning: Das Wichtigste auf einen Blick
Eigene Scan-Kategorie
Container Scanning prueft die Betriebssystem-Ebene des Images, die SAST und Dependency Scanning nicht abdecken.
Einfache Integration
include:template plus CS_IMAGE reicht aus, needs stellt korrekte Reihenfolge nach dem Image-Push sicher.
Basis-Image ist der Hebel
Ein schlankes, regelmaessig neu gebautes Basis-Image reduziert Findings staerker als jede Scanner-Konfiguration.
Diff statt Vollbild
GitLab zeigt neu hinzugekommene Findings getrennt von bereits im Basis-Image vorhandenen an.