web-dev-qa-db-fra.com

Docker et sécurisation des mots de passe

J'ai récemment expérimenté avec Docker la création de services sur lesquels jouer et une chose qui ne cesse de me tourmenter est de mettre des mots de passe dans un fichier Docker. Je suis un développeur, donc stocker des mots de passe dans le code source est comme un coup de poing dans le visage. Cela devrait-il être une préoccupation? Existe-t-il de bonnes conventions sur la gestion des mots de passe dans Dockerfiles?

107
anthonator

C'est vraiment une préoccupation. Les fichiers Docker sont généralement archivés dans des référentiels et partagés avec d'autres personnes. Une alternative consiste à fournir des informations d'identification (noms d'utilisateur, mots de passe, jetons, éléments sensibles) sous la forme de variables d'environnement à l'exécution . Ceci est possible via l'argument -e (pour des vars individuels sur la CLI) ou l'argument --env-file (pour plusieurs variables dans un fichier) à docker run. Lisez ceci pour utiliser l’environnement avec docker-compose.

Utiliser --env-file est définitivement une option plus sûre car elle protège contre les secrets apparaissant dans ps ou dans les journaux si l’on utilise set -x.

Cependant, les variables env ne sont pas particulièrement sécurisées non plus. Ils sont visibles via docker inspect et sont donc disponibles pour tout utilisateur pouvant exécuter des commandes docker. (Bien entendu, tout utilisateur ayant accès à docker sur l'hôte a également a la racine de toute façon.)

Mon modèle préféré consiste à utiliser un script wrapper en tant que ENTRYPOINT ou CMD. Le script d'emballage peut d'abord importer des secrets d'un emplacement extérieur dans le conteneur au moment de l'exécution, puis exécuter l'application en fournissant les secrets. La mécanique exacte de ceci varie en fonction de votre environnement d'exécution. Dans AWS, vous pouvez utiliser une combinaison de rôles IAM, le Key Management Service et S3 pour stocker des secrets chiffrés dans un compartiment S3. Quelque chose comme HashiCorp Vault ou credstash est une autre option.

Autant que je sache, il n’existe aucun modèle optimal pour l’utilisation de données sensibles dans le cadre du processus de construction. En fait, j'ai une/ SO question sur ce sujet. Vous pouvez utiliser docker-squash pour supprimer des calques d’une image. Mais il n'y a pas de fonctionnalité native dans Docker à cette fin.

Vous pouvez trouver des timides des commentaires sur la configuration dans des conteneurs utiles. 

66
Ben Whaley

Notre équipe évite de mettre des informations d'identification dans des référentiels, ce qui signifie qu'elles ne sont pas autorisées dans Dockerfile. Notre meilleure pratique dans les applications est d’utiliser des Cred à partir de variables d’environnement.

Nous résolvons pour cela en utilisant docker-compose.

Dans docker-compose.yml, vous pouvez spécifier un fichier contenant les variables d’environnement du conteneur:

 env_file:
- .env

Assurez-vous d’ajouter .env à .gitignore, puis définissez les informations d’identification dans le fichier .env comme suit:

SOME_USERNAME=myUser
SOME_PWD_VAR=myPwd

Stockez le fichier .env localement ou dans un emplacement sécurisé où le reste de l'équipe peut le récupérer.

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

56
theUtherSide

Docker maintenant (version 1.13 ou 17.06 et ultérieure) prend en charge la gestion des informations secrètes. Voici un aperçu et plus détaillé documentation

Une caractéristique similaire existe dans kubernetes et DCOS

27
Heather QC

Vous ne devez jamais ajouter d'informations d'identification à un conteneur, sauf si vous êtes d'accord pour diffuser les créations à quiconque peut télécharger l'image. Do et ADD creds et versions ultérieures RUN rm creds ne sont pas sécurisés, car le fichier creds reste dans l'image finale dans une couche de système de fichiers intermédiaire. Il est facile pour quiconque ayant accès à l'image de l'extraire.

La solution typique que j'ai vue lorsque vous avez besoin de crédits pour vérifier les dépendances est d'utiliser un conteneur pour en créer un autre. En d'autres termes, vous avez généralement un environnement de construction dans votre conteneur de base et vous devez l'invoquer pour créer votre conteneur d'applications. La solution simple consiste donc à ajouter la source de votre application, puis RUN aux commandes de construction. Ce n'est pas sûr si vous avez besoin de crédits dans cette RUN. Au lieu de cela, vous placez votre source dans un répertoire local, exécutez (comme dans docker run) le conteneur pour effectuer l'étape de création avec le répertoire source local monté en tant que volume et les creds étant injectés ou montés en tant que autre volume. Une fois l’étape de construction terminée, vous construisez votre dernier conteneur en ajoutant simplement ADD au répertoire source local qui contient maintenant les artefacts construits.

J'espère que Docker va ajouter quelques fonctionnalités pour simplifier tout ça!

Mise à jour: il semble que la méthode à suivre consistera à avoir des versions imbriquées. En bref, le fichier docker décrirait un premier conteneur utilisé pour créer l'environnement d'exécution, puis une deuxième construction de conteneur imbriquée pouvant assembler toutes les pièces dans le conteneur final. De cette façon, le contenu de la construction n’est pas dans le second conteneur. Ceci d'une application Java pour laquelle vous avez besoin du JDK pour la construction de l'application, mais uniquement du JRE pour l'exécuter. Un certain nombre de propositions sont en cours de discussion. Il est préférable de commencer par https://github.com/docker/docker/issues/7115 et de suivre certains des liens vers d'autres propositions.

8
TvE

Avec Docker v1.9, vous pouvez utiliser l'instruction ARG pour récupérer les arguments passés par la ligne de commande à l'image sur build action. Utilisez simplement le drapeau --build-arg. Ainsi, vous pouvez éviter de conserver un mot de passe explicite (ou toute autre information utile) sur le fichier Docker et de le transmettre à la volée.

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

Exemple:

Dockerfile

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

construire une commande d'image

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

pendant la construction, il imprime

$ 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

J'espère que ça aide! Au revoir.

5
NickGnd

Une autre solution que l’utilisation de variables d’environnement, ce qui peut poser problème si vous en avez beaucoup, consiste à utiliser des volumes pour créer un répertoire accessible sur l’hôte dans le conteneur.

Si vous placez toutes vos informations d'identification sous forme de fichiers dans ce dossier, le conteneur peut alors lire les fichiers et les utiliser à votre guise.

Par exemple:

$ 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

De nombreux programmes peuvent lire leurs informations d'identification à partir d'un fichier séparé. Ainsi, vous pouvez simplement pointer le programme sur l'un des fichiers.

3
Malvineous

Mon approche semble fonctionner, mais est probablement naïve. Dis-moi pourquoi c'est faux.

Les ARG définis lors de la construction du menu fixe sont exposés par la sous-commande history, aussi n'y allez pas. Toutefois, lors de l'exécution d'un conteneur, les variables d'environnement spécifiées dans la commande d'exécution sont disponibles pour le conteneur, mais ne font pas partie de l'image.

Ainsi, dans le fichier Dockerfile, effectuez une configuration n’impliquant pas de données secrètes. Définissez un CMD de quelque chose comme /root/finish.sh. Dans la commande d'exécution, utilisez des variables d'environnement pour envoyer des données secrètes dans le conteneur. finish.sh utilise essentiellement les variables pour terminer les tâches de construction.

Pour faciliter la gestion des données secrètes, placez-les dans un fichier chargé par le menu fixe exécuté avec le commutateur --env-file. Bien sûr, gardez le fichier secret. .gitignore et tel.

Pour moi, finish.sh exécute un programme Python. Il vérifie qu'il n'a pas été exécuté avant, puis termine la configuration (copie du nom de la base de données dans settings.py de Django, par exemple). 

1
Kieran Mathieson

Il y a une nouvelle commande docker [1] pour la gestion des "secrets", mais cela ne fonctionne que pour les grappes d'essaims.

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

[1] https://docs.docker.com/engine/swarm/secrets/

0
José Ibañez

Bien que je sois totalement d’accord, il n’ya pas de solution simple. Il y a toujours un seul point d'échec. Soit le fichier docker, etcd, etc. Apcera a un plan qui ressemble à un sidekick - une double authentification. En d'autres termes, deux conteneurs ne peuvent pas parler sauf s'il existe une règle de configuration Apcera. Dans leur démonstration, uid/pwd était en clair et ne pouvait pas être réutilisé tant que l'administrateur n'avait pas configuré le lien. Cependant, pour que cela fonctionne, il fallait probablement appliquer des correctifs à Docker ou au moins au plugin réseau (le cas échéant). 

0
Richard

La méthodologie de l'application 12-Factor indique que toute configuration doit être stockée dans des variables d'environnement. 

Docker compose peut faire une substitution de variable dans la configuration, de sorte qu’il puisse être utilisé pour passer les mots de passe d’un hôte à un autre. 

0
Bunyk

solution uniquement à l'exécution

docker-compose fournit également une solution en mode non-essaim (depuis la v1.11: Les secrets utilisant des montages liés ). 

Les secrets sont montés sous forme de fichiers ci-dessous /run/secrets/ par docker-compose. Cela résout le problème au moment de l'exécution (exécution du conteneur), mais pas au moment de la construction (construction de l'image), car /run/secrets/ n'est pas monté au moment de la construction. De plus, ce comportement dépend de l'exécution du conteneur avec docker-compose.


Exemple:

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

Pour construire, exécutez:

docker-compose up -d

Lectures complémentaires:

0
Murmel