Docker und Sicherung von Passwörtern

162

Ich habe kürzlich mit Docker experimentiert, um einige Dienste zu entwickeln, mit denen ich herumspielen kann, und eine Sache, die mich immer wieder nervt, ist das Einfügen von Passwörtern in eine Docker-Datei. Ich bin ein Entwickler, daher fühlt sich das Speichern von Passwörtern in der Quelle wie ein Schlag ins Gesicht an. Sollte dies überhaupt ein Problem sein? Gibt es gute Konventionen zum Umgang mit Passwörtern in Dockerfiles?

Anthonator
quelle
7
Es gibt ein offenes Problem bei Github, in dem nach Best Practices in Bezug auf Docker und Geheimnisse gefragt wird. Das Problem ist hier: github.com/docker/docker/issues/13490
Luís Bianchin

Antworten:

92

Auf jeden Fall ist es ein Problem. Docker-Dateien werden normalerweise in Repositorys eingecheckt und mit anderen Personen geteilt. Eine Alternative besteht darin, zur Laufzeit alle Anmeldeinformationen (Benutzernamen, Kennwörter, Token usw.) als Umgebungsvariablen bereitzustellen . Dies ist über das -eArgument (für einzelne --env-fileVariablen in der CLI) oder das Argument (für mehrere Variablen in einer Datei) möglich docker run. Lesen Sie dies für die Verwendung von Umwelt mit Docker-Compose.

Die Verwendung --env-fileist definitiv eine sicherere Option, da dies vor den Geheimnissen schützt, die bei Verwendung in psoder in Protokollen auftauchen set -x.

Umgebungsvariablen sind jedoch auch nicht besonders sicher. Sie sind über sichtbar docker inspectund stehen daher jedem Benutzer zur Verfügung, der dockerBefehle ausführen kann. (Natürlich hat jeder Benutzer, der dockerauf dem Host Zugriff hat, sowieso auch root .)

Mein bevorzugtes Muster ist die Verwendung eines Wrapper-Skripts als ENTRYPOINToder CMD. Das Wrapper-Skript kann zur Laufzeit zuerst Geheimnisse von einem externen Speicherort in den Container importieren und dann die Anwendung ausführen und die Geheimnisse bereitstellen. Die genaue Mechanik hängt von Ihrer Laufzeitumgebung ab. In AWS können Sie eine Kombination aus IAM-Rollen, dem Key Management Service und S3 verwenden, um verschlüsselte Geheimnisse in einem S3-Bucket zu speichern. Etwas wie HashiCorp Vault oder Credstash ist eine weitere Option.

AFAIK Es gibt kein optimales Muster für die Verwendung vertraulicher Daten als Teil des Erstellungsprozesses. Tatsächlich habe ich eine SO-Frage zu diesem Thema. Sie können Docker-Squash verwenden , um Ebenen aus einem Bild zu entfernen. Zu diesem Zweck gibt es in Docker jedoch keine native Funktionalität.

Möglicherweise finden Sie Shykes- Kommentare zur Konfiguration in Containern hilfreich.

Ben Whaley
quelle
Wie in anderen Kommentaren erwähnt, gibt es 2 Ebenen (nach ADD und nach dem ersten RUN), die .configDateien enthalten .
Petr Gladkikh
1
Ja, env-Variablen scheinen der beste Weg zu sein. Ich habe dies im Zusammenhang mit der Entwicklung von TDDing Dockerfile betrachtet.
Gnoll110
5
Ich mache mir Sorgen, dass Ihr Passwort, wenn es eine env-Variable ist, in angezeigt wird docker inspect.
schlank
Für eine Standardinstallation von Docker (unter Linux) sind Sudoer-Berechtigungen erforderlich docker inspect. Wenn der Angreifer bereits sudo kann, ist es wahrscheinlich ziemlich niedrig auf Ihrer Liste der Dinge, die jetzt schief gehen können, Ihr Passwort aus Docker Inspect zu entreißen. Dieses besondere Detail scheint mir ein akzeptables Risiko zu sein.
GrandOpener
7
@GrandOpener Dies gilt nur für Situationen, in denen ein Angreifer Ihr System verwendet. Wenn ich ein Docker-Image in ein Repository schiebe und es von jemand anderem abgerufen wird, ist es mir egal, ob sie Sudo auf ihrem eigenen System haben, aber es ist mir definitiv wichtig, ob sie Geheimnisse in env sehen, die nicht mehr vorhanden sein sollen.
vee_ess
74

