Sécurité Ansible¶
Gérer les secrets avec Ansible Vault et OpenBao pour ne jamais stocker de données sensibles en clair.
Ansible Vault¶
Ansible Vault permet de chiffrer des fichiers ou des variables directement dans le dépôt Git. Les fichiers chiffres sont stockes au format AES-256 et peuvent être commites sans risque.
Commandes essentielles¶
# Chiffrer un fichier existant
ansible-vault encrypt group_vars/production/vault.yml
# Creer un nouveau fichier chiffre directement
ansible-vault create group_vars/production/vault.yml
# Modifier un fichier chiffre (dechiffrement temporaire en memoire)
ansible-vault edit group_vars/production/vault.yml
# Dechiffrer un fichier sur place (deconseille en production)
ansible-vault decrypt group_vars/production/vault.yml
# Changer le mot de passe de chiffrement
ansible-vault rekey group_vars/production/vault.yml
# Chiffrer une seule variable inline
ansible-vault encrypt_string 'MonMotDePasseSecret123' --name 'vault_db_password'
Utiliser Vault dans un playbook¶
# Demander le mot de passe interactivement
ansible-playbook site.yml --ask-vault-pass
# Utiliser un fichier contenant le mot de passe
ansible-playbook site.yml --vault-password-file ~/.vault_pass
Fichier de mot de passe Vault
Ne jamais committer le fichier de mot de passe Vault dans Git. L'ajouter dans .gitignore :
En CI/CD, stocker le mot de passe dans les secrets du pipeline (GitHub Actions secrets, GitLab CI variables protegees) et l'injecter via une variable d'environnement ou un fichier temporaire créé à la volee.
Organisation recommandee¶
Séparer les variables en clair des variables chiffrees, un fichier par niveau d'inventaire :
group_vars/
├── all/
│ ├── vars.yml # variables communes en clair
│ └── vault.yml # secrets communs (chiffres)
├── production/
│ ├── vars.yml # variables de production en clair
│ └── vault.yml # secrets de production (chiffres)
└── staging/
├── vars.yml # variables de staging en clair
└── vault.yml # secrets de staging (chiffres)
# group_vars/production/vars.yml
db_host: db.production.example.com
db_port: 5432
db_user: app_user
db_password: "{{ vault_db_password }}" # reference la variable vault
api_endpoint: https://api.example.com
api_key: "{{ vault_api_key }}"
# group_vars/production/vault.yml (chiffre avec ansible-vault)
vault_db_password: "MonMotDePasseSecret123"
vault_api_key: "sk-abcdef1234567890"
vault_smtp_password: "MotDePasseSMTP!"
Le préfixe vault_ permet d'identifier immédiatement les variables sensibles sans avoir a dechiffrer le fichier.
Vault IDs¶
Les Vault IDs permettent de gérer plusieurs mots de passe Vault en parallèle, un par environnement. Cela applique le principe de moindre privilege : une compromission du mot de passe de staging ne compromet pas la production.
Chiffrer avec un Vault ID spécifique¶
# Chiffrer le vault de production avec son propre ID
ansible-vault encrypt group_vars/production/vault.yml \
--vault-id prod@prompt
# Chiffrer le vault de staging avec un fichier de mot de passe
ansible-vault encrypt group_vars/staging/vault.yml \
--vault-id dev@~/.vault_pass_dev
Exécuter un playbook avec plusieurs Vault IDs¶
# Fournir les deux mots de passe lors de l'execution
ansible-playbook site.yml \
--vault-id prod@prompt \
--vault-id dev@~/.vault_pass_dev
# En CI/CD avec des fichiers de mots de passe distincts
ansible-playbook site.yml \
--vault-id prod@/run/secrets/vault_prod \
--vault-id dev@/run/secrets/vault_dev
Quand utiliser les Vault IDs¶
Préférer les Vault IDs dans les cas suivants :
- Plusieurs environnements (dev, staging, prod) avec des équipes d'accès différentes
- Rotation indépendante des mots de passe par environnement
- Pipelines CI/CD multi-environnements avec des secrets distincts
Pour un projet simple mono-environnement, un seul mot de passe Vault suffit.
OpenBao¶
OpenBao est un fork open source de HashiCorp Vault, maintenu par la Linux Foundation après le changement de licence de Vault en 2023. Il offre une API entièrement compatible et une gestion centralisee des secrets avec audit des accès, rotation automatique et contrôle d'accès granulaire.
Installation¶
# Linux : telecharger le binaire depuis GitHub Releases
wget https://github.com/openbao/openbao/releases/download/v2.0.0/bao_2.0.0_linux_amd64.zip
unzip bao_2.0.0_linux_amd64.zip
sudo mv bao /usr/local/bin/
bao version
# macOS via Homebrew
brew install openbao
Démarrer un serveur de développement¶
Le mode dev démarré un serveur en mémoire, non persistant. Suffisant pour tester l'intégration Ansible.
bao server -dev -dev-root-token-id="root"
# Dans un autre terminal, configurer les variables d'environnement
export BAO_ADDR='http://127.0.0.1:8200'
export BAO_TOKEN='root'
# Verifier que le serveur repond
bao status
Stocker et lire des secrets (KV v2)¶
# Activer le moteur de secrets KV version 2
bao secrets enable -path=secret kv-v2
# Stocker un secret avec plusieurs champs
bao kv put secret/ansible/database \
password="MonMotDePasseSecret123" \
user="app_user" \
host="db.example.com"
# Lire l'ensemble des champs d'un secret
bao kv get secret/ansible/database
# Lire uniquement un champ specifique
bao kv get -field=password secret/ansible/database
# Mettre a jour un seul champ sans ecraser les autres
bao kv patch secret/ansible/database password="NouveauMotDePasse!"
Intégration avec Ansible¶
OpenBao partage la même API REST que HashiCorp Vault. Le plugin community.hashi_vault est directement compatible sans modification.
# Installer la collection Ansible
ansible-galaxy collection install community.hashi_vault
# Installer le client Python requis par le plugin
pip install hvac
# Recuperer un secret depuis OpenBao dans un playbook
- name: Recuperer les credentials de base de donnees
ansible.builtin.set_fact:
db_password: "{{ lookup('community.hashi_vault.hashi_vault',
'secret/data/ansible/database:password',
url='http://vault.example.com:8200',
token=lookup('ansible.builtin.env', 'BAO_TOKEN')
) }}"
no_log: true
- name: Configurer la base de donnees
ansible.builtin.template:
src: templates/db.conf.j2
dest: /etc/app/db.conf
owner: app
group: app
mode: '0600'
no_log: true
Politiques et tokens¶
Créer des tokens avec des permissions minimales pour Ansible :
# Creer une politique limitee en lecture seule sur le chemin ansible/
bao policy write ansible-readonly - <<EOF
path "secret/data/ansible/*" {
capabilities = ["read"]
}
path "secret/metadata/ansible/*" {
capabilities = ["list"]
}
EOF
# Creer un token avec cette politique et une TTL limitee
bao token create \
-policy=ansible-readonly \
-ttl=24h \
-display-name="ansible-pipeline"
# Verifier les capacites du token sur un chemin
bao token capabilities secret/data/ansible/database
Méthodes d'authentification¶
| Méthode | Usage typique |
|---|---|
| Token | Usage direct, scripts simples, tests |
| AppRole | Applications et pipelines CI/CD |
| Kubernetes | Pods Kubernetes via service account JWT |
| LDAP | Authentification utilisateurs enterprise |
OpenBao vs Ansible Vault : quand choisir lequel
- Ansible Vault : solution simple et intégrée, adaptée aux secrets statiques versiones avec le code. Aucun serveur a opérer. Pas de rotation automatique ni de journal d'audit. Recommande pour les projets de taille modérée avec une équipe réduite.
- OpenBao : solution centralise avec audit complet, rotation automatique des secrets, revocation granulaire et accès multi-équipes. Indispensable pour les environnements multi-projets, les architectures microservices ou les contextes soumis à des exigences de conformité (PCI-DSS, ISO 27001).
Autres sources de secrets externes¶
Ansible propose des plugins de lookup pour intégrer les principaux gestionnaires de secrets du marche :
| Source | Plugin Ansible |
|---|---|
| OpenBao / HashiCorp Vault | community.hashi_vault.hashi_vault |
| AWS Secrets Manager | amazon.aws.aws_secret |
| GCP Secret Manager | google.cloud.gcp_secret_manager |
| Azure Key Vault | azure.azcollection.azure_keyvault_secret |
Dans tous les cas, ajouter no_log: true sur les tâches qui récupèrent ou utilisent ces secrets.
Sécurité d'exécution¶
Permissions sur les fichiers déployés¶
Toujours définir explicitement owner, group et mode sur les fichiers déployés. Ne jamais laisser Ansible utiliser les valeurs par défaut du système.
- name: Deployer le fichier de configuration applicative
ansible.builtin.template:
src: templates/app.conf.j2
dest: /etc/app/app.conf
owner: app
group: app
mode: '0640'
- name: Deployer une cle privee
ansible.builtin.copy:
content: "{{ vault_private_key }}"
dest: /etc/app/private.key
owner: app
group: app
mode: '0600'
no_log: true
Limiter become au niveau de la tâche¶
Éviter become: true au niveau du play sauf si toutes les tâches du play necessitent les privileges root. Préférer l'elevation au niveau de la tâche pour limiter la surface d'exposition.
# Mauvaise pratique : become au niveau du play
- name: Configurer le serveur
hosts: webservers
become: true # toutes les taches s'executent en root, meme si inutile
tasks:
- name: Installer nginx
ansible.builtin.apt:
name: nginx
state: present
- name: Deployer la config applicative
ansible.builtin.template:
src: app.conf.j2
dest: /etc/app/app.conf
# Bonne pratique : become uniquement sur les taches qui en ont besoin
- name: Configurer le serveur
hosts: webservers
tasks:
- name: Installer nginx
ansible.builtin.apt:
name: nginx
state: present
become: true # elevation uniquement pour cette tache
- name: Deployer la config applicative
ansible.builtin.template:
src: app.conf.j2
dest: /etc/app/app.conf
owner: app
group: app
mode: '0640'
# pas de become : l'utilisateur Ansible a les droits suffisants
Masquer les secrets dans les logs¶
Utiliser no_log: true sur toute tâche qui manipule des données sensibles. Ansible affiche par défaut les parametres des tâches dans la sortie standard.
- name: Configurer le mot de passe de la base de donnees
ansible.builtin.lineinfile:
path: /etc/app/db.conf
regexp: '^DB_PASSWORD='
line: "DB_PASSWORD={{ vault_db_password }}"
no_log: true # empeche l'affichage du mot de passe dans les logs
- name: Creer l'utilisateur applicatif avec mot de passe
ansible.builtin.user:
name: app_user
password: "{{ vault_app_user_password | password_hash('sha512') }}"
state: present
no_log: true
Préférer les clés SSH aux mots de passe¶
Déployer les clés SSH autorisees plutôt que de distribuer des mots de passe. Le module ansible.posix.authorized_key géré le fichier ~/.ssh/authorized_keys de façon idempotente.
- name: Deployer la cle SSH de l'utilisateur de deploiement
ansible.posix.authorized_key:
user: deploy
state: present
key: "{{ lookup('ansible.builtin.file', '~/.ssh/id_ed25519.pub') }}"
- name: S'assurer que seules les cles autorisees sont presentes
ansible.posix.authorized_key:
user: deploy
state: present
key: "{{ lookup('ansible.builtin.file', 'files/deploy_keys/{{ inventory_hostname }}.pub') }}"
exclusive: true # supprime toute autre cle non listee
- name: Desactiver l'authentification par mot de passe SSH
ansible.builtin.lineinfile:
path: /etc/ssh/sshd_config
regexp: '^PasswordAuthentication'
line: 'PasswordAuthentication no'
validate: 'sshd -t -f %s'
become: true
notify: Redemarrer sshd
Validation avant application
Utiliser le parametre validate des modules ansible.builtin.template et ansible.builtin.lineinfile pour les fichiers de configuration système critiques (sshd, sudoers, nginx). Une configuration invalide peut rendre un serveur inaccessible.