Table des matières

2023/03/20 (atelier) : Ansible

Présences :

Météo

Moment informel durant lequel on exprime en peu de mots comment on se sent et si on a une attente forte pour la réunion. Ce n'est pas un moment de discussion mais d'expression individuelle et ce n'est pas obligatoire 🙂

Attente(s) forte(s)

Si l'une ou l'autre personne exprime une attente forte, merci de vous en occuper en priorité ou de la noter dans le hub ou dans un point approprié.

Fin: 17h

Secrets

Les secrets sont des mots de passes, des identifiants, mais ça peut aussi être des données sensibles. C'est pourquoi on parle de secret et pas uniquement de mots de passe.

Qu'est qu'un vault ?

Un vault signifie “coffre fort” en Anglais. On va stocker les données dans un coffre. En informatique, c'est un conteneur chiffré. Il y a des vault sous Linux qui permettent par exemple de chiffrer tout un dossier.

Dans ansible, cela se représente comme un fichier de variables mais chiffré.

Par exemple:

$ANSIBLE_VAULT;1.1;AES256
34373066383437646132363336313664313232626234313736653361343034653737336166333934
3739376237366164343736396663636534373234386261330a653639626235326534623362326231
65303864366238333833663335616330343433353539646634383561366565303432663232373336
3365626239346363610a343065636539613164613735393037333431613164363134343864313234
30303965306133646235316631646330366335653639613031666562333130356532636335303032
36656465343237373764323763313530306266363464643837333639336138616566626363643731
61396462363733633263633532366635616365333931643263636332316565653830306262636533
33306435346463383639356666336561353736366363363533646464386634346137353266613564
33663065623930356138386466653536313334643665326133346632653463613630613137623737
36363739323537313265386630663432386166623263303635383438656264363161336465363731
31353563623164626566613631376436646164663564316539613933383330663164613931633336
62343261343464323436663535333331366532306435353539613161326263353765346436646633
6361

On peut aussi définir un vault au niveau d'une variable ansible. Par exemple, pour le rôle let's encrypt :

snippet.yaml
letsencrypt_dns_gandi_api_key: !vault |
          $ANSIBLE_VAULT;1.1;AES256
          37623065386338343831383566336134303861396663666631656563633730613434633231343336
          3132646565373162613537646538353933363161363036650a343634633932373362336134636139
          34313539353938393164353034653366303664613332333038663266656466323265303130333035
          3430613234383662640a313864386230646137383637343263356236633434356335383335353935
          64623839396433346235383264613534383130386433363931306662663063306665

Dans Ansible, on a en général un fichier qui contient tous les secrets. C'est alors chiffré au niveau d'un fichier et pas par variable. En général, c'est mieux supporté par les logiciels tiers (AWX, les linters, etc).

Chez Neutrinet, on suit en général cela. Pour let's Encrypt, on a besoin d'un vault dans les variables du rôle parce qu'on a besoin de la clé d'API pour tester le rôle dans molécule. C'est un peu plus complexe d'avoir un fichier vault avec molécule, et cela pourrait poser des problèmes lorsque d'autres rôles feront appel au rôle qui contient le fichier vault.

Comment fonctionne le chiffrement des secrets ?

Qui dit chiffrement dit clés de chiffrement. Dans les exemples ci-dessus, c'est l'alogithme AES256 qui est utilisé. La clé de chiffrement se trouve dans un fichier qui est défini dans la config d'Ansible ansible.cfg: ìni vault_password_file = vault.key

On a donc une clé de chiffrement, Ansible sait où elle se trouve et ne fait que l'utiliser pour déchiffrer. Pour l'utilisateurice c'est transparant.

C'est du chiffrement symétrique, donc on a qu'une seule clé pour le chiffrement et le déchiffrement.

Pour plus d'infos, voir la doc https://docs.ansible.com/ansible/latest/vault_guide/index.html

Où placer les secrets ?

On en a déjà un peu parlé. On les stock dans un fichier des variables du playbook ou de l'inventaire. Chez Neutrinet, on les places dans un fichier vault.yml au côté du fichier vars.yml.

Donc ça donne par exemple: inventories/group_vars/all/vault.yml

Utilisation d'ansible-vault

ansible-vault est la commande qui permet de gérer les vault, et donc de chiffrer ou déchiffrer un fichier de variables. ansible-vault peut soit juste regarder dedans, soit le déchiffrer complétement.

