Loading search data...

Comment ne pas divulguer ses secrets ?

Y a quelques jours dans un billet je vous rappelais l’importance de la sécurité dans les projets Devops. Une des premières règles est de garder ses secrets bien au chaud et ne pas les divulguer. Parmi ces secrets on trouve les certificats, les mots de passe, les tokens d’api, …

Mais comment ne pas les embarquer dans un container?

Et bien docker, comme podman, ont commencé à y répondre mais partiellement. D’ailleurs pour les kubernetiens tout cela doit leur sembler bien naturel puisque pris en charge. Mais je suis sur qu’ils se sont posé la question pour le build des images.

En aucun cas je ne dois trouver ces secrets dans l’image finale. Si quelqu’un récupère l’image, il pourrait facilement retrouver ces infos. Je suis sur qu’en cherchant dans les images du dockerhub on peut trouver des infos de ce type. D’ailleurs je suis sur que les hackers puisent dedans.

Construire des images ne contenant pas de secrets

Je vais prendre un des besoins que je rencontre souvent. Comment intégrer un un fichier de config contenant des mots de passe d’accès à Nexus (là on stocke le résultat des builds).

Les dernières versions de Docker mettent à disposition un nouveau système de build appelé BuildKit , qui inclut la gestion des secrets, ainsi que le transfert d’authentification de l’agent SSH. Voyons comment l’utiliser la partie des secrets.

Pour activer cette fonctionnalité 2 moyens :

  • export DOCKER_BUILDKIT=1 avant de lancer les commandes de build
  • ajouter au fichier /etc/docker/daemon.json la clé features buildkit. Il faudra redémarrer le service Docker.

Le fichier complet :

{
  "registry-mirrors": [],
  "insecure-registries": [],
  "debug": false,
  "experimental": false,
  "features": {
    "buildkit": true
  }
}

Passons à l’écriture du Dockerfile

FROM python:3.9-slim as builder
RUN useradd -ms /bin/bash user && apt-get update && apt-get install -y --no-install-recommends curl
USER user
RUN --mount=type=secret,id=pipconfig,dst=/home/user/.config/pip/pip.conf,uid=1000,gid=1000 pip install -r requirements

Les habitués auront vite remarqué la présence derrière le RUN la directive mount. La documentation se trouve ici

RUN --mount=type=secret,id=pipconfig,dst=/home/user/.config/pip/pip.conf,uid=1000,gid=1000 ....

On indique simplement que l’on veut monter un volume un fichier avec l'id sur le point de montage dst avec les champs uid et gid pour indiquer qui seront le owner et le groupe de ce fichier. Il existe d’autres options mode par exemple.

Pour lancer le build :

docker build --secret id=pipconfig,src=/etc/pip.conf . -t python:0.5 --progress=plain --no-cache
  • l’option --secret id=pipconfig,src=https://blog.stephane-robert.info/etc/pip.conf permet d’indiquer comment créer les secrets. Ici je créé le secret avec l'id dont la source est le fichier src.
  • l’option --progress=plain permet d’avoir la sortie normale du build et non le condensé que propose buildkit
  • l’option --no-cache permet d’indiquer de ne pas utiliser le cache

Maintenant contrôlons que dans l’image ne se trouve pas les fameux secret :

docker run -it python:0.5 bash

user@7fe851946d90:/$ ls -al /home/user/.config/pip/
total 0
drwxr-xr-x 2 root root  6 Oct 21 15:30 .
drwxr-xr-x 3 root root 17 Oct 21 15:30 ..

Super pas de fichier présent. Maintenant voyons comment lancer un container en intégrant des secrets.

Exécuter des containers en intégrant des secrets

Avec la commande docker

La commande docker possède aussi la directive --mount type=<type>,src=<source>,dst=<dest>[,readonly][,bind-propagation=<propagation] :

  • type peut prendre la valeur bind, volume ou tmpfs.

Un exemple monte le fichier pip.conf dans le répertoire /etc

docker run --mount type=bind,src=/etc/pip.conf,dst=/etc/pip.conf -v $PWD:/src -it artefacts.robert.local/python:0.4 bash

Pour rappel, par défaut les volumes montés via l’option -v sont stocké dans /var/lib/docker/volumes. La directive mount vient en remplacer le contenu si il existe déjà. Si le fichier ou le répertoire n’existe pas il est créé.

Les mounts de type tmpfs permettent de créer des espaces de travail temporaire en mémoire, qui seront donc détruit à l’arrêt du conteneur. Vous imaginez bien qu’ici les performances sont maximales. Bien sur dans ce type on ne spécifie pas de source.

Avec docker-compose

On peut également utiliser la commande docker-compose. Voici pour rappel les commandes pour l’installer.

sudo curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose

Il faut écrire un fichier docker-compose.yml dont voici le contenu :

version: "3.9"
services:
  python:
    image: python:0.4
    secrets:
      - source: pipconfig
        target: /etc/pip.conf
      - source: certificate
        target: /etc/pki/ca-trust/source/anchors/server.crt
    network_mode: bridge
secrets:
  pipconfig:
    file: /etc/pip.conf
  certificate:
    file: /etc/pki/ca-trust/source/anchors/server.crt

Il suffit comme vous pouvez le remarquer, de créer ses secrets dans la catégorie générale du même nom.

Comme pour le build d’indiquer dans le service ou l’utiliser. Si on n’indique pas de target ils se retrouveront dans le répertoire /run/secrets

Vous trouverez la documentation ici

Pour lancer le container il suffit d’utiliser la commande :

docker-compose run --rm python bash

On indique le nom du service à lancer.

docker-compose run --rm python bash

Creating python_python_run ... done
user@ba46e44dc6d8:/$ cat /etc/pip.conf
[global]
index =  https://python:xxxxx@artefacts.robert.local/repository/pypi-all/pypi
index-url = https://python:xxxxx@artefacts.robert.local/repository/pypi-all/simple/
timeout = 10
trusted-host = artefacts.robert.local

Comment l’intégrer le build dans un pipeline Gitlab

C’est assez simple il suffit de créer des variables dans les settings CI/CD sous la forme de fichier comme dans la copie d’écran ci-dessous :

docker secrets gitlab

Dans le script CI il suffit de récupérer le fichier et de le stocker dans un fichier.

cat "$mon-secret" > "$(pwd)/mon-secret"
docker build --secret id=pipconfig,src=$(pwd)/mon-secret . -t python:0.5 --progress=plain --no-cache

Et voila le tour est joué. Vos SECRETS sont bien au chaud.

Mots clés :

devops docker tutorials

Si vous avez apprécié cet article de blog, vous pouvez m'encourager à produire plus de contenu en m'offrant un café sur Ko-Fi. Vous pouvez aussi passer votre prochaine commande sur amazon, sans que cela ne nous coûte plus cher, via ce lien. Je vous remercie de votre soutien