In zehn Sessions haben wir sechs Security-Tools in eine GitLab-Pipeline verdrahtet, die auf jedem Commit und jedem Merge Request feuert. Sind wir damit fertig? Nicht ganz. Code, der in Produktion läuft, bleibt dort Wochen oder Monate liegen, und in dieser Zeit finden Security-Researcher laufend neue CVEs in genau den Dependencies, die du längst ausgeliefert hast. In Teil 11 der GitLab DevSecOps Serie bauen Patrick Steger und ich eine Scheduled Pipeline, die den Production-Branch automatisch erneut scannt — ohne dass jemand pushen muss.
Warum Commit-getriggerte Pipelines nicht reichen#
Jeder Job, den wir bisher gebaut haben, läuft, wenn sich etwas ändert. Das deckt neuen Code ab, aber nicht das, was mit altem Code passiert, während sich die Welt drumherum bewegt. Eine Library, die du vor drei Monaten eingezogen hast, war damals sauber und hat heute vielleicht eine kritische CVE. Die Unit Tests werden es dir nicht sagen. Der statische Analyzer wird es dir nicht sagen. Das Einzige, was es findet, ist ein erneuter Lauf des Dependency Scanners gegen denselben unveränderten Code.
Genau dafür sind Scheduled Pipelines da: die Security-Checks regelmässig gegen den Branch laufen lassen, der den Production-Release enthält, sodass neu gefundene Vulnerabilities auch dann auftauchen, wenn die Entwicklung längst weitergezogen ist.
Was läuft mit — und was bleibt aussen vor#
Ein Scheduled Run braucht nicht die ganze Pipeline. Viele Jobs sind in diesem Kontext reine Verschwendung. Unit Tests gegen unveränderten Code geben in drei Monaten dasselbe Ergebnis wie heute. Dasselbe gilt für SAST gegen Code, der sich nicht bewegt hat. Sie erneut laufen zu lassen kostet Minuten und bringt Rauschen, sonst nichts.
Die zwei Jobs, die sich auf einem Schedule wirklich lohnen, sind die, die nach aussen schauen:
- SCA / Dependency Scanning. Geht den Dependency-Tree durch und gleicht jede Library und Version gegen die aktuelle CVE-Datenbank ab. Genau dafür machen wir das alles.
- Container Scanning. Das Docker-Image, das in Produktion läuft, kann seit dem Build neue OS-Vulnerabilities bekommen haben. Gleiche Idee, andere Schicht.
Zwei Jobs, auf einem Schedule, gegen den Production-Branch. Für die meisten Teams reicht das.
So richtest du das in GitLab ein#
Mechanisch ist es einfach, mit einem Trick. GitLabs Scheduled Pipelines führen ein normales .gitlab-ci.yml aus, also brauchen wir einen Weg, dass jeder Job entscheiden kann, ob er im Scheduled-Modus mitlaufen darf oder nicht. Das machen wir über eine Variable.
Das Rezept:
- Stelle sicher, dass du einen eigenen Release-Branch hast — den, der spiegelt, was in Produktion läuft.
- Geh in GitLab nach CI/CD → Schedules und lege einen neuen Schedule an. Wähle den Cron (täglich ist ein guter Default, wöchentlich ist für viele Teams in Ordnung), wähle den Production-Release-Branch und füge eine Variable namens
SCAN_ONLYmit irgendeinem Wert hinzu (wir nehmentrue). - Im
.gitlab-ci.ymlfügst du jedem Job, der im Scheduled-Lauf nicht mitlaufen soll, einenrules:-Block hinzu. Die Regel sagt: istSCAN_ONLYgesetzt, läuft dieser Job nie. Die SCA- und Container-Scanning-Jobs bekommen diese Regel nicht — sie laufen weiter.
Schedule speichern. Ab jetzt startet GitLab die Pipeline auf dem Cron, den du definiert hast, auf dem Branch, den du gewählt hast, mit gesetztem SCAN_ONLY — und nur die Security-Jobs, die du wirklich willst, laufen.
Warum die Variable der Schlüssel ist#
Du könntest das auch mit zwei Pipeline-Files lösen, aber dann hast du zwei Pipelines, die du synchron halten musst. Sobald du ein neues Tool dazunimmst, musst du daran denken, es an beiden Stellen einzubauen. Ein einziges Pipeline-File mit einer SCAN_ONLY-Regel auf jedem nicht relevanten Job hält alles an einem Ort. Der Schedule entscheidet über die Variable, was läuft; jeder Job entscheidet für sich, ob ihn das interessiert.
Es macht ausserdem die Absicht beim Lesen der Pipeline offensichtlich. Ein Job mit if: $SCAN_ONLY und when: never ist selbsterklärend: “Dieser Job ist nicht Teil des Scheduled Scans.”
Sind wir jetzt sicher?#
Wenn du alles hast, was wir in der Serie aufgebaut haben — SAST, Secret Detection, SCA, Container Scanning, DAST, Vulnerability Management, Merge-Request-Gating und jetzt ein Scheduled Re-Scan der Produktion — bist du auf dem besten Weg, den GitLab ohne Drittanbieter-Tools hergibt. Du wirst weiter Probleme finden. Du wirst weiter triagieren müssen. Aber du findest sie, solange sie billig zu beheben sind, statt sie von einem Auditor oder einem Incident vorgesetzt zu bekommen.
In der nächsten Session schliessen wir die Serie mit den Empfehlungen, die Patrick und ich einem Team geben würden, das frisch damit anfängt.
Key Takeaways#
Commit-Trigger fangen keine neuen CVEs in altem Code. Eine Library, die vor drei Monaten sauber war, kann heute kritisch sein. Dafür brauchst du einen Schedule.
Lass nur das laufen, was sich zwischen den Läufen ändern kann. SCA und Container Scanning lohnen sich auf einem Schedule. Unit Tests und SAST gegen unveränderten Code sind Rauschen.
Ein Pipeline-File, eine Variable.
SCAN_ONLYaus dem Schedule setzen, irrelevante Jobs mit einemrules:-Block ausgaten. Kein zweites Pipeline-File, das synchron gehalten werden muss.Wähle einen echten Production-Branch. Der Schedule ist nur so nützlich wie der Branch, auf den er zeigt. Stell sicher, dass dieser Branch tatsächlich abbildet, was in Produktion läuft.
Täglich oder wöchentlich reicht. Du musst nicht alle sechs Minuten scannen. Wähl eine Kadenz, die zu der Geschwindigkeit passt, mit der du auf ein neues Finding reagieren kannst.
Scheduled Scanning schliesst den Loop. Pipelines auf Commit fangen das, was du schreibst. Schedules fangen das, was die Welt über deine Dependencies schreibt. Beides brauchst du.