Pour utiliser la commande, il faut rester à la racine du repo ansible, car il va aller chercher la clé de chiffrement dans le fichier ansible.cfg

Avec ansible-vault help on peut voir toutes les commandes possibles.

On va d'abord crée un dossier dans les variables de l'inventaire:

mkdir inventories/group_vars/all

Et ensuite on déplace le fichier inventories/group_vars/all.yml vers inventories/group_vars/all/vars.yml. Ainsi on pourra placer le fichier vault à côté du fichier de variables.

On va générer une clé de chiffrement, ça peut n'importe quoi. On la génère avec openssl:

snippet.bash
openssl rand -base64 -out vault.key 48

Openssl a un module rand auquel on peut indiquer la taille en bits. Avec l'option base64, tout est encodé en base64, mais on pourrait aussi avoir un fichier binaire si on le voulait (ansible le supporte sans problème).

Attention aux permissions quand a créé la clé de chiffrement ! Par défaut, elle est accessible en lecture pour tout le monde. Ici on s'en fiche comme c'est un test.

On va rajouter le nom du fichier contenant la clé de chiffrement dans le fichier de config d'Ansible, dans la section defaults :

snippet.ini
vault_password_file = vault.key

Maintenant que tout est prêt, on peut créer notre premier vault:

snippet.bash
ansible-vault create inventories/group_vars/all/vault.yml

Un éditeur s'ouvre. On peut écrire dedans mais par défaut, c'est vi qui est utilisé.

Sous Manjaro, il faut préciser que c'est vim que l'on veut, et pas vi… On peut choisir l'éditeur avec:

snippet.bash
EDITOR=vim ansible-vault create inventories/group_vars/all/vault.yml

On peut mettre cette variable dans notre .bashrc pour ne pas devoir repréciser ceci par la suite.

Il y a une convention pour les variables qui sont des vault dans Ansible. On met un préfixe vault_ dans le nom des variables, cela permet que quand on utilise ces variables, c'est clair pour le lecteur que c'est un secret.

Comme ce n'est rien d'autre qu'un fichier de variables, c'est du YAML, donc on met quelque chose comme:

snippet.yaml
vault_super_secret: neutrinet

Si on fait un cat du fichier créé, le fichier ressemble aux exemples ci-dessus. C'est illisible…

Si on veut le lire, il faut utiliser ansible-vault view :

snippet.bash
EDITOR=vim ansible-vault view inventories/group_vars/all/vault.yml

Si jamais on veut changer le contenu du vault, il suffit d'utiliser la sous-commande edit:

snippet.bash
EDITOR=vim ansible-vault view inventories/group_vars/all/vault.yml

On peut mettre autant de secrets / variables que l'on veut dans le même fichier vault.

Si on veut déchiffrer un fichier vault, il suffit de faire:

snippet.bash
EDITOR=vim ansible-vault decrypt inventories/group_vars/all/vault.yml

On peut faire un cat, et on voit bien que le fichier est désormais en clair.

