Geheimnisse aus Containerimages fernhalten

DockerBeginner
Jetzt üben

Einführung

Eine aus einem Containerimage entfernte Datei kann weiterhin in einer früheren Imageschicht vorhanden sein. Auch Git-Ignorierregeln steuern nicht, was Docker während eines Builds erhält.

Du untersuchst ein vorbereitetes Image, beschränkst seine Build-Eingaben und prüfst jede Schicht eines neuen Images. Worker und Docker-Ablauf bauen auf dem vorherigen Lab auf. Alle Zugangsdaten sind fiktive lokale Testwerte; das zwischengespeicherte Basisimage und die Untersuchungshilfen sind vorbereitet.

Die vorbereiteten Build-Eingaben untersuchen

In diesem Schritt trennst du Ignorierregeln der Versionsverwaltung von Docker-Build-Eingaben.

cd /home/labex/project/ticket-image
ls -a

ls -a zeigt auch Dateien mit führendem Punkt an. Dieses Projekt enthält den Worker, öffentliche Konfiguration, Ein-/Ausgabeverzeichnisse, private.env und debug.txt. Die letzten beiden sind private lokale Eingaben, keine Auslieferungsdateien.

cat .gitignore

Git ignoriert die beiden privaten Namen. Das betrifft den Versionsverfolgungsablauf von Git, nicht den Build-Kontext von Docker.

cat .dockerignore

Die Datei ist derzeit leer. .dockerignore steuert, welche Pfade Docker ausschließt, wenn es den Build-Kontext erhält. Eine Datei kann von Git ignoriert und trotzdem an einen Docker-Build gesendet werden.

cat Dockerfile

COPY . /app/ kopiert den gesamten verfügbaren Kontext. Das spätere RUN rm ... entfernt private Dateien aus dem abschließenden Dateisystem, macht jedoch die frühere Imageschicht nicht rückgängig.

Die versteckte Kopie in einer Schicht finden

In diesem Schritt vergleichst du das abschließende Dateisystem mit gespeicherten Imageschichten.

Der vorbereitete alte Tag ticket-image:legacy wurde aus diesem Dockerfile gebaut. Starte einen einmaligen Untersuchungscontainer. --rm entfernt diesen temporären Container automatisch, nachdem ls beendet ist; sein Befehl überschreibt den standardmäßigen Worker-Start des Images:

sudo docker run --rm ticket-image:legacy ls -a /app

Das abschließende /app sollte weder private.env noch debug.txt auflisten. Es enthält weiterhin den Worker und die öffentliche Konfiguration.

docker history zeigt Anweisungen zum Image-Build an. --no-trunc erhält den vollständigen Anweisungstext:

sudo docker history --no-trunc ticket-image:legacy

Suche nach dem umfassenden Kopieren und dem anschließenden Entfernen. Die Historie erklärt die Abfolge, aber nicht den Inhalt jeder Datei. Das vorbereitete Hilfsprogramm course-image-scan speichert dieses tatsächliche Image und liest jede gespeicherte Schicht sowie die Image-Konfiguration:

sudo course-image-scan ticket-image:legacy

Erwartet werden Funde, die private Dateien in einer früheren Schicht und maskierte Ziel-Übungszugangsdaten benennen. Der Exit-Status 1 bedeutet Funde; 2 oder CHECK ERROR bedeutet, dass die Untersuchung fehlgeschlagen ist. Der feste Prüfumfang des Hilfsprogramms umfasst diese aufgelisteten privaten Namen und diese unechten Zugangsdaten, keinen vollständigen Scanner für Geheimnisse im Produktivbetrieb.

Löschungen in späteren Schichten entfernen frühere Bytes nicht. Eine erfolgreiche Prüfung des abschließenden Dateisystems mit ls reicht daher nicht aus.

Private Build-Eingaben ausschließen

In diesem Schritt behältst du die lokalen privaten Dateien bei und schließt sie zugleich aus dem Docker-Kontext aus.

nano .dockerignore

Verwende diese vollständige Datei:

private.env
debug.txt
input/
output/

Jede Zeile ist ein auszuschließender Pfad oder ein Verzeichnis. Diese Muster entfernen private Konfiguration, Debug-Material und Laufzeitdaten aus den Build-Eingaben; der Worker und config.public bleiben verfügbar.

Speichere mit Ctrl+O, Enter und beende den Editor mit Ctrl+X. Lösche die lokalen privaten Dateien nicht. Einen Pfad zu ignorieren soll seine Aufnahme begrenzen, nicht die lokale Konfiguration zerstören.

Den Kopierumfang des Dockerfiles begrenzen

In diesem Schritt machst du die erforderlichen Eingaben des Images ausdrücklich sichtbar.

Die alte Löschanweisung ist jetzt unnötig und würde fehlschlagen, weil die ausgeschlossenen Dateien nicht verfügbar sind. Öffne das Dockerfile:

nano Dockerfile

Verwende diese vollständige Datei:

