Ansible Vault : Gérer vos Secrets en Toute Sécurité

Sécurisez vos secrets avec Ansible Vault. Chiffrement de fichiers et variables, vault password file, multi-vault IDs, intégration CI/CD et bonnes pratiques de sécurité.

Introduction : Pourquoi Chiffrer vos Secrets ?

L'automatisation avec Ansible implique inévitablement la manipulation de données sensibles : mots de passe de bases de données, clés API, certificats SSL, tokens d'authentification, clés SSH privées. Ces secrets sont nécessaires pour que vos playbooks fonctionnent, mais les stocker en clair dans vos fichiers YAML est une faille de sécurité majeure.

Imaginez la situation suivante : votre fichier group_vars/all.yml contient le mot de passe root de votre base de données de production. Ce fichier est versionné dans Git. Toute personne ayant accès au dépôt — développeurs, stagiaires, prestataires — peut lire ce mot de passe. Pire encore, si le dépôt est public ou si une fuite se produit, vos secrets sont exposés au monde entier.

Architecture en un coup d'œil

Diagramme - Ansible Vault : Gérer vos Secrets en Toute Sécurité

Ansible Vault résout ce problème en fournissant un mécanisme de chiffrement intégré directement dans Ansible. Il permet de chiffrer des fichiers entiers ou des variables individuelles avec l'algorithme AES-256, un standard de chiffrement militaire. Les fichiers chiffrés peuvent être versionnés dans Git en toute sécurité : sans le mot de passe Vault, leur contenu est illisible.

Dans cet article, nous allons explorer en profondeur toutes les fonctionnalités d'Ansible Vault : création et édition de fichiers chiffrés, chiffrement de variables individuelles, gestion multi-vault, intégration CI/CD, et bonnes pratiques de sécurité. Vous apprendrez à protéger vos secrets sans compromettre l'ergonomie de votre workflow Ansible.

Les Commandes Fondamentales d'Ansible Vault

Ansible Vault s'utilise via la commande ansible-vault qui propose plusieurs sous-commandes. Voyons chacune d'entre elles en détail.

ansible-vault create : Créer un fichier chiffré