Unser Team vermeidet es, Anmeldeinformationen in Repositorys zu speichern, sodass sie nicht zugelassen werden Dockerfile. Unsere beste Vorgehensweise bei Anwendungen ist die Verwendung von Creds aus Umgebungsvariablen.

Wir lösen dies mit docker-compose.

Innerhalb docker-compose.ymlkönnen Sie eine Datei angeben, die die Umgebungsvariablen für den Container enthält:

 env_file:
- .env

Stellen Sie sicher , hinzufügen .envzu .gitignore, dann die Anmeldeinformationen innerhalb der eingestellten .envDatei wie:

SOME_USERNAME=myUser
SOME_PWD_VAR=myPwd

Speichern Sie die .envDatei lokal oder an einem sicheren Ort, an dem der Rest des Teams sie abrufen kann.

Siehe: https://docs.docker.com/compose/environment-variables/#/the-env-file

theUtherSide
quelle
15
Sie können dies auch ohne eine .env-Datei tun, wenn Sie dies wünschen. Verwenden Sie einfach die Umgebungseigenschaft in Ihrer Datei docker-compose.yml. "Umgebungsvariablen mit nur einem Schlüssel werden auf dem Computer, auf dem Compose ausgeführt wird, in ihre Werte aufgelöst. Dies kann für geheime oder hostspezifische Werte hilfreich sein."
D. Visser
1
Gib diesem Mann einen Keks! :) yep das ist wirklich eine gute Praxis Ich möchte nur hinzufügen, dass docs.docker.com/compose/env-file dies automatisch funktionieren sollte, aber in Docker Compose Version 2 scheint es, dass Sie es wie in dieser Antwort beschrieben deklarieren müssen.
Äquivalent8
5
Die Verwendung von Umgebungsvariablen wird vom Docker-Team selbst nicht empfohlen, da env var über / proc / <pid> / environ und Docker inspect angezeigt werden kann. Es verschleiert nur den Weg, um die Anmeldeinformationen für einen Angreifer zu erhalten, der Root-Zugriff erhalten hat. Natürlich sollten Anmeldeinformationen niemals vom CVS verfolgt werden. Ich denke, die einzige Möglichkeit, einen Root-Benutzer daran zu hindern, ein Guthaben zu erhalten, besteht darin, die Anmeldeinformationen aus der Webanwendung (in der Hoffnung, dass die Prozessumgebungsdatei nicht aktualisiert wird) aus einer verschlüsselten Datei zu lesen, wobei der Entschlüsselungsprozess sicher nach einem Kennwort fragt. Ich denke, ich werde es mit einem Grab versuchen: github.com/dyne/Tomb
pawamoy
.gitignoredamit die .envDatei mit vertraulichen Informationen nicht in GitHub eingecheckt wird. Ich bin mir ziemlich sicher, dass dies nicht funktioniert, wenn Sie es hinzufügen.dockerignore
theUtherSide
hi @theUtherSide, danke für Ihre Antwort. Ich hatte eine Frage. Wenn ich die .envDatei nicht einchecke und eine Bereitstellung auf einem Server vor Ort durchführe, schlagen Sie vor, die .envDatei manuell erneut auf dem Server zu erstellen ?
OpenSource-Entwickler
37

Docker jetzt (Version 1.13 oder 17.06 und höher) unterstützt die Verwaltung geheimer Informationen. Hier ist eine Übersicht und eine detailliertere Dokumentation

Eine ähnliche Funktion gibt es in Kubernetes und DCOS

