Docker e protezione delle password


162

Recentemente ho sperimentato Docker sulla costruzione di alcuni servizi con cui giocare e una cosa che mi tormenta è stata mettere le password in un file Docker. Sono uno sviluppatore, quindi archiviare le password nel sorgente sembra un pugno in faccia. Questo dovrebbe anche essere un problema? Esistono buone convenzioni su come gestire le password nei Dockerfile?


7
C'è un problema aperto su Github che richiede le migliori pratiche relative a Docker e segreti, il problema è qui: github.com/docker/docker/issues/13490
Luís Bianchin,

Risposte:


93

Sicuramente è una preoccupazione. I file Docker sono comunemente archiviati nei repository e condivisi con altre persone. Un'alternativa è fornire tutte le credenziali (nomi utente, password, token, qualsiasi cosa sensibile) come variabili di ambiente in fase di esecuzione . Ciò è possibile tramite l' -eargomento (per singoli parametri sulla CLI) o l' --env-fileargomento (per più variabili in un file) a docker run. Leggi questo per l'utilizzo ambientale con docker-compose.

L'uso --env-fileè sicuramente un'opzione più sicura poiché protegge dai segreti che compaiono psnei registri o se si utilizza set -x.

Tuttavia, neanche gli envar sono particolarmente sicuri. Sono visibili tramite docker inspecte quindi sono disponibili per qualsiasi utente in grado di eseguire dockercomandi. (Ovviamente, qualsiasi utente che ha accesso dockerall'host ha anche root comunque.)

Il mio modello preferito è usare uno script wrapper come ENTRYPOINTo CMD. Lo script wrapper può prima importare segreti da una posizione esterna nel contenitore in fase di esecuzione, quindi eseguire l'applicazione, fornendo i segreti. La meccanica esatta di questo varia in base all'ambiente di runtime. In AWS, puoi utilizzare una combinazione di ruoli IAM, Key Management Service e S3 per archiviare segreti crittografati in un bucket S3. Qualcosa come HashiCorp Vault o credstash è un'altra opzione.

AFAIK non esiste un modello ottimale per l'utilizzo di dati sensibili come parte del processo di generazione. In effetti, ho una domanda SO su questo argomento. È possibile utilizzare la finestra mobile-squash per rimuovere i livelli da un'immagine. Ma non esiste alcuna funzionalità nativa in Docker per questo scopo.

Puoi trovare utili i commenti di shykes su config in container .


Come notato in altri commenti ci saranno 2 livelli (dopo ADD e dopo il primo RUN) che contengono .configfile.
Petr Gladkikh,

1
Sì, le variabili env sembrano il modo migliore di procedere. Ho esaminato questo aspetto nel contesto dello sviluppo di TDDing Dockerfile.
gnoll110,

5
Sono preoccupato che se la tua password è una variabile env, appare in docker inspect.
magro,

Un'installazione predefinita di docker (su Linux) richiede i privilegi di sudoer per essere eseguita docker inspect. Se l'aggressore può già fare sudo, strappare la password dalla finestra mobile ispezionare è probabilmente abbastanza basso nella tua lista di cose che ora possono andare storte. Questo particolare dettaglio mi sembra un rischio accettabile.
GrandOpener,

7
@GrandOpener Questo vale solo per la situazione in cui un attaccante sta usando il tuo sistema. Se spingo un'immagine docker in un repository ed è estratta da qualcun altro, non mi interessa se hanno sudo sul proprio sistema, ma sicuramente mi interessa se vedono segreti in env che non dovrebbero più essere lì.
vee_ess,

75

Il nostro team evita di inserire le credenziali nei repository, quindi ciò significa che non sono ammessi Dockerfile. La nostra migliore pratica all'interno delle applicazioni è quella di utilizzare i crediti dalle variabili di ambiente.

Risolviamo per questo usando docker-compose.

All'interno docker-compose.yml, è possibile specificare un file che contiene le variabili di ambiente per il contenitore:

 env_file:
- .env

Assicurati di aggiungere .enva .gitignore, quindi imposta le credenziali all'interno del .envfile come:

SOME_USERNAME=myUser
SOME_PWD_VAR=myPwd

Archivia il .envfile localmente o in un luogo sicuro in cui il resto del team possa acquisirlo.

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


15
Puoi anche farlo senza un file .env, se lo desideri. Basta usare la proprietà environment nel file docker-compose.yml. "Le variabili di ambiente con solo una chiave vengono risolte sui loro valori sulla macchina su cui è in esecuzione Compose, che può essere utile per valori segreti o specifici dell'host."
D. Visser,

1
dai a quest'uomo un biscotto! :) sì, questa è davvero una buona pratica. Voglio solo aggiungere che docs.docker.com/compose/env-file dovrebbe funzionare automaticamente, ma nella docker compose la versione 2 sembra che sia necessario dichiararlo come descritto in questa risposta.
equivalente8

5
L'uso delle variabili di ambiente è sconsigliato dal team Docker stesso, dal momento che env var può essere visto attraverso / proc / <pid> / environment e docker inspect. Offusca solo il modo di ottenere le credenziali per un attaccante che ha ottenuto l'accesso come root. Naturalmente le credenziali non devono mai essere monitorate dal CVS. Immagino che l'unico modo per impedire a un utente root di ottenere credito sia leggere le credenziali dall'app Web (sperando che non aggiorni il suo file proc environment) da un file crittografato, il processo di decrittazione richiede in modo sicuro una password. Penso che proverò con una tomba: github.com/dyne/Tomb
pawamoy

.gitignorein modo che il .envfile con informazioni riservate non venga archiviato in GitHub. Sono abbastanza sicuro che non funzionerà se lo aggiungi.dockerignore
theUtherSide il

ciao @theUtherSide, grazie per la risposta, ho avuto una domanda, quando non eseguo il check-in del .envfile e eseguo una distribuzione su un server on premise, suggerisci di creare .envnuovamente il file sul server manualmente?
opensource-developer

37

Docker ora (versione 1.13 o 17.06 e successive) supporta la gestione di informazioni segrete. Ecco una panoramica e una documentazione più dettagliata

Funzionalità simile esiste in kubernetes e DCOS


Alcuni comandi utili dai link sopra docker secret create:: crea un segreto docker secret inspect: mostra informazioni dettagliate su un segreto docker secret ls: visualizza tutti i segreti docker secret rm: rimuovi un --secretcontrassegno segreto specifico per docker service create: crea un segreto durante la creazione del servizio --secret-adde --secret-rmcontrassegni per docker service update: aggiorna il valore di un segreto o rimuovi un segreto durante l'attività di aggiornamento del servizio. I segreti Docker sono protetti a riposo sui nodi del gestore e forniti ai nodi di lavoro durante l'avvio del contenitore.
PJ,

7
Sì, è necessario impostare uno sciame per utilizzare i segreti Docker
Heather QC

11
Questo è un buon inizio per una risposta, ma ha bisogno di molte più informazioni da ciò che è collegato per apparire nella risposta stessa.
Jeff Lambert,

7
Non sono sicuro che questa possa essere la risposta accettata se funziona solo con sciami. Molte persone non usano sciami, ma devono ancora passare segreti.
John Y,

9

Non dovresti mai aggiungere credenziali a un contenitore a meno che tu non stia trasmettendo le credenziali a chiunque può scaricare l'immagine. In particolare, fare e ADD credspoi RUN rm credsnon è sicuro perché il file dei crediti rimane nell'immagine finale in un livello di filesystem intermedio. È facile per chiunque abbia accesso all'immagine estrarla.

La soluzione tipica che ho visto quando hai bisogno di crediti per verificare le dipendenze e tale è quella di utilizzare un contenitore per costruirne un altro. Cioè, in genere hai un ambiente di creazione nel contenitore di base e devi invocarlo per creare il contenitore dell'app. Quindi la soluzione semplice è aggiungere l'origine dell'app e quindi RUNi comandi di generazione. Questo non è sicuro se hai bisogno di crediti in questo RUN. Invece, ciò che fai è mettere la tua sorgente in una directory locale, eseguire (come in docker run) il contenitore per eseguire il passo di compilazione con la directory di origine locale montata come volume e i crediti iniettati o montati come un altro volume. Una volta completato il passaggio di compilazione, si crea il contenitore finale semplicemente ADDinserendo la directory di origine locale che ora contiene gli artefatti creati.

Spero che Docker aggiunga alcune funzionalità per semplificare tutto questo!

Aggiornamento: sembra che il metodo in futuro sarà quello di avere build nidificate. In breve, il file docker descriverà un primo contenitore utilizzato per creare l'ambiente di runtime e quindi una seconda generazione di contenitori nidificati che può assemblare tutti i pezzi nel contenitore finale. In questo modo la roba di build-time non è nel secondo contenitore. Questa è un'app Java in cui è necessario JDK per creare l'app ma solo JRE per eseguirla. Sono in discussione diverse proposte, la migliore per iniziare da https://github.com/docker/docker/issues/7115 e seguire alcuni dei collegamenti per proposte alternative.


7

Un'alternativa all'utilizzo delle variabili di ambiente, che possono diventare complicate se ne hai molte, è usare i volumi per rendere accessibile una directory sull'host nel contenitore.

Se metti tutte le tue credenziali come file in quella cartella, il contenitore può leggere i file e usarli come preferisce.

Per esempio:

$ 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

Molti programmi possono leggere le loro credenziali da un file separato, quindi in questo modo puoi semplicemente puntare il programma su uno dei file.


5

soluzione solo runtime

docker-compose fornisce anche una soluzione in modalità non sciame (dalla v1.11: segreti che utilizzano i bind mount ).

I segreti sono montati come file di seguito /run/secrets/da docker-compose. Ciò risolve il problema in fase di esecuzione (esecuzione del contenitore), ma non in fase di creazione (creazione dell'immagine), poiché /run/secrets/non è montato in fase di creazione. Inoltre, questo comportamento dipende dall'esecuzione del contenitore con docker-compose.


Esempio:

Dockerfile

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

finestra mobile-compose.yml

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

secrets:
  password:
    file: password.txt

Per compilare, eseguire:

docker-compose up -d

Ulteriori letture:


2

Con Docker v1.9 è possibile utilizzare l' istruzione ARG per recuperare gli argomenti passati dalla riga di comando all'immagine durante l' azione di creazione . Usa semplicemente --build-arg . In questo modo puoi evitare di conservare password esplicite (o altre informazioni sensibili) sul file Docker e passarle al volo.

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

Esempio:

Dockerfile

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

comando build image

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

durante la compilazione stampa

$ 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

Spero che sia d'aiuto! Ciao.


26
Secondo i documenti ARG di Docker : "Non è consigliabile utilizzare variabili di build-time per passare segreti come chiavi github, credenziali utente ecc."
Lie Ryan,

3
Mi chiedo solo perché Docker sconsiglia di usare --build-arg var=secretper passare una chiave privata SSH in un'immagine, non ci sono ragioni logiche documentate. Qualcuno può spiegarlo?
Henk Wiersema,

2
@HenkWiersema Le informazioni sul processo, i registri e la cronologia dei comandi non sono sicuri. Le informazioni sul processo sono disponibili pubblicamente e includono tutti i parametri della riga di comando. Spesso queste chiamate finiscono in registri che possono essere anche pubblici. Non è raro che un utente malintenzionato controlli le informazioni sui processi in esecuzione e cerca i segreti dei file di registro pubblici. Anche quando non è pubblico, potrebbe essere archiviato nella cronologia dei comandi, il che renderebbe facile per qualcuno ottenere segreti attraverso un account non amministrativo.
tu-Reinstate Monica-dor duh,

2
Qual è il modo consigliato per fornire le credenziali necessarie al momento della compilazione? Ad esempio, un'immagine che necessita dell'accesso a aws s3 per recuperare un set di dati di grandi dimensioni che risiederà all'interno dell'immagine?
ely,

3
Immagino che il motivo per cui non è raccomandato sia perché docker historyespone build-arg/ ARGvariabili. Si può estrarre qualsiasi immagine, ispezionarla e vedere tutti i segreti passati durante la compilazione come parametro build-arg/ ARG.
vee_ess,

2

Il mio approccio sembra funzionare, ma è probabilmente ingenuo. Dimmi perché è sbagliato.

Gli ARG impostati durante la compilazione della finestra mobile sono esposti dal sottocomando cronologico, quindi non andare lì. Tuttavia, quando si esegue un contenitore, le variabili di ambiente fornite nel comando di esecuzione sono disponibili per il contenitore, ma non fanno parte dell'immagine.

Quindi, nel Dockerfile, esegui un'installazione che non implichi dati segreti. Imposta un CMD di qualcosa del genere /root/finish.sh. Nel comando di esecuzione, utilizzare le variabili ambientali per inviare dati segreti nel contenitore. finish.shutilizza essenzialmente le variabili per completare le attività di compilazione.

Per semplificare la gestione dei dati segreti, inserirli in un file caricato dalla finestra mobile eseguito con l' --env-fileopzione. Certo, mantieni il file segreto. .gitignoree simili.

Per me, finish.shesegue un programma Python. Verifica che non sia mai stato eseguito prima, quindi termina l'installazione (ad esempio, copia il nome del database in Django settings.py).


2

Esiste un nuovo comando docker per la gestione dei "segreti". Ma questo funziona solo per i gruppi di sciami.

docker service create
--name my-iis
--publish target=8000,port=8000
--secret src=homepage,target="\inetpub\wwwroot\index.html"
microsoft/iis:nanoserver 


-2

Mentre sono totalmente d'accordo, non esiste una soluzione semplice. Continua a esserci un singolo punto di errore. Il file docker, ecc. E così via. Apcera ha un piano che sembra sidekick: doppia autenticazione. In altre parole, due container non possono parlare a meno che non ci sia una regola di configurazione di Apcera. Nella loro demo uid / pwd era in chiaro e non poteva essere riutilizzato fino a quando l'amministratore non ha configurato il collegamento. Per far funzionare tutto ciò, probabilmente, significava patchare Docker o almeno il plug-in di rete (se esiste una cosa del genere).


2
C'è una risposta da qualche parte alla domanda posta?
Abhijit Sarkar,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.