Réinstallation de mon environnement de gestion des mots de passe sous MacOS

Dans le cadre de mon emploi, j’ai pu procéder il y a peu à un changement de mon ordinateur car je commençais à m’approcher dangereusement des limites de ses capacités de stockage. Malgré une analyse du contenu du disque dur, difficile de trouver plus d’une dizaine de giga octets de place, même après nettoyage des anciennes versions de certains logiciels (versions restées sur le disque après mise à jour). Bref, qui dit changement de matériel, dit réinstallation de mon environnement de développement et une occasion à ne pas manquer de prendre quelques notes sur les étapes et autres réglages incontournables à ne pas oublier.

Avant de préciser les étapes d’installation, quelques mots sur la manière dont je gère mes mots de passe s’imposent.

Pour la gestion des mots de passe, j’utilise pass, petit utilitaire en ligne de commande, où chaque mot de passe est stocké dans un fichier chiffré sur le disque. La sauvegarde et la synchronisation sont réalisées via git. La clé de chiffrement est stockée sur un support externe de type « smartcard », une YubiKey en l’occurrence. Après maintenant trois ans d’utilisation quotidienne, le système a fait ses preuves et me convient parfaitement. Pour plus de détails, se référer aux articles de la catégorie Crypto autour de novembre 2018.

Récapitulons les éléments nécessaires:

  • gnupg.
  • pinentry, pour la saisie du mot passe protégeant la YubiKey.
  • Une YubiKey.
  • pass.
  • browserpass, pour une utilisation simplifiée dans les navigateurs.

Première étape, installer les briques logicielles nécessaires en utilisant brew.

brew install libyubikey yubikey-personalization gnupg pinentry pinentry-mac gpg-suite-pinentry pass amar1729/formulae/browserpass

Je n’entre pas dans les détails de l’étape intermédiaire de déploiement des fichiers de configuration de mon dossier dotfiles, celle-ci étant décrite dans l’article dotfiles, git et rcm. Mentionnons tout de même que ce déploiement permet la configuration de gnupg et de la variable d’environnement indiquant le chemin vers le dossier des mots de passe à pass.

Passons à la suite.

Lors de mes premiers tests, j’obtiens l’erreur suivante: gpg: WARNING: unsafe permissions on homedir '/home/path/to/user/.gnupg'. Problème de permission sur le répertoire de configuration .gnupg, une petite recherche concernant l’erreur, me donne un gist qui propose la solution ci-dessous:

chown -R $(whoami) ~/.gnupg/
# Set 600 for files
find ~/.gnupg -type f -exec chmod 600 {} \;
# Set 700 for directories
find ~/.gnupg -type d -exec chmod 700 {} \;

Je passe ensuite à la configuration de l’extension de navigateur browserpass sur les deux navigateurs que j’utilise: Firefox et Brave. Une fois l’extension installée, il faut déployer ce qui permettra à celle-ci de dialoguer en local avec pass. Ces commandes, ou une version similaire, sont rappelées à l’installation de browserpass via brew et je conseille vivement de faire une petite relecture du Readme du projet sur GitHub pour se remettre en tête la procédure.

PREFIX='/usr/local/opt/browserpass' make hosts-firefox-user -f '/usr/local/opt/browserpass/lib/browserpass/Makefile'

PREFIX='/usr/local/opt/browserpass' make hosts-brave-user -f '/usr/local/opt/browserpass/lib/browserpass/Makefile'

Je termine en configurant au niveau de l’extension le chemin vers le répertoire des mots de passe, celle-ci n’arrivant pas à utiliser la variable d’environnement dédiée et pourtant parfaitement accessible dans un terminal.

Je pensais en avoir terminé après cette opération, mais mes mots de passe restaient inaccessibles car pass ne parvenait pas à trouver les informations de clef nécessaires au déchiffrement. Après un test rapide de l’état de ma YubiKey avec gpg --card-status pour m’assurer que celle-ci était bien lisible et reconnue, je me suis souvenue qu’il me fallait importer ma clef publique. Après transfert du fichier la contenant, j’ai donc procédé à l’import via gpg --import < publickey.txt.

Nouveau test. C’est mieux, mais le programme se plaint de ne pas savoir quelle confiance accorder à la clef que je viens d’importer et limite donc grandement son utilisation. Pas de problème ! Accordons à cette clef une confiance absolue.