Heather QC
quelle
Einige nützliche Befehle über die obigen Links docker secret create:: Geheimnis erstellen docker secret inspect: Detaillierte Informationen zu einem Geheimnis anzeigen docker secret ls: Alle Geheimnisse anzeigen docker secret rm: Ein bestimmtes geheimes --secretFlag entfernen für docker service create: Ein Geheimnis während der Diensterstellung erstellen --secret-addund --secret-rmFlags für docker service update: Den Wert eines Geheimnisses aktualisieren oder ein Geheimnis entfernen während der Service-Update-Aufgabe. Docker-Geheimnisse werden in Ruhe auf Manager-Knoten geschützt und beim Starten des Containers für Worker-Knoten bereitgestellt.
PJ
7
Ja, Sie müssen einen Schwarm einrichten, um Docker-Geheimnisse nutzen zu können
Heather QC
11
Dies ist ein guter Anfang für eine Antwort, benötigt jedoch viel mehr Informationen von dem, was verknüpft ist, um in der Antwort selbst zu erscheinen.
Jeff Lambert
7
Ich bin mir nicht sicher, ob dies die akzeptierte Antwort sein kann, wenn es nur mit Schwärmen funktioniert. Viele Menschen benutzen keine Schwärme, müssen aber dennoch Geheimnisse preisgeben.
John Y
9

Sie sollten einem Container niemals Anmeldeinformationen hinzufügen, es sei denn, Sie senden die Creds an jeden, der das Bild herunterladen kann. Insbesondere ist dies und ADD credsspäter RUN rm credsnicht sicher, da die creds-Datei im endgültigen Image in einer Zwischenschicht des Dateisystems verbleibt. Jeder, der Zugriff auf das Bild hat, kann es einfach extrahieren.

Die typische Lösung, die ich gesehen habe, wenn Sie Creds zum Auschecken von Abhängigkeiten benötigen, besteht darin, einen Container zum Erstellen eines anderen zu verwenden. Das heißt, normalerweise befindet sich in Ihrem Basiscontainer eine Build-Umgebung, die Sie aufrufen müssen, um Ihren App-Container zu erstellen. Die einfache Lösung besteht also darin, Ihre App-Quelle und dann RUNdie Build-Befehle hinzuzufügen . Dies ist unsicher, wenn Sie Creds benötigen RUN. Stattdessen legen Sie Ihre Quelle in einem lokalen Verzeichnis ab. Führen Sie docker runden Container (wie in ) aus, um den Erstellungsschritt auszuführen, wobei das lokale Quellverzeichnis als Volume bereitgestellt und die Creds entweder injiziert oder als anderes Volume bereitgestellt werden. Sobald der Erstellungsschritt abgeschlossen ist, erstellen Sie Ihren endgültigen Container, indem Sie einfach ADDdas lokale Quellverzeichnis aufrufen, das jetzt die erstellten Artefakte enthält.

Ich hoffe, Docker fügt einige Funktionen hinzu, um dies alles zu vereinfachen!

Update: Es sieht so aus, als ob die Methode in Zukunft verschachtelte Builds haben wird. Kurz gesagt, die Docker-Datei würde einen ersten Container beschreiben, der zum Erstellen der Laufzeitumgebung verwendet wird, und dann einen zweiten verschachtelten Container-Build, der alle Teile zum endgültigen Container zusammenfügen kann. Auf diese Weise befindet sich das Build-Time-Material nicht im zweiten Container. Dies ist eine Java-App, bei der Sie das JDK zum Erstellen der App benötigen, aber nur die JRE zum Ausführen. Es werden eine Reihe von Vorschlägen diskutiert. Beginnen Sie am besten unter https://github.com/docker/docker/issues/7115 und folgen Sie einigen Links für alternative Vorschläge.

TvE
quelle
7

Eine Alternative zur Verwendung von Umgebungsvariablen, die bei vielen von ihnen unübersichtlich werden können, besteht darin, Volumes zu verwenden, um ein Verzeichnis auf dem Host im Container zugänglich zu machen.

