SĂ©curisez les secrets lors de la construction dans Docker Compose

Une traduction de l'article a été préparée avant le début du cours Python Web Developer .




Lorsque vous créez une image Docker, vous pouvez avoir besoin de secrets, tels qu'un mot de passe pour un référentiel de packages privé. Vous ne voulez pas que ce secret se retrouve dans l'image, car alors toute personne ayant accès à l'image aura accès à votre référentiel privé.
Remarque : Si vous pensez «Pourquoi ne pas simplement utiliser des variables d'environnement?», Lesquelles sont utilisées pour les secrets lors de l'exécution lors de la création d'une image. Cet article se concentre sur les secrets de génération utilisés lors de la création d'une image à l'aide d'un fichier Docker.
Les versions plus récentes de Docker conservent des secrets à l'aide du service expérimental BuildKit , et dans Docker Compose 1.25 et versions ultérieures, vous pouvez déjà créer des images à l'aide de BuildKit. Malheureusement, depuis mars 2020, la possibilité de travailler en toute sécurité avec les secrets de Compose est toujours en cours de développement .

Que faire maintenant?

Dans l'article d'aujourd'hui, je vais vous montrer comment vous pouvez utiliser le même Dockerfile pour créer en toute sécurité des images secrètes sans perdre les avantages d'un développement rapide à l'aide de Docker Compose.

Deux options pour utiliser votre dockerfile


Il est très pratique d'utiliser le même Dockerfile pour la production et pour le développement local avec Docker Compose. Habituellement, vous utilisez le Dockerfile avec la fonction de construction de Compose:

version: "3.7"
services:
  yourapp:
    build:
      context: "."	

Ensuite, vous pouvez faire:

$ docker-compose up

Avec cette commande, vous pouvez (ré) assembler l'image puis l'exécuter.
Pour une utilisation en production, vous collectez l'image et l'envoyez avec push :

$ docker build -t myimage .
$ docker push myimage

Et pendant que tout se passe bien. Mais que faire si vous avez besoin d'une version secrète?

Premier essai (dangereux)


Supposons que vous ayez un script qui nécessite une construction secrète, par exemple, pour télécharger un package Python à partir d'un référentiel DevPI privé . Pour plus de simplicité, nous allons simplement dériver le secret avec l'aide use-secret.shde montrer que nous l'avons.

#!/bin/bash
set -euo pipefail

echo "Secret is: $THEPASSWORD"

Vous pouvez simplement transmettre le secret Ă  l'aide des arguments de construction Docker, car ils sont pris en charge partout, y compris dans Docker Compose.
Remarque : Au-delà de la portée de notre discussion, je tiens à dire que l'utilisation de fichiers Docker dans cet article n'est pas la meilleure pratique, cependant, une complexité excessive peut interférer avec la transmission de la signification principale de l'article.
Par conséquent, si vous souhaitez exécuter votre application Python en production avec Docker, voici deux bonnes façons de procéder:


FROM python:3.8-slim-buster
# Using ARG for build secrets is INSECURE!
ARG THEPASSWORD
COPY use_secret.sh .
RUN ./use_secret.sh

Nous pouvons Ă©crire docker-compose.yml, qui sera transmis en secret:

version: "3.7"
services:
  yourapp:
    build:
      context: "."
      args:
        THEPASSWORD: "s3kr!t"

Pour le travail local, vous pouvez exécuter ou créer une image à l'aide de Compose:

$ docker-compose build | grep Secret
Secret is: s3kr!t

Et tout va bien.

Et nous pouvons également assembler l'image à l'aide de Docker, en vue de la déplacer vers le registre d'images:

$ docker build -t myimage --build-arg THEPASSWORD=s3krit . | grep Secret
Secret is: s3krit

Cela n'est pas sûr: ne le faites jamais . Si nous décidons de regarder les couches de l'image, nous verrons le secret qui s'y trouve!

$ docker history myimage
IMAGE               CREATED              CREATED BY                                      SIZE
c224231ec30b        47 seconds ago       |1 THEPASSWORD=s3krit /bin/sh -c ./use_secre…   0B
6aef62acf0db        48 seconds ago       /bin/sh -c #(nop) COPY file:7aa28bbe6595e0d5…   62B
f88b19ca8e65        About a minute ago   /bin/sh -c #(nop)  ARG THEPASSWORD              0B
...

