Docker - Pour que vos secrets le restent
Publié le : 21 octobre 2021 | Mis à jour le : 22 janvier 2023Y 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 sûr 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
sûr qu’en cherchant dans les images du dockerhub
on peut trouver des infos de
ce type. D’ailleurs je suis sûr que les hackers puisent dedans. Un billet
intéressant sur le
sujet
Construire des images ne contenant pas de secrets
Je vais prendre un des besoins que je rencontre souvent. Comment intégrer 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ée le secret avec l'id
dont la source est le fichiersrc
. - 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 s’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 sûr, 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 :
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 voilà le tour est joué. Vos SECRETS sont bien au chaud.