gpg --edit-keys <email_address> 
gpg> trust
Your decision? 5
Do you really want to set this key to ultimate trust? (y/N) y
gpg> quit

A l’issue de ces étapes de configuration, une nouvelle tentative d’accès à l’un de mes mots de passe se traduit cette fois par une récupération réussie de celui-ci.

La réinstallation de mon environnement de gestion des mots de passe sous MacOS s’est donc déroulée sans trop de difficulté et dans un temps plus que raisonnable, puisque je ne crois pas y avoir passé plus d’une heure. Il est toujours agréable de ne pas rencontrer trop d’erreurs en réinstallant et en reconfigurant ses outils, et de retrouver son environnement habituel propre, neuf et fonctionnel en peu de temps et sans avoir à y laisser un ou deux points de santé mentale.

Et un jour, qui sait, je disposerais peut-être enfin d’un script de réinstallation pour simplifier encore le processus.

Migration vers Ansible Vault

Je l’avais évoqué plusieurs fois dans quelques articles, j’utilise ansible pour gérer l’installation automatique des services que j’auto-héberge. J’étais jusqu’à présent resté dans une gestion simple des mots de passe liés aux services (comprendre « exposé en clair dans les fichiers »). Vraiment pas terrible du point de vue sécurité, mais permettant de me concentrer sur la partie (ré-)installation automatique, là où réside le vrai gain de temps. Disposant de quelques jours de congés, je me suis donc attelé à ce sujet longtemps repoussé qu’est la migration des secrets vers le vault ansible.

Un vault ansible, en quelques mots, est un fichier chiffré contenant des pairs clé/valeur permettant de référencer un secret dans un script ansible.

Configuration

Côté implémentation, j’ai choisi de stocker mon vault dans le dossier group_vars/all/ et j’ai commencé en créant deux fichiers all.yml et vault_all.yml. Dans vault_all.yml, je stocke l’ensemble de mes secrets associés à un identifiant, par exemple, le mot de passe secretpassword associé à la clé vault_test_user_password donnera le fichier suivant :

---
vault_test_user_password: secretpassword

Ensuite, dans all.yml, je référence la variable du vault et l’expose dans une nouvelle variable. Cette étape n’est pas forcément nécessaire, il est tout à fait possible d’utiliser directement l’identifiant présent dans le vault. L’intérêt de cette méthode quelque peu répétitive au moment de la mise en place, réside dans le fait que l’on dispose d’un inventaire des variables stockées dans notre fichier vault, sans avoir besoin de déchiffrer le fichier vault pour parcourir son contenu. Voici donc, en reprenant l’exemple ci-dessus, le contenu de notre fichier de référence :

---
test_user_password: "{{ vault_test_user_password }}"

Maintenant que je dispose de mon dictionnaire de secrets, je peux passer à l’opération de chiffrement de ce dernier. Par défaut, ansible demandera le mot de passe à utiliser à chaque opération de chiffrement/déchiffrement du fichier, ce qui se révèle vite rébarbatif. Heureusement, il est possible de créer un fichier .vault_pass pour y stocker le mot de passe du vault. Évidemment, on prendra soin de l’ajouter à notre .gitignore, afin de ne pas commit cette information dans notre dépôt git. Dernière étape, référencer l’emplacement du mot de passe dans la configuration ansible, soit dans ansible.cfg, par ajout de la ligne :

[defaults]
vault_password_file = .vault_pass

Maintenant que tout est prêt, il convient de chiffrer le fichier vault. Pour effectuer cette opération, on utilisera la commande :

ansible-vault encrypt group_vars/all/vault_all.yml

Le fichier vault étant désormais chiffré, l’édition s’effectuera désormais avec :

ansible-vault edit group_vars/all/vault_all.yml

Parmi les autres opérations de la commande ansible-vault, on notera en particulier decrypt, view et rekey.

Utilisation

Maintenant que tout est configuré, je peux donc remplacer les références directes au mot de passe présent dans mes playbooks, par les nouvelles variables créées. Toujours avec l’exemple précédent, on passera de l’extrait de playbook suivant :

password: secretpassword

au nouveau contenu « sécurisé »:

password: "{{ test_user_password }}"

