Minimale Container-Images
A production image ships a compiler, a package manager, and a shell, turning a small application flaw into a working toolkit. Perform the pivot, then cut the runtime down to a minimal stage with none of it.
Was ist Minimale Container-Images?
Jedes Werkzeug, das Sie in einem Produktions-Image ausliefern, ist ein Werkzeug, das ein Angreifer erbt. Ein Runtime-Image, das einen Paketmanager, einen Compiler, eine Shell und Netzwerk-Tools mitführt, verwandelt eine begrenzte Anwendungsschwachstelle in ein einsatzbereites Toolkit, weil der Angreifer nichts mehr selbst mitbringen muss. Diese Übung behandelt diese Eskalation: Beobachten Sie, wie ein Angreifer mithilfe des eigenen Inhalts des Images pivotiert, und reduzieren Sie die Runtime anschließend auf eine minimale Stage ohne Shell und ohne Build-Tooling.
Was Sie lernen in Minimale Container-Images
- Es erlaubt einem Angreifer mit eingeschränkter Code-Ausführung, alles zu holen und zu installieren, was er braucht, sodass ein kleiner Fehler zu einem vollständigen Foothold wird, ohne dass er eigenes Tooling mitbringen muss.
- Das Build-Tooling bleibt in der Build-Stage, und nur das kompilierte Artefakt und seine Laufzeitabhängigkeiten werden in das finale Image kopiert.
- Viele gängige Exploitation- und Persistenz-Techniken setzen eine Shell zum Ausführen von Befehlen voraus, sodass ihr Entfernen den einfachsten Weg von Code-Ausführung zu Kontrolle unterbricht.
- Bei der einen geht es darum, was die Layer noch aus dem Build aufzeichnen, bei dieser hier darum, was das finale Image einem Angreifer zur Laufzeit in die Hand gibt. Gleiches Werkzeug, unterschiedliches Versagen.
Minimale Container-Images — Trainingsschritte
-
Ein Foothold im Checkout
Bob beginnt nicht mit einer Shell. Der Checkout-Service erstellt PDF-Versandetiketten und ruft dafür eine Shell auf, und ein Feld in dieser Anfrage wird nicht bereinigt. Er injiziert eine Sonde, um zu bestätigen, dass er einen Befehl ausführen kann, und um zu sehen, wer und wo er ist.
-
Alles, was das Image mitbringt
Bob hat als App eine Ein-Befehl-nach-dem-anderen-Ausführung, aber noch keine Shell. Das ist normalerweise der Punkt, an dem ein Angreifer feststeckt, es sei denn, der Container reicht ihm ein Toolkit. Bevor er etwas Auffälliges tut, prüft er, was bereits installiert ist.
-
Die Cloud-Credentials per curl abrufen
Der Container läuft in der Cloud, und jede Cloud-Instanz stellt einen Metadaten-Dienst unter einer festen internen Adresse bereit, der die temporären Rollen-Credentials der Maschine ausgibt. Um ihn zu erreichen, braucht man einen HTTP-Client. Das Image hat einen mitgeliefert.
-
Wie ein Befehl zu einem Breach wurde
Bobs Zugriff auf die App war stark eingeschränkt.
-
Eine Shell in einem Runtime-Container
Skelwyn betreibt Endpoint Detection auf seinen Container-Hosts. Es weiß nicht, wofür jeder Container da ist; es meldet Verhalten, das nicht zu einer Runtime passt.
-
Bestätigen, was mitausgeliefert wurde
Alice reproduziert, was der Angreifer vorgefunden hat: Sie fragt den laufenden Container, welche dieser Tools er tatsächlich enthält.
-
Eine 412-MB-Runtime
Das Toolkit ist nicht kostenlos. Es ist Gewicht, und es ist Angriffsfläche. Alice prüft die Größe des Images, das der Service tatsächlich ausführt.
-
Wo das Toolkit hineinkommt
Das Image wird aus einem einzigen Dockerfile gebaut. Alice öffnet es, um zu sehen, warum ein Runtime-Container am Ende einen Compiler mitführt.
-
Eine Stage, alles wird mitausgeliefert
Das Image wird in einer einzigen Stage gebaut und ausgeführt, sodass die Runtime alles mitführt, was der Build benötigt.
-
Build von Runtime trennen
Die Korrektur ist ein Multi-Stage-Build: Das vollständige Image mit seiner Toolchain bleibt als Build-Stage, die die App kompiliert, und anschließend werden nur die fertige App und ihre Abhängigkeiten in ein distroless Runtime-Image kopiert, das weder Shell noch Paketmanager noch Compiler besitzt.