Table des matières

Exposer le socket Docker via TLS

Préambule

Pour certaines opérations, il peut être utile de pouvoir lancer des commandes Docker à distance. Par exemple, les graphes des services sont construits de manière centralisée en récupérant des informations sur les conteneurs qui tournent, à distance. Une chaîne d’intégration aurait besoin de lancer des commandes à distance.

Pour ce faire, l’idée est d’exposer le socket Docker (qui permet d’effectuer toutes les opérations possibles avec Docker) à l’extérieur.

Attention:

Exposer le socket Docker à l’extérieur revient à donner des accès root à quiconque pourra discuter avec lui. Il est donc essentiel d’utiliser TLS pour le sécuriser proprement.

Pour pouvoir communiquer avec le socket Docker depuis l’extérieur, les éléments suivants sont nécessaires :

Note:

La clé privée est l’équivalent d’une clé privée SSH, qui est plus sûre qu’un mot de passe. Le certificat client est une sorte de carte d’identité du client, et ne peut être émis que par l’instance de Docker accessible à l’extérieur.

Pour ce faire, il faut créer une autorité de certification (CA) côté serveur et générer l’ensemble de ces éléments.

Important:

On crée ces éléments dans /DATA/docker/remote, ils appartiendront à root avec le groupe docker, et seront en u=rw,g=r.

Note:

On a fixé arbitrairement la durée de vie des certificats à un an. Il conviendra donc de les renouveler et de les mettre à jour sur les serveurs et les clients concernés tous les ans.

Lien:

Un tutoriel complet est disponible dans la documentation officielle, nous en reprenons les éléments principaux.

Une bonne pratique est de ne pas ré-utiliser les certificats et clés clientes pour des clients multiples : générez autant de certificats que de clients.

Créer une clé privée pour la CA

C’est la clé la plus importante, puisqu’elle permet de créer les certificats. Si elle est compromise, n’importe qui pourrait créer un certificat client illégitime. C’est pourquoi on la protegera avec un mot de passe.

On génère la clé :

snippet.bash
openssl genrsa -aes256 -out ca-key.pem 4096

Générer la clé avec vaultwarden, avec la nomenclature Tech/Keys/<serveur>/ca-key.pem.

Créer ou renouveller la CA

On crée la CA à partir de la clé privée existante, ca-key.pem, à l’aide de la commande suivante :

snippet.bash
$ openssl req -new -x509 -days 365 -key ca-key.pem -sha256 -out ca.pem

Les informations à remplir sont :

Note:

L’autorité de certification ainsi obtenue permettra de créer des certificats (serveur ou client). Elle n’est jamais utilisée pour chiffrer les communications.

Création du certificat serveur

Ce certificat est spécifié lors du lancement du démon Docker, et a plusieurs rôles :

On commence par créer une nouvelle clé privée pour le certificat serveur :

snippet.bash
$ openssl genrsa -out server-key.pem 4096

On crée une demande de signature du certificat. Attention, on remplace bien le CN par le champ Common Name de la CA, c’est-à-dire l’URL du serveur.

snippet.bash
$ openssl req -subj "/CN=<serveur>.picasoft.net" -sha256 -new -key server-key.pem -out server.csr

Notez que le fichier extfile.cnf contient déjà toutes les informations nécessaires pour autoriser l’accès au socket Docker. S’il n’existe pas, créez le avec les informations suivantes :

extendedKeyUsage = serverAuth
subjectAltName = DNS:<serveur>.picasoft.net,IP:<IP du serveur>,IP:127.0.0.1

Ainsi, ce certificat pourra être utilisé pour valider les authentifications côté serveur. On génère le certificat signé par la CA elle-même.

snippet.bash
openssl x509 -req -days 365 -sha256 -in server.csr -CA ca.pem -CAkey ca-key.pem -CAcreateserial -out server-cert.pem -extfile extfile.cnf

On fait du nettoyage :

snippet.bash
$ rm server.csr

Renouvellement des certificats client

On commence par effacer puis créer à nouveau les dossiers des clients (e.g graphbot, ci) :

Pour chaque client, on crée une nouvelle clé privée:

snippet.bash
$ cd <client>
$ openssl genrsa -out <client>-key.pem 4096

On crée ensuite la demande de signature de certificat :

snippet.bash
$ openssl req -subj '/CN=<client>' -new -key <client>-key.pem -out <client>.csr

Le fichier extfile-client.cnf contient déjà les informations nécessaires pour autoriser l’accès au socket Docker. S’il n’existe pas, créez le avec les informations suivantes :

extendedKeyUsage = clientAuth

Ainsi, le client sera autorisé à s’authentifier. On crée ensuite le certificat client signé.

snippet.bash
$ openssl x509 -req -days 365 -sha256 -in <client>.csr -CA ../ca.pem -CAkey ../ca-key.pem -CAcreateserial -out <client>-cert.pem -extfile ../extfile-client.cnf

On fait du nettoyage :

snippet.bash
$ rm <client>.csr

Renouvelez l’opération pour l’ensemble des clients.

Configurer le démon Docker

Vérifier que le démon Docker est bien configuré pour démarrer avec TLS et utiliser le certificat généré.

Relancer le démon Docker

Avant toute chose, il est indispensable de donner des permissions propres à tout ce qui a été généré :

snippet.bash
cd /DATA/docker/remote
sudo chown -R root:docker .
sudo chmod -R u=rwX,g=rwX .

Il faut relancer le démon Docker avec les nouveaux certificats.

snippet.bash
sudo systemctl restart docker
systemctl status docker

Utilisation des certificats clients

Depuis le serveur concerné, récupérez les fichiers suivants :

Pour faciliter et sécuriser la tâche, on peut mettre tout ça dans un tar puis le chiffrer avec un mot de passe temporaire.

snippet.bash
tar -cvf certs.tar ca.pem <client>
gpg -c certs.tar
rm certs.tar

Depuis notre PC, on récupère le fichier chiffré, puis on l’envoie vers le bon client:

snippet.bash
rsync <user>@<serveur>.picasoft.net:/DATA/docker/remote/certs.tar.gpg /tmp
rsync /tmp/certs.tar.gpg <user>@<client>.picasoft.net:/tmp

On se connecte au client et on déchiffre et extrait le fichier:

snippet.bash
cd /tmp
gpg certs.tar.gpg
tar -xvf certs.tar

On peut vérifier que tout est ok avec la commande suivante:

snippet.bash
docker --tlsverify --tlscacert=/tmp/ca.pem --tlscert=/tmp/client/<client>-cert.pem --tlskey=/tmp/client/<client>-key.pem -H=<serveur>.picasoft.net:2376 version

Si tout se passe bien, vous obtenez la version de Docker. Vérifiez qu’il n’y a aucune erreur.

Note:

Il est nécessaire de mettre à jour les fichiers des services qui l’utilisent : on se référera à leur documentation.