Il ne reste plus qu’à déclencher l’exécution de l’un des playbooks afin de vérifier que tout a été configuré correctement. Je pourrais m’arrêter là; les secrets de mes playbooks sont maintenant chiffrés dans un fichier dédié, tout va pour le mieux, mais un dernier point de faiblesse subsiste, le mot de passe du vault stocké en clair dans notre fichier .vault_pass. Évidemment, si un attaquant devait mettre la main sur ce fichier, il y a fort à parier que ce serait le cadet de mes soucis, mais voyons tout de même si je peux améliorer les choses.

Sécurisation du mot de passe Vault

En parcourant la documentation ansible liée au concept de vault, j’ai découvert que le paramètre de configuration vault_password_file est susceptible de prendre un fichier de script exécutable en entrée. Seule condition, le script doit renvoyer le mot de passe à utiliser. Étant donné que j’utilise déjà password-store en ligne de commande pour la gestion de mes mots de passe, j’y ai vu une occasion parfaite d’augmenter encore la sécurité en stockant le mot de passe du vault dans une entrée de mon password-store. Quelques recherches plus tard, j’obtiens donc le script suivant; script chargé de retourner le contenu de l’entrée ansible-vault.

#!/bin/bash

###################################
## Get password from password store
# Inspired by https://github.com/paulRbr/ansible-makefile/blob/master/pass.sh
###################################

if (command -v pass >/dev/null 2>&1)
then
    existingVault=$(pass "ansible-vault" || true)

    if [ -n "${existingVault}" ]
    then
        >&2 echo "Using passphrase found at 'ansible-vault' in your password store."
        echo "${existingVault}"
    else
        >&2 echo "No passphrase found at 'ansible-vault' in your password store."
        exit 0
    fi
fi

Ma configuration ansible devient donc (Ne pas oublier de rendre le fichier de script exécutable):

[defaults]
vault_password_file = ./get-vault-pass.sh

Autres améliorations

Il est possible d’avoir plusieurs vaults dans un projet ansible. Dans l’exemple précédent, toutes les entrées du vault sont partagées avec l’ensemble des playbooks, du fait d’appartenir au groupe all. Pour simplifier l’organisation, j’ai dans mon cas déplacé tous les secrets liés à unicoda et à son playbook de déploiement dans le dossier group_vars/unicoda/ et son vault dédié. De la même façon, on peut alors envisager d’améliorer le script pour utiliser un mot de passe différent pour chaque vault, chacun des mots de passe étant alors stocké de façon chiffrée dans password-store.

Par ailleurs, j’ai découvert pendant la mise en place de vault, qu’il existe un plugin ansible maintenu par la communauté et qui permet d’aller chercher directement le contenu d’un mot de passe dans password-store. Je n’ai pas poussé plus avant l’expérimentation, mais l’utilisation de ce plugin pourrait être une alternative valable à l’utilisation de vault.

Conclusion

Grâce à cette dernière amélioration, mes secrets ansible sont désormais stockés en lieu sûr et ne sont plus accessible au premier venu. C’est un élément de sécurité que j’encourage à mettre en place immédiatement, dès que le premier secret apparaît dans le dépôt de code.

Sources

pass comme gestionnaire de mot de passe

Cela fait maintenant plusieurs années que j’utilise un gestionnaire de mot de passe pour retenir à ma place les informations d’accès aux différents services que j’utilise. J’avais jusqu’à présent choisi d’utiliser Keepass, en particulier pour ces fonctions de synchroniser via WebDAV et l’existence de ses nombreuses variantes qui permettent une utilisation sur GNU/Linux, Windows, Mac et Android sans trop de difficultés. Très récemment, j’ai décidé de changer de gestionnaire et de tester pass.

Quelques mots sur pass. Le programme de base prend la forme d’une simple ligne de commande. Chaque entrée consiste en un fichier dont la première ligne contient le mot de passe. On peut ensuite stocker diverses informations sur les lignes suivantes, comme url, username, clés d’API, etc. Tous les fichiers sont chiffrés par clé gpg. Lorsqu’on accède à l’un des fichiers de mot de passe, seul ce fichier sera déchiffré et non l’ensemble de la base comme c’est en général le cas avec les autres gestionnaires. La synchronisation est assurée par git, ce qui permet de bénéficier de l’historique du dépôt qui constituera notre base de référence de mot de passe.

Continuer la lecture de « pass comme gestionnaire de mot de passe »