Enfin, on peut chiffrer un fichier (n'import lequel, même un simple fichier texte), avec la sous-commande encrypt:

snippet.bash
EDITOR=vim ansible-vault encrypt inventories/group_vars/all/vault.yml

On remarque que le résultat est différent du premier chiffrement, même si le contenu n'a pas changé. C'est normal, c'est dû au salt du chiffrement, mais on entrera pas dans le détail ici.

Comment garder la clé de chiffrement secrète ?

Pour l'instant, on a créé une clé de chiffrement, que l'on a mis dans un fichier en clair. Mais ici, on est sur un repo git public, donc comment faire pour la publier sur le repo git sans qu'elle soit accessible à tout un chacun ?

On va utiliser git-secret pour chiffrer la clé sur le repo git, et gpg pour se partager les accès \o/

GPG

Comment créer une clé GPG

On trouve plusieurs tutoriels. Quelques exemples qui sont très complets :

L'idée c'est d'avoir plusieurs clés : une master ou primary, qui permet de créer des sous-clés. C'est exactement le même principe que le CA pour les certificats.

Lors qu'on crée cette clé, on lui donne des autorisations comme celle de chiffrer.

Ajout de la clé GPG de Célo

On a créé une clé GPG pour Célo en suivant le tutoriel de Mike Ross. On l'a publié sur un serveur de clé via la commande

snippet.bash
gpg --send-keys <ID de la clé>

Ensuite, HgO a récupéré la clé via la commande

snippet.bash
gpg --recv-keys <ID de la clé>

Et on accorde une confiance ultime à la clé de Célo:

snippet.bash
$ gpg --edit-key <ID de la clé>
> trust
> 5

Maintenant, il ne reste plus qu'à rajouter la clé avec git-secret.

Pour ce faire, il faut installer git-secret, cf. le site web du logiciel.. qui est down 😞

Bon, en général il y a un package qui existe, sous Manjaro en tout cas il y a un AUR 🙂

Pour rajouter la clé de Célo, il faut faire:

git-secret tell <email de la clé de Célo>

On voit que git-secret a modifié le dossier .gitsecret en rajoutant la clé publique de Célo.

De son côté, Célo récupère le repo git une fois que les changements sont mergés.

snippet.bash
git pull

Ensuite, on fait

snippet.bash
git-secret reveal

Mais cela ne marche pas… À suivre Du coup Célo a récupéré le fichier contenant la clé de chiffrement des vaults directement sur une clé USB. Une fois copié dans le projet Ansible, il faut lui donner les bonnes permissions avec :

chmod 0640 vault.key   

TODO: Comprendre pourquoi git-secret n'aime pas Célo

Résumé

On a un fichier vault.key.secret qui est chiffré avec la clé GPG publique de chaque participant. Ce fichier est envoyé sur le repo git, et est donc accessible publiquement. Mais comme ce fichier est chiffré, ce n'est pas un problème.

Ensuite, chaque participant déchiffre localement le fichier vault.key.secret. On obtient ainsi la clé de chiffrement dans vault.key.

Enfin, ansible utilise vault.key pour déchiffrer ses vaults.

Playbook Mobilizon

Avant de commencer, on active le virtual env de python:

snippet.bash
source .venv/bin/activate

On met à jour les dépendences via

snippet.bash
pip install -U -r requirements.txt

On met aussi à jour les plugins de vagrant:

vagrant plugin update

On récupère les derniers changements qui ont été fait sur la branche main:

git pull origin main

Review du playbook

On a mis certaines valeurs dans des variables.

Test du playbook

On lance le playbook converge de molecule:

snippet.bash
molecule converge

On remarque que pour l'extension postgis pour PostgreSQL qui est nécessaire à Mobilizon, il faut installer le package suivant:

postgresql-13-postgis

Cependant, cela doit être installé sur chaque serveur postgresql quand on est en production, et sur la VM de molecule quand on est en local. Donc pour ça, on utilise l'option delegate_to pour dire à molecule d'exécuter la tâche sur le bon serveur.

Ensuite, on active les extensions PostgreSQL:

snippet.yaml
- name: Ajout des extensions nécessaires à postgresql
  community.postgresql.postgresql_ext:
    name: "{{ extensions }}"
    db: "{{ mobilizon_owner }}"
  loop: 
    - postgis
    - pg_trgm
    - unaccent
  loop_control:
    loop_var: extensions
  become_user: postgres
  delegate_to: "{{ postgresql_patroni_primary_host | default(inventory_hostname) }}"

On rajoute une étape pour créer / migrer la base de données de Mobilizon.

On doit encore rajouter des handlers pour dire à ansible de redémarrer Mobilizon lorsque sa config change ou lorsque la base de données.

Par contre, le playbook n'est pas idempotent : d'une part il télécharge la même version de Mobilizon à chaque fois qu'on lance le playbook, et la tâche apparaît comme modifiée… D'autre part, la migration de la db ne devrait s'exécuter que lorsqu'on met à jour ou qu'on installe Mobilizon pour la première fois.

Lors du téléchargement, on dit au module unarchive de ne pas télécharger Mobilizon si le binaire bin/mobilizon existe déjà.

TODO: Déclencher la migration de la db uniquement lorsque la version de Mobilizon a changé TODO: Installer la dépendence postgresql pour l'extension postgis. Voir le rôle postgresdb pour les delegateto TODO: Voir si avoir un lien symbolique serait pertinent TODO: Tester le redémarrage de la VM

Monitoring

Backups

HAProxy

Prochaine réunion

Prochain atelier Ansible : 24/04

Review du playbook Mobilizon et préparation pour la migration

Lieu : Chez Célo (Crainhem)

Météo de fin

Moment informel durant lequel on exprime en peu de mots comment, à titre personnel, la réunion a été vécue que ce soit positif ou négatif. Si une ou plusieurs tension est née durant la réunion, il est peut-être nécessaire d'envisager l'une ou l'autre réunion pour y remédier.