Wenn Sie alle Ihre Anmeldeinformationen als Dateien in diesem Ordner ablegen, kann der Container die Dateien lesen und nach Belieben verwenden.

Beispielsweise:

$ echo "secret" > /root/configs/password.txt
$ docker run -v /root/configs:/cfg ...

In the Docker container:

# echo Password is `cat /cfg/password.txt`
Password is secret

Viele Programme können ihre Anmeldeinformationen aus einer separaten Datei lesen. Auf diese Weise können Sie das Programm einfach auf eine der Dateien verweisen.

Malvineous
quelle
5

Nur zur Laufzeit Lösung

Docker-Compose bietet auch eine Lösung ohne Schwarmmodus (seit Version 1.11: Geheimnisse mit Bind-Mounts ).

Die Geheimnisse werden /run/secrets/von Docker-Compose als Dateien unten gemountet . Dies löst das Problem zur Laufzeit (Ausführen des Containers), jedoch nicht zur Build-Zeit (Erstellen des Images), da /run/secrets/es nicht zur Build-Zeit bereitgestellt wird. Darüber hinaus hängt dieses Verhalten davon ab, ob der Container mit Docker-Compose ausgeführt wird.


Beispiel:

Dockerfile

FROM alpine
RUN cat /run/secrets/password
CMD sleep inifinity

docker-compose.yml

version: '3.1'
services:
  app:
    build: .
    secrets:
      - password

secrets:
  password:
    file: password.txt

Führen Sie zum Erstellen Folgendes aus:

docker-compose up -d

Weiterführende Literatur:

Murmel
quelle
2

Mit Docker v1.9 können Sie die ARG-Anweisung verwenden , um Argumente abzurufen, die bei der Build-Aktion über die Befehlszeile an das Image übergeben wurden . Verwenden Sie einfach das Flag --build-arg . So können Sie vermeiden, explizite Passwörter (oder andere sinnvolle Informationen) in der Docker-Datei zu speichern und diese im laufenden Betrieb weiterzugeben.

Quelle: https://docs.docker.com/engine/reference/commandline/build/ http://docs.docker.com/engine/reference/builder/#arg

Beispiel:

Dockerfile

FROM busybox
ARG user
RUN echo "user is $user"

Befehl image erstellen

docker build --build-arg user=capuccino -t test_arguments -f path/to/dockerfile .

während des Builds drucken

$ docker build --build-arg user=capuccino -t test_arguments -f ./test_args.Dockerfile .

Sending build context to Docker daemon 2.048 kB
Step 1 : FROM busybox
 ---> c51f86c28340
Step 2 : ARG user
 ---> Running in 43a4aa0e421d
 ---> f0359070fc8f
Removing intermediate container 43a4aa0e421d
Step 3 : RUN echo "user is $user"
 ---> Running in 4360fb10d46a
**user is capuccino**
 ---> 1408147c1cb9
Removing intermediate container 4360fb10d46a
Successfully built 1408147c1cb9

Ich hoffe es hilft! Tschüss.