FROM desklite-base:1.37.0
WORKDIR /app
COPY worker.sh config.public /app/
USER nobody
CMD ["sh", "/app/worker.sh"]

COPY worker.sh config.public /app/ führt nur die beiden erforderlichen Geschäftsdateien auf. Behalte USER nobody und den ursprünglichen Startbefehl aus dem vorherigen Lab bei. Speichere mit Ctrl+O, Enter, Ctrl+X.

Die beiden Maßnahmen wirken zusammen: .dockerignore beschränkt verfügbare Build-Eingaben, und das ausdrückliche COPY beschränkt, was dieses Image aufnimmt. Keine der beiden beruht darauf, ein Geheimnis zu löschen, nachdem es in eine Schicht gelangt ist.

Das neue Artefakt bauen und untersuchen

In diesem Schritt untersuchst du ein neu gebautes Auslieferungsimage, statt die Bedeutung der alten Nachweise zu verändern.

sudo docker build -t ticket-image:delivery .

Erwartet wird ein erfolgreicher lokaler Build. Der neue Tag unterscheidet sich von ticket-image:legacy.

sudo course-image-scan ticket-image:delivery

Erwartet wird ein PASS für jede gespeicherte Schicht und die Image-Konfiguration. Dieses auf die Prüfziele begrenzte Ergebnis behauptet nicht, dass jedes mögliche Geheimnis oder jede Schwachstelle erkannt wurde.

Prüfe nun den Kontext unabhängig davon:

sudo course-context-check .

Dieses vorbereitete Hilfsprogramm baut ein temporäres Image mit einer festen Prüfung durch COPY ., wendet dieselbe tatsächliche Schichtuntersuchung an und entfernt dann dieses temporäre Image. Erwartet wird PASS. Das weist nach, dass die privaten Dateien aus dem Kontext ausgeschlossen wurden, statt lediglich durch dein enger gefasstes Auslieferungs-COPY ausgelassen zu werden.

Das alte Image kann weiterhin den ursprünglichen Fund enthalten. Ein sauberes Auslieferungsartefakt neu zu bauen schreibt weder zuvor verteilte Images um noch widerruft es offengelegte Zugangsdaten. Echte Offenlegungen erfordern den zuvor erlernten Austausch von Zugangsdaten und eine angemessene Bereinigung alter Kopien. Hier ist das Zieltoken bewusst unecht, und die Abnahme betrifft das neue Auslieferungsimage.

Den ursprünglichen Bericht aus dem neuen Image erzeugen

In diesem Schritt weist du nach, dass das Entfernen privater Build-Eingaben die erforderlichen Dateien und das Verhalten des Workers erhalten hat.

Das Ausgabeverzeichnis gehört bereits der UID 65534 und hat privaten Schreibzugriff. Verwende den Worker ohne Root-Rechte und den Bind-Mount-Ablauf aus dem vorherigen Lab erneut:

sudo docker run -d --name ticket-image-worker --network none --mount type=bind,src=/home/labex/project/ticket-image/input,dst=/data/input,readonly --mount type=bind,src=/home/labex/project/ticket-image/output,dst=/data/output ticket-image:delivery
sudo docker exec ticket-image-worker id -u

Erwartet wird 65534.

sudo docker logs ticket-image-worker

Erwartet werden mode=report und tickets=2. Die erste Zeile stammt aus der erforderlichen öffentlichen Konfiguration; die zweite entsteht durch das Lesen der ursprünglichen Eingabe und das Schreiben des tatsächlichen Berichts.

sudo docker exec ticket-image-worker cat /data/output/report.txt

Erwartet wird tickets=2. Der Worker hat weiterhin schreibgeschützte Eingabe und beschreibbare Ausgabe und benötigt keine private Konfiguration innerhalb des Images.

Lokale Quellen und Auslieferungsnachweise bestätigen

In diesem Schritt schließt du ab, während sowohl die lokalen privaten Eingaben als auch das sichere Auslieferungsartefakt erhalten bleiben.

Liste die privaten Quelldateien auf, ohne ihre Inhalte auszugeben:

ls -l private.env debug.txt

Beide müssen weiterhin lokal vorhanden sein. Sie zu löschen würde die beabsichtigte Übung zur Build-Grenze umgehen.

sudo course-image-scan ticket-image:delivery
sudo docker ps

Die Auslieferungsprüfung sollte bestehen, und ticket-image-worker sollte laufen. Die Kursprüfung untersucht auch den tatsächlichen Build-Kontext, prüft die ID des laufenden Images und verifiziert den ursprünglichen Bericht. Eine separate schriftliche Untersuchungsdatei muss nicht abgegeben werden.

Zusammenfassung

Du hast die tatsächlichen Docker-Build-Eingaben beschränkt, nur erforderliche Geschäftsdateien kopiert, alle gespeicherten Schichten und die Image-Konfiguration untersucht und den ursprünglichen Worker ohne Root-Rechte erhalten. Ein sauberes abschließendes Dateisystem allein hätte diese Grenze nicht nachgewiesen.