Quiconque accède à cette image reconnaîtra votre mot de passe. Que faire alors?

BuildKit Secrets (solution partielle)


BuildKit est une nouvelle solution (encore expérimentale) pour créer des images Docker, qui, entre autres, ajoute la prise en charge de l'utilisation sûre des secrets lors de l'assemblage . Docker Compose prend en charge BuildKit depuis la version 1.25.

Mais il y a un problème: Docker Compose ne prend toujours pas en charge la fonctionnalité des secrets de BuildKit. Des travaux sont actuellement en cours sur ce sujet, mais à partir de mars 2020, il n'y a pas de solutions toutes faites, sans parler d'une version stable.

Par conséquent, nous allons combiner ces deux approches:

  • Docker Compose continuera d'utiliser des arguments de gĂ©nĂ©ration pour transmettre des secrets;
  • Pour une image de production construite Ă  l'aide de la construction Docker, nous utilisons BuildKit pour transmettre des secrets.

De cette façon, nous pouvons utiliser le même Dockerfile pour travailler localement et en production.
BuildKit fonctionne avec les secrets comme suit: le fichier contenant les secrets est monté dans un répertoire temporaire pendant que la commande RUN est exécutée, par exemple, dans /var/secrets/thepassword. Puisqu'il est monté lors de l'exécution de la commande RUN, il ne sera pas ajouté à l'image finale.

Nous allons modifier le fichier use_secret.shpour vérifier si un tel fichier temporaire existe. S'il existe, il utilise ses paramètres de variable d'environnement $THEPASSWORD. Si le fichier n'existe pas, nous reviendrons sur la variable d'environnement. Autrement dit, il $THEPASSWORDpeut être installé à l'aide de BuildKit ou des arguments de génération:

#!/bin/bash
set -euo pipefail
if [ -f /run/secrets/thepassword ]; then
   export THEPASSWORD=$(cat /run/secrets/thepassword)
fi

echo "Secret is: $THEPASSWORD"

Ensuite, nous modifierons le Dockerfile pour ajouter le BuildKit et monter le secret:

# syntax = docker/dockerfile:1.0-experimental
FROM python:3.8-slim-buster
# Only use the build arg for local development:
ARG THEPASSWORD
COPY use_secret.sh .
# Mount the secret to /run/secrets:
RUN --mount=type=secret,id=thepassword ./use_secret.sh

docker-compose.ymlNous ne modifions pas le fichier :

version: "3.7"
services:
  yourapp:
    build:
      context: "."
      args:
        THEPASSWORD: "s3kr!t"

Vous devez maintenant définir deux variables d'environnement, dont l'une indiquera à Docker que vous devez utiliser BuildKit, la seconde dont Compose a besoin pour utiliser la version CLI de Docker et, par conséquent, BuildKit. Nous écrirons également le secret dans le fichier:

$ export DOCKER_BUILDKIT=1
$ export COMPOSE_DOCKER_CLI_BUILD=1
$ echo 's3krit' > /tmp/mypassword

Avec Compose, nous utilisons les arguments de construction:

$ docker-compose build --progress=plain \
    --no-cache 2>&1 | grep Secret
#12 0.347 Secret is: s3kr!t

Veuillez noter qu'il est --no-cachenécessaire de comprendre que l'image sera vraiment reconstruite si vous exécutez vous-même tout ce qui précède. Dans la vie réelle, ce paramètre peut être omis. 2>&1rediriger stderrvers stdoutpour un fonctionnement correct grep.

Lorsque nous sommes prêts à construire sur la production, nous utilisons la construction Docker avec la fonctionnalité des secrets de BuildKit:

$ docker build --no-cache -t myimage \
    --secret id=thepassword,src=/tmp/mypassword \
    --progress=plain . 2>&1 | grep Secret
#12 0.359 Secret is: s3krit

Est-ce sûr?


Assurons-nous que le secret n'est pas visible:

$ docker history myimage
IMAGE               CREATED             CREATED BY                                      SIZE
a77f3c32b723        25 seconds ago      RUN |1 THEPASSWORD= /bin/sh -c ./use_secret.…   0B
<missing>           25 seconds ago      COPY use_secret.sh . # buildkit                 160B
...

Hourra! Nous avons transmis le secret au même Dockerfile en utilisant Compose et docker build, et dans ce dernier cas, nous n'avons pas révélé le secret de l'assemblage.



En savoir plus sur le cours.



All Articles