NickGnd
quelle
26
In den ARG-Dokumenten von Docker heißt es : "Es wird nicht empfohlen, Build-Time-Variablen zu verwenden, um Geheimnisse wie Github-Schlüssel, Benutzeranmeldeinformationen usw. zu übergeben."
Lie Ryan,
3
Wenn Sie sich nur fragen, warum Docker die --build-arg var=secretÜbergabe eines privaten SSH-Schlüssels an ein Image nicht empfiehlt , ist keine Begründung dokumentiert. Kann es jemand erklären?
Henk Wiersema
2
@HenkWiersema Prozessinformationen, Protokolle und Befehlsverlauf sind unsicher. Prozessinformationen sind öffentlich verfügbar und umfassen alle Befehlszeilenparameter. Häufig enden diese Aufrufe in Protokollen, die auch öffentlich sein können. Es ist nicht ungewöhnlich, dass ein Angreifer Informationen über laufende Prozesse überprüft und öffentliche Protokolldateien nach Geheimnissen durchsucht. Selbst wenn es nicht öffentlich ist, kann es in Ihrem Befehlsverlauf gespeichert werden, wodurch es für jemanden einfach wird, Geheimnisse über ein nicht administratives Konto zu erhalten.
tu-Reinstate Monica-dor duh
2
Was ist die empfohlene Methode, um Anmeldeinformationen bereitzustellen, die zum Zeitpunkt der Erstellung benötigt werden? Zum Beispiel ein Bild, das aws s3-Zugriff benötigt, um einen großen Datensatz abzurufen, der sich im Bild befindet?
ely
3
Ich stelle mir vor, der Grund, warum dies nicht empfohlen wird, ist, dass docker historyExposures build-arg/ ARGVariablen verfügbar sind. Man kann jedes Bild ziehen, es untersuchen und alle Geheimnisse sehen, die während des Builds als build-arg/ ARG-Parameter übergeben wurden.
vee_ess
2

Mein Ansatz scheint zu funktionieren, ist aber wahrscheinlich naiv. Sag mir, warum es falsch ist.

ARGs, die während der Docker-Erstellung festgelegt wurden, werden durch den Unterbefehl "Verlauf" verfügbar gemacht. Wenn Sie einen Container ausführen, stehen dem Container die im Befehl run angegebenen Umgebungsvariablen zur Verfügung, sind jedoch nicht Teil des Abbilds.

Führen Sie in der Docker-Datei ein Setup durch, das keine geheimen Daten enthält. Stellen Sie eine CMD von so etwas wie ein /root/finish.sh. Verwenden Sie im Befehl run Umgebungsvariablen, um geheime Daten in den Container zu senden. finish.shVerwendet die Variablen im Wesentlichen, um Build-Aufgaben abzuschließen.

Um die Verwaltung der geheimen Daten zu vereinfachen, legen Sie sie in einer Datei ab, die vom Docker geladen wird, der mit dem --env-fileSwitch ausgeführt wird. Halten Sie die Datei natürlich geheim. .gitignoreund derartige.

Läuft für mich finish.shein Python-Programm. Es prüft, ob es noch nicht ausgeführt wurde, und beendet dann das Setup (z. B. kopiert es den Datenbanknamen in Djangos settings.py).

Kieran Mathieson
quelle
2

Es gibt einen neuen Docker- Befehl für die Verwaltung von "Geheimnissen". Das funktioniert aber nur für Schwarmcluster.

docker service create
--name my-iis
--publish target=8000,port=8000
--secret src=homepage,target="\inetpub\wwwroot\index.html"
microsoft/iis:nanoserver 
José Ibañez
quelle
1

Die 12-Faktor-App-Methodik besagt, dass jede Konfiguration in Umgebungsvariablen gespeichert werden sollte.

Docker Compose kann in der Konfiguration Variablen ersetzen , sodass Kennwörter vom Host an den Docker übergeben werden können.

Bunyk
quelle
Ich schätze den Hinweis auf die Bibel.
JakeCowton
-2

Obwohl ich völlig einverstanden bin, gibt es keine einfache Lösung. Es gibt weiterhin einen einzigen Fehlerpunkt. Entweder die Docker-Datei usw. usw. Apcera hat einen Plan, der wie ein Kumpel aussieht - doppelte Authentifizierung. Mit anderen Worten, zwei Container können nur dann kommunizieren, wenn eine Apcera-Konfigurationsregel vorhanden ist. In ihrer Demo war die UID / PWD im Klartext und konnte nicht wiederverwendet werden, bis der Administrator die Verknüpfung konfiguriert hatte. Damit dies funktioniert, bedeutete es wahrscheinlich, dass Docker oder zumindest das Netzwerk-Plugin gepatcht wurde (falls es so etwas gibt).

Richard
quelle
2
Gibt es irgendwo eine Antwort auf die gestellte Frage?
Abhijit Sarkar