La commande create crée un nouveau fichier directement chiffré. Elle ouvre votre éditeur de texte par défaut (défini par la variable d'environnement $EDITOR) pour que vous saisissiez le contenu, puis le chiffre automatiquement à la sauvegarde :

# Créer un nouveau fichier chiffré
ansible-vault create group_vars/production/vault.yml

# Ansible vous demandera de saisir un mot de passe Vault :
# New Vault password:
# Confirm New Vault password:

# Votre éditeur s'ouvre. Saisissez le contenu :
# vault_db_password: "S3cur3P@ssw0rd!"
# vault_api_key: "ak_live_xxxxxxxxxxx"
# vault_ssl_passphrase: "M0nCert1f1cat!"

# Sauvegardez et quittez l'éditeur. Le fichier est automatiquement chiffré.

Après la création, si vous ouvrez le fichier avec cat, vous verrez quelque chose comme ceci :

cat group_vars/production/vault.yml

# Résultat :
# $ANSIBLE_VAULT;1.1;AES256
# 33363965326261303234313966633033643033326439656430616531636561656463
# 64373734393633383163333739303835326238386136366264643566623834353032
# 6533643331363039620a303234353663366636643039363933363535373264623737
# ...

Le contenu est entièrement chiffré en AES-256. Sans le mot de passe Vault, il est impossible de lire les données.

ansible-vault edit : Modifier un fichier chiffré

La commande edit déchiffre temporairement le fichier en mémoire, ouvre votre éditeur, puis re-chiffre le fichier à la sauvegarde :

# Modifier un fichier chiffré existant
ansible-vault edit group_vars/production/vault.yml

# Vault password: (saisissez votre mot de passe)
# L'éditeur s'ouvre avec le contenu déchiffré
# Modifiez, sauvegardez, quittez — le fichier est re-chiffré

Le fichier déchiffré n'est jamais écrit sur le disque en clair. Le déchiffrement se fait en mémoire, ce qui garantit qu'aucune trace en clair ne reste sur le système de fichiers.

ansible-vault view : Afficher un fichier chiffré

Pour simplement consulter le contenu d'un fichier chiffré sans le modifier :

# Afficher le contenu déchiffré dans le terminal
ansible-vault view group_vars/production/vault.yml

# Vault password:
# vault_db_password: "S3cur3P@ssw0rd!"
# vault_api_key: "ak_live_xxxxxxxxxxx"
# vault_ssl_passphrase: "M0nCert1f1cat!"

ansible-vault encrypt : Chiffrer un fichier existant

Si vous avez un fichier en clair que vous souhaitez chiffrer a posteriori :

# Chiffrer un fichier existant en clair
ansible-vault encrypt secrets.yml

# New Vault password:
# Confirm New Vault password:
# Encryption successful

# Vous pouvez aussi chiffrer plusieurs fichiers en une seule commande
ansible-vault encrypt fichier1.yml fichier2.yml fichier3.yml
Attention : après le chiffrement, assurez-vous que le fichier en clair n'est plus accessible. Si le fichier était déjà versionné en clair dans Git, l'historique contient toujours la version non chiffrée. Nous verrons plus loin comment gérer cette situation.

ansible-vault decrypt : Déchiffrer un fichier

L'opération inverse du chiffrement :

# Déchiffrer un fichier (le remplace par la version en clair)
ansible-vault decrypt secrets.yml

# Vault password:
# Decryption successful

# Le fichier est maintenant en clair sur le disque
# ATTENTION : ne commitez jamais un fichier déchiffré !

Cette commande est utile pour des opérations de maintenance, mais doit être utilisée avec précaution. Ne laissez jamais un fichier déchiffré traîner sur le disque.

ansible-vault encrypt_string : Chiffrer une variable individuelle

C'est l'une des fonctionnalités les plus puissantes de Vault. Au lieu de chiffrer un fichier entier, vous pouvez chiffrer une seule variable et l'intégrer directement dans un fichier YAML par ailleurs lisible :

# Chiffrer une chaîne avec un nom de variable
ansible-vault encrypt_string 'S3cur3P@ssw0rd!' --name 'vault_db_password'

# Vault password:
# Résultat :
# vault_db_password: !vault |
#   $ANSIBLE_VAULT;1.1;AES256
#   61326634653738373163356364373961653931363...
#   3365653230383963380a623435343933363533366...
#   6432326265636664640a313732323965376565626...

# Chiffrer depuis stdin (utile pour les mots de passe complexes)
echo -n 'MonMotDePasse' | ansible-vault encrypt_string --stdin-name 'vault_password'

# Chiffrer en mode interactif
ansible-vault encrypt_string --ask-vault-pass --name 'vault_secret'
# Saisissez la valeur puis Ctrl+D pour terminer

Vous pouvez ensuite copier-coller la sortie directement dans votre fichier de variables :

# group_vars/all.yml — Mélange de variables en clair et chiffrées
---
# Variables publiques (lisibles par tous)
app_name: mon_application
app_port: 3000
app_environment: production
db_host: db.example.com
db_name: app_production
db_user: app_user

# Variables sensibles (chiffrées individuellement)
vault_db_password: !vault |
  $ANSIBLE_VAULT;1.1;AES256
  61326634653738373163356364373961653931363032666232333232363564366262
  3365653230383963380a623435343933363533366336363738623834623065643539
  6432326265636664640a313732323965376565626233623538633539386131333761
  3163

vault_api_key: !vault |
  $ANSIBLE_VAULT;1.1;AES256
  34373565623430376136623462353832323335353530356165346333633335636163
  6231353830306166350a333735656362613431393833373431613338333333393132
  3834

Cette approche est extrêmement pratique car elle permet de voir la structure du fichier et les noms des variables sans pouvoir lire les valeurs sensibles.

ansible-vault rekey : Changer le mot de passe Vault

Pour changer le mot de passe de chiffrement d'un ou plusieurs fichiers :

# Changer le mot de passe d'un fichier chiffré
ansible-vault rekey secrets.yml

# Vault password: (ancien mot de passe)
# New Vault password: (nouveau mot de passe)
# Confirm New Vault password:
# Rekey successful

# Rechiffrer plusieurs fichiers en même temps
ansible-vault rekey group_vars/production/vault.yml group_vars/staging/vault.yml

Utiliser un Fichier de Mot de Passe Vault

Saisir le mot de passe Vault manuellement à chaque exécution est fastidieux et incompatible avec l'automatisation CI/CD. Ansible permet d'utiliser un fichier de mot de passe pour automatiser le déchiffrement.

Créer un fichier de mot de passe

# Créer le fichier de mot de passe
echo 'MonMotDePasseVaultTresLong2024!' > ~/.vault_password

# CRUCIAL : restreindre les permissions
chmod 600 ~/.vault_password

# Vérifier les permissions
ls -la ~/.vault_password
# -rw------- 1 user user 32 Mar  7 10:00 /home/user/.vault_password

Utiliser le fichier avec --vault-password-file

# Exécuter un playbook sans saisie interactive
ansible-playbook playbook.yml --vault-password-file ~/.vault_password

# Éditer un fichier chiffré sans saisie interactive
ansible-vault edit secrets.yml --vault-password-file ~/.vault_password

# Chiffrer un fichier sans saisie interactive
ansible-vault encrypt fichier.yml --vault-password-file ~/.vault_password

Configurer le fichier de mot de passe par défaut

Pour éviter de spécifier --vault-password-file à chaque commande, vous pouvez le configurer dans ansible.cfg :

# ansible.cfg
[defaults]
vault_password_file = ~/.vault_password

Avec cette configuration, toutes les commandes Ansible utiliseront automatiquement ce fichier pour le déchiffrement.

Utiliser un script comme source de mot de passe

Ansible permet aussi d'utiliser un script exécutable comme source de mot de passe. Le script doit afficher le mot de passe sur stdout. C'est très utile pour récupérer le mot de passe depuis un gestionnaire de secrets externe :

#!/bin/bash
# ~/.vault_password_script.sh
# Récupérer le mot de passe depuis un gestionnaire de secrets

# Option 1 : Depuis une variable d'environnement
echo "${ANSIBLE_VAULT_PASSWORD}"

# Option 2 : Depuis le trousseau macOS
# security find-generic-password -a "ansible-vault" -s "vault-password" -w

# Option 3 : Depuis HashiCorp Vault
# vault kv get -field=password secret/ansible/vault

# Option 4 : Depuis AWS Secrets Manager
# aws secretsmanager get-secret-value --secret-id ansible-vault --query SecretString --output text
# Rendre le script exécutable
chmod 700 ~/.vault_password_script.sh

# Utiliser le script
ansible-playbook playbook.yml --vault-password-file ~/.vault_password_script.sh

# Ou dans ansible.cfg
# vault_password_file = ~/.vault_password_script.sh

Intégration dans les Playbooks

Utiliser des fichiers de variables chiffrés

La méthode la plus courante consiste à chiffrer des fichiers de variables entiers et à les inclure dans vos playbooks avec vars_files :

# playbook.yml
---
- name: Déployer l'application
  hosts: webservers
  become: true
  vars_files:
    - vars/common.yml        # Variables en clair
    - vars/vault.yml          # Variables chiffrées avec Vault

  tasks:
    - name: Configurer la base de données
      ansible.builtin.template:
        src: database.conf.j2
        dest: /etc/app/database.conf
        owner: app
        group: app
        mode: "0600"

    - name: Configurer l'application
      ansible.builtin.template:
        src: app.conf.j2
        dest: /etc/app/app.conf
        owner: app
        group: app
        mode: "0644"
      notify: Redémarrer application
# vars/common.yml (en clair)
---
app_name: mon_application
app_port: 3000
db_host: db.production.local
db_name: app_production
db_user: app_user
# vars/vault.yml (chiffré avec ansible-vault encrypt)
---
vault_db_password: "S3cur3P@ssw0rd!"
vault_api_key: "ak_live_xxxxxxxxxxxxxxxx"
vault_smtp_password: "smtp_p@ssw0rd"
vault_ssl_key_passphrase: "c3rt_p@ss"
# Exécuter le playbook
ansible-playbook playbook.yml --ask-vault-pass

# Ou avec un fichier de mot de passe
ansible-playbook playbook.yml --vault-password-file ~/.vault_password

Ansible détecte automatiquement que vars/vault.yml est chiffré et le déchiffre à la volée pendant l'exécution. Aucune modification du playbook n'est nécessaire.

Utiliser des variables inline chiffrées

Comme nous l'avons vu avec encrypt_string, vous pouvez mélanger variables en clair et variables chiffrées dans le même fichier :

# group_vars/production.yml
---
# Variables publiques
app_environment: production
app_debug: false
app_log_level: warning

# Variables sensibles chiffrées inline
db_password: !vault |
  $ANSIBLE_VAULT;1.1;AES256
  33363965326261303234313966633033643033326439656430616531636561656463
  64373734393633383163333739303835326238386136366264643566623834353032
  6533643331363039620a303234353663366636643039363933363535373264623737

api_secret: !vault |
  $ANSIBLE_VAULT;1.1;AES256
  61326634653738373163356364373961653931363032666232333232363564366262
  3365653230383963380a623435343933363533366336363738623834623065643539

Variables chiffrées dans l'inventaire

Les variables chiffrées fonctionnent aussi dans les fichiers group_vars et host_vars :

# Structure de l'inventaire avec des fichiers Vault
inventory/
├── production/
│   ├── hosts.yml
│   ├── group_vars/
│   │   ├── all/
│   │   │   ├── vars.yml       # Variables en clair
│   │   │   └── vault.yml      # Variables chiffrées
│   │   ├── webservers/
│   │   │   ├── vars.yml
│   │   │   └── vault.yml
│   │   └── databases/
│   │       ├── vars.yml
│   │       └── vault.yml
│   └── host_vars/
│       └── db01.production.local/
│           ├── vars.yml
│           └── vault.yml

La convention de nommer les fichiers chiffrés vault.yml est une bonne pratique. Elle rend immédiatement visible quels fichiers contiennent des secrets.

Multi-Vault IDs : Gérer Plusieurs Mots de Passe

Dans un environnement complexe, vous pourriez avoir besoin de différents mots de passe Vault pour différents environnements ou niveaux de sensibilité. Ansible supporte les Vault IDs pour gérer cette situation.

Concept des Vault IDs

Un Vault ID est un identifiant associé à un mot de passe Vault spécifique. Cela permet de chiffrer différents fichiers avec différents mots de passe et de fournir les bons mots de passe lors de l'exécution.

Chiffrer avec un Vault ID

# Chiffrer un fichier avec le Vault ID "production"
ansible-vault encrypt --vault-id production@prompt secrets_prod.yml

# Chiffrer un fichier avec le Vault ID "staging"
ansible-vault encrypt --vault-id staging@prompt secrets_staging.yml

# Chiffrer avec un Vault ID et un fichier de mot de passe
ansible-vault encrypt --vault-id production@~/.vault_pass_prod secrets_prod.yml
ansible-vault encrypt --vault-id staging@~/.vault_pass_staging secrets_staging.yml

# Chiffrer une variable avec un Vault ID
ansible-vault encrypt_string --vault-id production@prompt 'SecretProd' --name 'db_password'

Le format est --vault-id LABEL@SOURCE où :

  • LABEL est un identifiant libre (production, staging, dev, secrets, etc.).
  • SOURCE peut être prompt (saisie interactive), un chemin de fichier, ou un script.

Exécuter avec plusieurs Vault IDs

# Fournir plusieurs mots de passe Vault lors de l'exécution
ansible-playbook playbook.yml \
  --vault-id production@~/.vault_pass_prod \
  --vault-id staging@~/.vault_pass_staging

# Mélanger fichiers et saisie interactive
ansible-playbook playbook.yml \
  --vault-id production@~/.vault_pass_prod \
  --vault-id dev@prompt

Exemple pratique multi-environnement

# Créer les fichiers de mots de passe par environnement
echo 'ProdVaultPass2024!' > ~/.vault_pass_prod
echo 'StagingVaultPass2024!' > ~/.vault_pass_staging
chmod 600 ~/.vault_pass_prod ~/.vault_pass_staging

# Chiffrer les secrets de production
ansible-vault encrypt \
  --vault-id production@~/.vault_pass_prod \
  inventory/production/group_vars/all/vault.yml

# Chiffrer les secrets de staging
ansible-vault encrypt \
  --vault-id staging@~/.vault_pass_staging \
  inventory/staging/group_vars/all/vault.yml
# inventory/production/group_vars/all/vault.yml (avant chiffrement)
---
vault_db_password: "ProdDbP@ss2024!"
vault_api_key: "ak_prod_xxxxxxxx"
vault_smtp_password: "smtp_prod_p@ss"
# inventory/staging/group_vars/all/vault.yml (avant chiffrement)
---
vault_db_password: "StagingDbPass123"
vault_api_key: "ak_staging_yyyyyyyy"
vault_smtp_password: "smtp_staging_pass"
# Déployer en production (seul le mot de passe production est nécessaire)
ansible-playbook -i inventory/production playbook.yml \
  --vault-id production@~/.vault_pass_prod

# Déployer en staging
ansible-playbook -i inventory/staging playbook.yml \
  --vault-id staging@~/.vault_pass_staging

Bonnes Pratiques de Sécurité

1. Ne jamais commiter de secrets en clair

C'est la règle numéro un, non négociable. Même si vous chiffrez le fichier plus tard, l'historique Git conserve la version en clair. Configurez votre .gitignore pour exclure les fichiers sensibles :

# .gitignore
# Fichiers de mots de passe Vault
.vault_password
.vault_pass_*
*.vault_password

# Fichiers déchiffrés temporaires
*.decrypted
*.dec

# Clés et certificats en clair
*.pem
*.key
*.p12

# Variables d'environnement
.env
.env.*

2. Séparer variables et vault vars

Adoptez la convention de séparer les variables en clair et les variables chiffrées dans des fichiers distincts :

# group_vars/webservers/vars.yml — Variables en clair
---
app_name: mon_application
app_port: 3000
db_host: db.production.local
db_name: app_production
db_user: app_user
db_password: "{{ vault_db_password }}"  # Référence à la variable Vault
api_key: "{{ vault_api_key }}"          # Référence à la variable Vault
# group_vars/webservers/vault.yml — Variables chiffrées
---
vault_db_password: "S3cur3P@ssw0rd!"
vault_api_key: "ak_live_xxxxxxxxxxxxxxxx"

Cette convention offre plusieurs avantages :

  • Le fichier vars.yml est lisible et montre la structure des variables.
  • Le fichier vault.yml contient uniquement les valeurs sensibles.
  • Il est facile de voir quelles variables sont des secrets (celles préfixées par vault_).
  • Lors d'un ansible-vault view, vous voyez uniquement les secrets sans le bruit des variables publiques.

3. Préfixer les variables Vault

Préfixez systématiquement vos variables chiffrées avec vault_. Cela crée une distinction claire et permet de tracer facilement l'utilisation des secrets dans vos playbooks :

# Convention de nommage
vault_db_password: "..."       # Mot de passe BDD
vault_api_key: "..."           # Clé API
vault_ssl_cert_key: "..."      # Clé privée SSL
vault_smtp_password: "..."     # Mot de passe SMTP
vault_ssh_private_key: "..."   # Clé SSH privée

4. Utiliser des mots de passe Vault robustes

Le mot de passe Vault protège tous vos secrets. Il doit être suffisamment fort :

# Générer un mot de passe robuste
openssl rand -base64 48 > ~/.vault_password
chmod 600 ~/.vault_password

# Ou avec pwgen
pwgen -s 64 1 > ~/.vault_password
chmod 600 ~/.vault_password

# Vérifier les permissions
stat -c '%a %U:%G' ~/.vault_password
# 600 user:user

5. Protéger le fichier de mot de passe

# Permissions strictes (lecture/écriture uniquement pour le propriétaire)
chmod 600 ~/.vault_password

# Vérifier que le fichier n'est PAS dans un dépôt Git
git status ~/.vault_password  # Ne doit pas être traqué

# Ajouter à .gitignore global
echo '.vault_password' >> ~/.gitignore_global
git config --global core.excludesfile ~/.gitignore_global

6. Auditer l'utilisation des secrets

Vérifiez régulièrement que vos secrets ne sont pas exposés accidentellement :

# Chercher des mots de passe potentiellement en clair dans le projet
grep -rn "password:" --include="*.yml" --include="*.yaml" . | grep -v vault | grep -v "{{" 

# Chercher des clés API en clair
grep -rn "api_key\|api_secret\|token" --include="*.yml" . | grep -v vault | grep -v "{{"

# Vérifier que tous les fichiers vault sont bien chiffrés
find . -name "vault.yml" -exec head -1 {} \; | grep -v ANSIBLE_VAULT
# Si cette commande retourne quelque chose, un fichier vault n'est pas chiffré !

Intégration CI/CD

L'intégration d'Ansible Vault dans un pipeline CI/CD nécessite de rendre le mot de passe disponible sans intervention humaine, tout en le gardant sécurisé.

Variable d'environnement ANSIBLE_VAULT_PASSWORD_FILE

La variable d'environnement ANSIBLE_VAULT_PASSWORD_FILE permet de spécifier le fichier de mot de passe sans modifier ansible.cfg :

# Définir la variable d'environnement
export ANSIBLE_VAULT_PASSWORD_FILE=~/.vault_password

# Toutes les commandes Ansible utiliseront automatiquement ce fichier
ansible-playbook playbook.yml  # Pas besoin de --ask-vault-pass

Intégration avec GitLab CI

# .gitlab-ci.yml
---
stages:
  - test
  - deploy

variables:
  ANSIBLE_FORCE_COLOR: "true"

.ansible_base:
  image: python:3.11-slim
  before_script:
    - pip install ansible
    # Créer le fichier de mot de passe à partir de la variable CI/CD
    - echo "${VAULT_PASSWORD}" > /tmp/vault_password
    - chmod 600 /tmp/vault_password
    - export ANSIBLE_VAULT_PASSWORD_FILE=/tmp/vault_password
  after_script:
    # Supprimer le fichier de mot de passe après utilisation
    - rm -f /tmp/vault_password

test_playbook:
  extends: .ansible_base
  stage: test
  script:
    - ansible-playbook --check -i inventory/staging playbook.yml
  only:
    - merge_requests

deploy_staging:
  extends: .ansible_base
  stage: deploy
  script:
    - ansible-playbook -i inventory/staging playbook.yml
  only:
    - develop
  environment:
    name: staging

deploy_production:
  extends: .ansible_base
  stage: deploy
  script:
    - ansible-playbook -i inventory/production playbook.yml
  only:
    - main
  when: manual
  environment:
    name: production

La variable VAULT_PASSWORD est configurée dans les CI/CD Variables de GitLab (Settings > CI/CD > Variables) en mode "masked" et "protected".

Intégration avec GitHub Actions

# .github/workflows/deploy.yml
---
name: Deploy with Ansible
on:
  push:
    branches: [main]

jobs:
  deploy:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout du code
        uses: actions/checkout@v4

      - name: Installer Python et Ansible
        run: |
          python -m pip install --upgrade pip
          pip install ansible

      - name: Installer les dépendances Galaxy
        run: |
          ansible-galaxy install -r requirements.yml
          ansible-galaxy collection install -r requirements.yml

      - name: Créer le fichier de mot de passe Vault
        run: |
          echo "${{ secrets.ANSIBLE_VAULT_PASSWORD }}" > /tmp/vault_password
          chmod 600 /tmp/vault_password

      - name: Exécuter le playbook
        env:
          ANSIBLE_VAULT_PASSWORD_FILE: /tmp/vault_password
          ANSIBLE_HOST_KEY_CHECKING: "false"
        run: |
          ansible-playbook -i inventory/production playbook.yml

      - name: Nettoyer le fichier de mot de passe
        if: always()
        run: rm -f /tmp/vault_password

Intégration avec Jenkins

# Jenkinsfile (Pipeline déclaratif)
pipeline {
    agent any

    environment {
        ANSIBLE_VAULT_PASSWORD_FILE = credentials('ansible-vault-password')
    }

    stages {
        stage('Prepare') {
            steps {
                sh 'pip install ansible'
                sh 'ansible-galaxy install -r requirements.yml'
            }
        }

        stage('Test') {
            steps {
                sh 'ansible-playbook --check -i inventory/staging playbook.yml'
            }
        }

        stage('Deploy') {
            when {
                branch 'main'
            }
            steps {
                sh 'ansible-playbook -i inventory/production playbook.yml'
            }
        }
    }

    post {
        always {
            sh 'rm -f /tmp/vault_*'
        }
    }
}

Rotation des Mots de Passe Vault

La rotation régulière des mots de passe Vault est une bonne pratique de sécurité. Voici comment procéder méthodiquement.

Processus de rotation

#!/bin/bash
# rotate_vault_password.sh — Script de rotation du mot de passe Vault

set -euo pipefail

VAULT_FILES=$(find . -name "vault.yml" -type f)
OLD_PASS_FILE=~/.vault_password
NEW_PASS_FILE=~/.vault_password_new

# 1. Générer le nouveau mot de passe
echo "Génération du nouveau mot de passe..."
openssl rand -base64 48 > "${NEW_PASS_FILE}"
chmod 600 "${NEW_PASS_FILE}"

# 2. Rechiffrer tous les fichiers Vault
echo "Rechiffrement des fichiers Vault..."
for vault_file in ${VAULT_FILES}; do
    echo "  Rechiffrement de ${vault_file}..."
    ansible-vault rekey \
        --vault-password-file "${OLD_PASS_FILE}" \
        --new-vault-password-file "${NEW_PASS_FILE}" \
        "${vault_file}"
done

# 3. Remplacer l'ancien mot de passe par le nouveau
echo "Remplacement du fichier de mot de passe..."
mv "${NEW_PASS_FILE}" "${OLD_PASS_FILE}"
chmod 600 "${OLD_PASS_FILE}"

# 4. Mettre à jour la variable CI/CD (manuellement ou via API)
echo ""
echo "IMPORTANT : Mettez à jour la variable VAULT_PASSWORD dans votre CI/CD !"
echo "Nouveau mot de passe :"
cat "${OLD_PASS_FILE}"

echo ""
echo "Rotation terminée avec succès."
# Exécuter le script de rotation
chmod +x rotate_vault_password.sh
./rotate_vault_password.sh

Planification de la rotation

Établissez un calendrier de rotation adapté à votre contexte :

  • Rotation régulière : tous les 3 à 6 mois pour les environnements standards.
  • Rotation immédiate : lorsqu'un membre de l'équipe quitte le projet ou en cas de suspicion de compromission.
  • Rotation après incident : si le fichier de mot de passe a pu être exposé.

Ansible Vault vs HashiCorp Vault

Une confusion fréquente existe entre Ansible Vault et HashiCorp Vault. Ce sont deux outils très différents qui peuvent être complémentaires.

Ansible Vault

  • Type : outil de chiffrement de fichiers intégré à Ansible.
  • Fonction : chiffrer des fichiers YAML ou des variables individuelles avec AES-256.
  • Stockage des secrets : les secrets chiffrés sont stockés dans les fichiers du projet (versionnés dans Git).
  • Gestion des accès : quiconque possède le mot de passe Vault peut déchiffrer tous les secrets.
  • Rotation : manuelle, nécessite de rechiffrer les fichiers.
  • Audit : pas de journal d'accès intégré.
  • Coût : gratuit, inclus dans Ansible.
  • Complexité : très simple à mettre en place.

HashiCorp Vault

  • Type : gestionnaire de secrets centralisé (service à part entière).
  • Fonction : stocker, distribuer et faire tourner des secrets de manière centralisée.
  • Stockage des secrets : les secrets sont stockés dans un backend sécurisé (mémoire, Consul, base de données chiffrée).
  • Gestion des accès : contrôle d'accès fin avec des politiques, authentification multiple (LDAP, tokens, certificats, etc.).
  • Rotation : automatique pour certains types de secrets (credentials de BDD, certificats).
  • Audit : journal d'accès complet (qui a lu quel secret, quand).
  • Coût : gratuit en version open source, payant pour la version Enterprise.
  • Complexité : nécessite un déploiement et une maintenance dédiés.

Quand utiliser quoi ?

Ansible Vault est parfait pour les projets de petite à moyenne taille où les secrets sont peu nombreux et gérés par une équipe restreinte. C'est la solution la plus simple et la plus rapide à mettre en place.
HashiCorp Vault est recommandé pour les organisations qui gèrent des centaines de secrets, qui ont besoin de rotation automatique, de contrôle d'accès fin et de traçabilité complète. C'est un investissement en infrastructure mais qui offre des garanties de sécurité supérieures.

Les utiliser ensemble

Les deux outils ne sont pas mutuellement exclusifs. Une approche hybride courante consiste à utiliser HashiCorp Vault comme source de vérité pour les secrets et Ansible pour les récupérer au moment de l'exécution :

# playbook.yml — Récupérer des secrets depuis HashiCorp Vault
---
- name: Déploiement avec secrets HashiCorp Vault
  hosts: webservers
  become: true

  tasks:
    - name: Lire les secrets depuis HashiCorp Vault
      community.hashi_vault.vault_read:
        url: https://vault.entreprise.com
        path: secret/data/app/production
        auth_method: token
        token: "{{ lookup('env', 'VAULT_TOKEN') }}"
      register: vault_secrets
      delegate_to: localhost
      run_once: true

    - name: Déployer la configuration avec les secrets
      ansible.builtin.template:
        src: app.conf.j2
        dest: /etc/app/app.conf
        owner: app
        mode: "0600"
      vars:
        db_password: "{{ vault_secrets.data.data.db_password }}"
        api_key: "{{ vault_secrets.data.data.api_key }}"

Vous pouvez aussi utiliser le plugin lookup de HashiCorp Vault directement dans vos variables :

# group_vars/all.yml
---
db_password: "{{ lookup('community.hashi_vault.hashi_vault', 'secret/data/app:db_password') }}"
api_key: "{{ lookup('community.hashi_vault.hashi_vault', 'secret/data/app:api_key') }}"

Exemples Complets de Chiffrement et Déchiffrement

Mettons tout en pratique avec un scénario complet de gestion des secrets pour un projet Ansible de production.

Mise en place initiale

# 1. Créer la structure du projet
mkdir -p mon_projet/{inventory/{production,staging}/{group_vars/all,host_vars},playbooks,roles}
cd mon_projet

# 2. Générer un mot de passe Vault robuste
openssl rand -base64 48 > ~/.vault_password_mon_projet
chmod 600 ~/.vault_password_mon_projet

# 3. Configurer ansible.cfg
cat > ansible.cfg << 'EOF'
[defaults]
inventory = inventory/production
roles_path = roles
vault_password_file = ~/.vault_password_mon_projet
host_key_checking = False

[privilege_escalation]
become = True
become_method = sudo
EOF

Créer les fichiers de variables

# 4. Créer les variables en clair pour la production
cat > inventory/production/group_vars/all/vars.yml << 'EOF'
---
# Variables publiques
app_name: mon_application
app_port: 3000
app_environment: production
app_log_level: warning

# Base de données
db_host: db.production.local
db_port: 5432
db_name: app_production
db_user: app_user
db_password: "{{ vault_db_password }}"

# API externe
api_url: https://api.service-externe.com
api_key: "{{ vault_api_key }}"

# Email
smtp_host: smtp.gmail.com
smtp_port: 587
smtp_user: notifications@codeclan.fr
smtp_password: "{{ vault_smtp_password }}"
EOF

# 5. Créer le fichier de secrets
cat > inventory/production/group_vars/all/vault.yml << 'EOF'
---
vault_db_password: "Pr0duct10n_DB_P@ss_2024!"
vault_api_key: "ak_live_7f8a9b2c3d4e5f6g7h8i9j0k"
vault_smtp_password: "xvfb pqrs tuvw xyz1"
vault_ssl_cert_passphrase: "SSL_C3rt_P@ss!"
vault_deploy_token: "glpat-xxxxxxxxxxxxxxxxxxxx"
EOF

# 6. Chiffrer le fichier de secrets
ansible-vault encrypt inventory/production/group_vars/all/vault.yml

# Vérifier que le chiffrement a fonctionné
head -1 inventory/production/group_vars/all/vault.yml
# $ANSIBLE_VAULT;1.1;AES256

Utiliser les secrets dans un playbook

# playbooks/deploy.yml
---
- name: Déployer l'application en production
  hosts: webservers
  become: true

  tasks:
    - name: Créer le répertoire de configuration
      ansible.builtin.file:
        path: /etc/{{ app_name }}
        state: directory
        owner: root
        group: root
        mode: "0755"

    - name: Déployer la configuration de l'application
      ansible.builtin.template:
        src: templates/app.env.j2
        dest: "/etc/{{ app_name }}/.env"
        owner: "{{ app_name }}"
        group: "{{ app_name }}"
        mode: "0600"  # Lecture/écriture uniquement pour le propriétaire
      notify: Redémarrer application

    - name: Déployer la configuration de la base de données
      ansible.builtin.template:
        src: templates/database.yml.j2
        dest: "/etc/{{ app_name }}/database.yml"
        owner: "{{ app_name }}"
        group: "{{ app_name }}"
        mode: "0600"
      notify: Redémarrer application

  handlers:
    - name: Redémarrer application
      ansible.builtin.service:
        name: "{{ app_name }}"
        state: restarted
# templates/app.env.j2
APP_NAME={{ app_name }}
APP_PORT={{ app_port }}
APP_ENV={{ app_environment }}
LOG_LEVEL={{ app_log_level }}

# Base de données (secret déchiffré automatiquement)
DATABASE_URL=postgresql://{{ db_user }}:{{ db_password }}@{{ db_host }}:{{ db_port }}/{{ db_name }}

# API externe (secret déchiffré automatiquement)
API_URL={{ api_url }}
API_KEY={{ api_key }}

# SMTP (secret déchiffré automatiquement)
SMTP_HOST={{ smtp_host }}
SMTP_PORT={{ smtp_port }}
SMTP_USER={{ smtp_user }}
SMTP_PASSWORD={{ smtp_password }}

Opérations courantes

# Voir les secrets actuels
ansible-vault view inventory/production/group_vars/all/vault.yml

# Modifier un secret
ansible-vault edit inventory/production/group_vars/all/vault.yml

# Ajouter un nouveau secret chiffré inline
ansible-vault encrypt_string 'NouveauSecret2024!' --name 'vault_nouveau_secret'
# Copier la sortie dans vault.yml

# Exécuter le playbook (le déchiffrement est automatique grâce à ansible.cfg)
ansible-playbook playbooks/deploy.yml

# Exécuter en mode check (dry-run)
ansible-playbook playbooks/deploy.yml --check --diff

# Vérifier qu'aucun secret n'apparaît dans la sortie (mode no_log)
ansible-playbook playbooks/deploy.yml -v

Protéger la sortie Ansible avec no_log

Par défaut, Ansible peut afficher les valeurs des variables dans sa sortie (mode verbose). Pour empêcher l'affichage des secrets, utilisez no_log: true :

# Protéger les tâches manipulant des secrets
- name: Configurer l'accès à la base de données
  ansible.builtin.template:
    src: database.conf.j2
    dest: /etc/app/database.conf
  no_log: true  # Empêche l'affichage du contenu dans les logs

- name: Définir le mot de passe de l'utilisateur
  ansible.builtin.user:
    name: deploy
    password: "{{ vault_deploy_password | password_hash('sha512') }}"
  no_log: true  # CRUCIAL pour les mots de passe

Dépannage et Erreurs Courantes

Erreur : "Attempting to decrypt but no vault secrets found"

# Cause : pas de mot de passe Vault fourni
# Solution 1 : fournir le mot de passe
ansible-playbook playbook.yml --ask-vault-pass

# Solution 2 : configurer le fichier de mot de passe
ansible-playbook playbook.yml --vault-password-file ~/.vault_password

# Solution 3 : configurer dans ansible.cfg
# vault_password_file = ~/.vault_password

Erreur : "Decryption failed"

# Cause : mauvais mot de passe Vault
# Vérifiez que vous utilisez le bon mot de passe
ansible-vault view fichier.yml --ask-vault-pass

# Si vous avez plusieurs Vault IDs, vérifiez que vous fournissez le bon
ansible-vault view fichier.yml --vault-id production@prompt

Erreur : "input is not vault encrypted data"

# Cause : le fichier n'est pas chiffré ou est corrompu
# Vérifiez l'en-tête du fichier
head -1 fichier.yml
# Devrait afficher : $ANSIBLE_VAULT;1.1;AES256

# Si le fichier n'est pas chiffré, chiffrez-le
ansible-vault encrypt fichier.yml

Déboguer les variables Vault

# Pour vérifier qu'une variable Vault est correctement déchiffrée
# ATTENTION : utilisez uniquement en développement, jamais en production !
- name: Debug variable Vault (DEV UNIQUEMENT)
  ansible.builtin.debug:
    msg: "La longueur du mot de passe est {{ vault_db_password | length }} caractères"
  # Ne PAS afficher la valeur elle-même !
  # msg: "{{ vault_db_password }}"  # DANGEREUX !

Conclusion

Ansible Vault est un outil essentiel pour tout projet Ansible professionnel. Il offre un mécanisme de chiffrement simple mais robuste qui s'intègre naturellement dans le workflow Ansible existant. En suivant les bonnes pratiques présentées dans cet article — séparation des variables et des secrets, convention de nommage vault_, fichiers de mot de passe sécurisés, intégration CI/CD — vous protégez vos secrets sans ajouter de complexité excessive à votre projet.

Les points essentiels à retenir :

  • Chiffrez systématiquement tout ce qui est sensible avec ansible-vault encrypt ou encrypt_string.
  • Séparez les variables en clair (vars.yml) des secrets (vault.yml) avec une convention de nommage vault_.
  • Automatisez le déchiffrement en CI/CD avec ANSIBLE_VAULT_PASSWORD_FILE et des variables de pipeline protégées.
  • Utilisez multi-vault pour des mots de passe différents par environnement.
  • Protégez la sortie avec no_log: true sur les tâches manipulant des secrets.
  • Planifiez la rotation régulière de vos mots de passe Vault.
  • Pour les besoins avancés (rotation automatique, audit, contrôle d'accès fin), envisagez HashiCorp Vault en complément.

Avec cette série d'articles sur les rôles, Ansible Galaxy et Ansible Vault, vous disposez désormais de toutes les connaissances nécessaires pour construire une automatisation Ansible modulaire, réutilisable et sécurisée. Il ne reste plus qu'à mettre en pratique dans vos projets !

Vous vous êtes abonné avec succès à CodeClan
Parfait ! Ensuite, complétez le paiement pour obtenir un accès complet à tout le contenu premium.
Erreur ! Impossible de s'inscrire. Lien invalide.
Bienvenue ! Vous vous êtes connecté avec succès.
Erreur ! Impossible de se connecter. Veuillez réessayer.
Succès ! Votre compte est entièrement activé, vous avez maintenant accès à tout le contenu.
Erreur ! Le paiement Stripe a échoué.
Succès ! Vos informations de facturation sont mises à jour.
Erreur ! La mise à jour des informations de facturation a échoué.