
Mit Dockerfile war es immer schwierig, auf private Ressourcen zuzugreifen. Es gab einfach keine gute Lösung. Es ist nicht gut, Umgebungsvariablen zu verwenden oder geheime Dateien nach der Verwendung einfach zu löschen: Sie verbleiben in den Bildmetadaten. Benutzer gingen manchmal zu Tricks über: Sie erstellten mehrstufige Assemblys. Es war jedoch äußerste Vorsicht geboten, damit im Endstadium keine geheimen Werte vorhanden waren und geheime Dateien bis zum Abschneiden im lokalen Assemblycache gespeichert wurden.
Das Docker-Build-Team vom 18. September enthält viele Updates. Das Hauptmerkmal ist, dass eine völlig neue Version der serverseitigen Implementierung veröffentlicht wurde, die als Teil des Moby BuildKit-Projekts angeboten wird. Die BuildKit-Serveranwendung hat neue Funktionen erhalten, einschließlich der Unterstützung von Dockerfile-Build-Geheimnissen.
Geheimnisse benutzen
Zunächst müssen Sie die BuildKit-Serverseite aktivieren. BuildKit in Version 18.09
ist eine Auswahlfunktion, die mithilfe der Umgebungsvariablen DOCKER_BUILDKIT=1
aktiviert werden kann, bevor der docker build
gestartet wird. In der nächsten Version ist geplant, BuildKit standardmäßig zum Serverteil zu machen.
export DOCKER_BUILDKIT=1
Das Implementieren von Build-Geheimnissen basiert auf zwei neuen BuildKit-Funktionen. Eine davon ist die Möglichkeit, eine Benutzeroberfläche zu verwenden, die aus Bildern in der Registrierung geladen wurde. Die zweite ist die Möglichkeit, Einhängepunkte in RUN
Befehlen für die Docker-Datei zu verwenden. Um eine Implementierungsfunktion zu verwenden, die Geheimnisse unterstützt (anstelle der Standardfunktion), definieren Sie das Linker-Image mithilfe der Syntaxanweisung in der ersten Zeile der Docker-Datei. Geben Sie dabei das Image des Containers an, den Sie verwenden möchten. Bisher sind keine Geheimnisse im stabilen Kanal externer Docker-Dateien verfügbar: Sie benötigen eine der Versionen im experimentellen Kanal, z. B. docker/dockerfile:experimental
oder docker/dockerfile/1.0.0-experimental
.
# syntax=docker/dockerfile:1.0.0-experimental
Wenn Sie als Autor der Docker-Datei wissen, dass für den in der Docker-Datei installierten RUN
Befehl ein geheimer Wert erforderlich ist, verwenden Sie die Bezeichnung --mount
, um anzugeben, welches Geheimnis der Befehl benötigt und wo er bereitgestellt werden soll. Das Label --mount
akzeptiert eine durch Kommas getrennte Struktur wie in --mount
für den docker run
.
# syntax=docker/dockerfile:1.0.0-experimental FROM alpine RUN --mount=type=secret,id=mysite.key command-to-run
Diese Bezeichnung gibt an, dass der Befehl während des Betriebs Zugriff auf die geheime Datei über den Pfad /run/secrets/mysite.key
. Das Geheimnis steht nur dem Team mit dem Montageetikett und nicht anderen Teilen der Baugruppe zur Verfügung. Die Daten in dieser Datei werden basierend auf der angegebenen Kennung "mysite.key" aus dem Geheimspeicher heruntergeladen. Die Docker-Befehlszeilenschnittstelle unterstützt derzeit die Offenlegung von Geheimnissen aus lokalen --secret
mithilfe des Tags --secret
.
docker build --secret id=mysite.key,src=path/to/mysite.key .
Wie oben beschrieben, werden Geheimnisse standardmäßig in /run/secrets
. Sie können jedoch einen beliebigen Pfad mit dem Schlüssel "Ziel" angeben. Wenn "Ziel" angegeben ist, "ID" jedoch nicht, wird "ID" standardmäßig zum Basisnamen des Zielpfads.
Es ist nicht notwendig, sich auf ein Geheimnis zu beschränken. Sie können eine beliebige Anzahl von ihnen verwenden und unterschiedliche Bezeichner angeben.
Wenn der Autor der Docker-Datei angibt, dass die RUN
Anweisung das Geheimnis verwenden kann und der Benutzer, der die Assembly aufruft, es nicht bereitstellt, wird das Geheimnis ignoriert und keine Datei auf dem angegebenen Pfad installiert. Wenn diese Situation unerwünscht ist, verwenden Sie die Taste "Erforderlich". Dies zeigt an, dass die Assembly ohne Wert fehlschlägt.
# syntax=docker/dockerfile:1.0.0-experimental FROM alpine RUN --mount=type=secret,id=mysite.key,required <command-to-run>
Implementierung
Die geheime Datei wird automatisch nur in einem separaten tmpfs-Dateisystem installiert, um Undichtigkeiten im endgültigen Image oder im nächsten Befehl zu vermeiden, sodass sie nicht im lokalen Build-Cache gespeichert wird.
Geheime Werte werden auch von Build-Cache-Berechnungen ausgeschlossen, sodass der Metadaten-Cache nicht verwendet werden kann.
Ssh
Am häufigsten versuchen sie wahrscheinlich, über das SSH-Protokoll auf private Repositorys zuzugreifen. Ja, Sie können geheime Elemente verwenden, um den privaten SSH-Schlüssel für die Assembly anzuzeigen, aber es gibt eine bessere Lösung. Das SSH-Protokoll verwendet die Kryptografie mit öffentlichen Schlüsseln. Dank dieses Designs müssen Sie Ihren privaten Schlüssel an niemanden weitergeben. Wenn Sie beispielsweise mehrere Computer mit SSH verwenden, müssen Sie Ihren Schlüssel nicht übertragen. Stellen Sie lediglich eine Verbindung über das ssh-A
Protokoll her.
Wir haben eine ähnliche Funktion in docker build
hinzugefügt, mit der Sie die Bezeichnung --ssh
, um eine vorhandene SSH-Agentenverbindung oder einen vorhandenen Schlüssel zum Linker zu leiten. Anstatt Schlüsselinformationen zu übertragen, teilt Docker dem Linker einfach mit, dass diese verfügbar sind. Wenn der Linker über SSH auf den Remote-Server zugreifen muss, kontaktiert er den Client und bittet um Bestätigung der für die Verbindung erforderlichen spezifischen Anforderung. Der Schlüssel selbst verlässt das Client-Programm nicht, und nach Abschluss des Programms, für das Zugriff erforderlich war, bleiben keine Daten vom Linker übrig, um die Remoteverbindung neu zu installieren.
Der Zugriff auf die Dateiübertragung über das SSH-Protokoll wird nur Befehlen in der Docker-Datei gewährt, die durch Angabe des Blocks type=ssh
direkt den Zugriff auf SSH angefordert haben. Andere Befehle enthalten keine Daten zum verfügbaren SSH-Agenten.
Erwähnenswert ist auch ein weiterer Aspekt von SSH - die Verwendung des TOFU-Sicherheitsmodells. Bei der erstmaligen Verbindung mit dem SSH-Server werden Informationen zum unbekannten Host angefordert, da für diesen Server kein lokaler Schlüssel lokal verfügbar ist und dementsprechend nicht überprüft werden kann, ob der von der Gegenstelle bereitgestellte öffentliche Schlüssel für diese Adresse gültig ist.
Beim Zusammenstellen mit Dockerfile kann die Richtigkeit dieser Anforderung nicht überprüft werden. Dementsprechend muss der öffentliche Schlüssel des Servers bereits in dem Container vorhanden sein, der versucht, SSH zu verwenden. Es gibt verschiedene Möglichkeiten, diesen öffentlichen Schlüssel zu erhalten. Das Basis-Image stellt es beispielsweise bereit, oder Sie kopieren es aus dem Build-Kontext. Wenn Sie eine einfachere Lösung wünschen, führen Sie das Programm ssh–keyscan
als Teil der Assembly aus. Es lädt den aktuellen öffentlichen Schlüssel des Hosts.
Um den SSH-Zugriff auf den Befehl RUN
in der Docker-Datei anzufordern, müssen Sie einen Block vom Typ "ssh" angeben. Während des Vorgangs wird dann ein Socket mit schreibgeschütztem Zugriff auf den SSH-Agenten installiert. Dadurch wird auch die Umgebungsvariable SSH_AUTH_SOCK
, sodass Programme, die das SSH-Protokoll verwenden, diesen Socket automatisch verwenden.
# syntax=docker/dockerfile:experimental FROM alpine # install ssh client and git RUN apk add --no-cache openssh-client git # download public key for github.com RUN mkdir -p -m 0600 ~/.ssh && ssh-keyscan github.com >> ~/.ssh/known_hosts # clone our private repository RUN --mount=type=ssh git clone git@github.com:myorg/myproject.git myproject
Verwenden Sie auf der Docker-Clientseite die Bezeichnung --ssh
anzugeben, dass die SSH-Weiterleitung für diese Assembly zulässig ist.
docker build --ssh default .
Das Label akzeptiert ein Paar von Schlüsselwerten, die den Socket-Standort des lokalen SSH-Agenten oder der privaten Schlüssel bestimmen. Wenn Sie den Wert default=$SSH_AUTH_SOCK
, können Sie den Socket-Pfad leer lassen.
Im Dockerfile-Block können Sie auch den ID-Schlüssel verwenden, um die verschiedenen Server in derselben Assembly zu trennen. Beispielsweise kann der Zugriff auf verschiedene Repositorys in der Docker-Datei mit verschiedenen Bereitstellungsschlüsseln erfolgen. In diesem Fall verwenden Sie in der Docker-Datei:
… RUN --mount=type=ssh,id=projecta git clone projecta … RUN --mount=type=ssh,id=projectb git clone projectb …
und erweitern Sie die --ssh projecta=./projecta.pem --ssh projectb=./projectb.pem
mit Docker Build --ssh projecta=./projecta.pem --ssh projectb=./projectb.pem
. Beachten Sie, dass selbst wenn Sie die tatsächlichen Schlüssel angeben, nur die Agentenverbindung an den Linker gesendet wird, nicht der tatsächliche Inhalt dieser privaten Schlüssel.
Damit ist die Überprüfung der neuen Funktionen von Build-Geheimnissen in Docker 18.09 abgeschlossen. Ich hoffe, dass die neuen Funktionen dazu beitragen werden, die Funktionen von Dockerfile in Projekten besser zu nutzen und ein höheres Maß an Sicherheit für das Fließband zu bieten.