Skip to main content

Ansible avancé : Rôles, Ansible Vault et intégration CI/CD

· 7 min read

L'article précédent sur Ansible couvrait les bases de cet outil d'automatisation puissant. Cet article explore des concepts avancés qui permettent de créer des infrastructures complexes de manière modulaire, sécurisée et automatisée. 🚀

Les rôles Ansible : modularité et réutilisabilité 📦

Les rôles sont la pierre angulaire de la modularité dans Ansible. Ils permettent d'organiser les playbooks en composants réutilisables et maintenables.

Structure d'un rôle

Un rôle suit une structure de répertoires standardisée :

roles/
└── webserver/
├── defaults/ # Variables par défaut (priorité la plus basse)
│ └── main.yml
├── vars/ # Variables du rôle (priorité haute)
│ └── main.yml
├── tasks/ # Tâches principales du rôle
│ └── main.yml
├── handlers/ # Gestionnaires d'événements
│ └── main.yml
├── templates/ # Templates Jinja2
│ └── nginx.conf.j2
├── files/ # Fichiers statiques
│ └── index.html
├── meta/ # Métadonnées et dépendances
│ └── main.yml
└── README.md # Documentation du rôle

Créer un rôle avec ansible-galaxy

# Créer la structure d'un nouveau rôle
ansible-galaxy init webserver

# Créer un rôle dans un répertoire spécifique
ansible-galaxy init roles/webserver

# Voir la structure créée
tree roles/webserver

Exemple de rôle complet : webserver

tasks/main.yml

---
# Installation et configuration de Nginx
- name: Installer les paquets requis
apt:
name:
- nginx
- python3-pip
state: present
update_cache: yes

- name: Configurer Nginx
template:
src: nginx.conf.j2
dest: /etc/nginx/sites-available/{{ site_name }}
owner: root
group: root
mode: '0644'
notify: reload nginx

- name: Activer le site
file:
src: /etc/nginx/sites-available/{{ site_name }}
dest: /etc/nginx/sites-enabled/{{ site_name }}
state: link
notify: reload nginx

- name: Déployer le contenu du site
template:
src: index.html.j2
dest: /var/www/{{ site_name }}/index.html
owner: www-data
group: www-data
mode: '0644'

- name: S'assurer que Nginx est démarré
service:
name: nginx
state: started
enabled: yes

defaults/main.yml

---
# Variables par défaut du rôle webserver
site_name: example.com
document_root: /var/www/{{ site_name }}
server_port: 80
server_name: "{{ site_name }}"

vars/main.yml

---
# Variables spécifiques au rôle (priorité plus haute)
nginx_worker_processes: auto
nginx_worker_connections: 1024

handlers/main.yml

---
# Gestionnaires pour Nginx
- name: reload nginx
service:
name: nginx
state: reloaded

- name: restart nginx
service:
name: nginx
state: restarted

templates/nginx.conf.j2

server {
listen {{ server_port }};
server_name {{ server_name }};

root {{ document_root }};
index index.html;

location / {
try_files $uri $uri/ =404;
}

access_log /var/log/nginx/{{ site_name }}_access.log;
error_log /var/log/nginx/{{ site_name }}_error.log;
}

meta/main.yml

---
# Métadonnées et dépendances du rôle
galaxy_info:
author: Votre Nom
description: Installation et configuration de Nginx
company: Votre Entreprise
license: MIT
min_ansible_version: 2.9

platforms:
- name: Ubuntu
versions:
- focal
- jammy
- name: Debian
versions:
- bullseye
- bookworm

galaxy_tags:
- nginx
- webserver
- web

dependencies: []

Utiliser un rôle dans un playbook

---
- name: Configurer les serveurs web
hosts: webservers
become: yes

roles:
- role: webserver
vars:
site_name: monsite.com
server_port: 8080

# Ou avec une syntaxe plus détaillée
- name: Configurer avec des conditions
hosts: webservers
become: yes

roles:
- role: webserver
when: ansible_os_family == "Debian"
tags:
- nginx
- web

Collections Ansible 📚

Les collections sont des packages qui regroupent modules, rôles, plugins et playbooks. Elles remplacent progressivement les rôles Galaxy.

Installer une collection

# Installer depuis Ansible Galaxy
ansible-galaxy collection install community.general

# Installer depuis un fichier requirements.yml
ansible-galaxy collection install -r requirements.yml

# Installer une version spécifique
ansible-galaxy collection install community.general:5.8.0

Fichier requirements.yml

---
collections:
# Depuis Ansible Galaxy
- name: community.general
version: ">=5.0.0"

- name: ansible.posix
version: "1.5.1"

- name: community.docker

# Depuis un dépôt Git
- name: https://github.com/organisation/ma-collection.git
type: git
version: main

Utiliser une collection

---
- name: Utiliser des modules de collections
hosts: all

tasks:
# Méthode 1 : FQCN (Fully Qualified Collection Name)
- name: Installer un paquet avec community.general
community.general.npm:
name: express
global: yes

# Méthode 2 : Importer la collection
- name: Docker tasks
block:
- community.docker.docker_container:
name: nginx
image: nginx:latest
state: started
collections:
- community.docker

Créer sa propre collection

# Créer la structure d'une collection
ansible-galaxy collection init mon_namespace.ma_collection

# Structure créée
mon_namespace/
└── ma_collection/
├── docs/
├── galaxy.yml # Métadonnées de la collection
├── plugins/
│ ├── modules/ # Modules personnalisés
│ ├── inventory/ # Plugins d'inventaire
│ └── lookup/ # Plugins lookup
├── roles/ # Rôles inclus dans la collection
├── playbooks/ # Playbooks d'exemple
└── README.md

Ansible Vault : gérer les secrets en toute sécurité 🔒

Ansible Vault permet de chiffrer les fichiers contenant des données sensibles.

Créer un fichier chiffré

# Créer un nouveau fichier chiffré
ansible-vault create secrets.yml

# Vous serez invité à entrer un mot de passe
# Puis un éditeur s'ouvrira pour saisir le contenu

Contenu de secrets.yml (déchiffré) :

---
db_password: "SuperSecretPassword123!"
api_key: "abc123def456ghi789"
ssl_certificate_key: |
-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC...
-----END PRIVATE KEY-----

Chiffrer un fichier existant

# Chiffrer un fichier existant
ansible-vault encrypt vars/production.yml

# Chiffrer plusieurs fichiers
ansible-vault encrypt vars/*.yml

Modifier un fichier chiffré

# Éditer un fichier chiffré (déchiffrement temporaire)
ansible-vault edit secrets.yml

# Voir le contenu sans éditer
ansible-vault view secrets.yml

Déchiffrer un fichier

# Déchiffrer un fichier (attention, perte de la protection !)
ansible-vault decrypt secrets.yml

# Rechiffrer avec un nouveau mot de passe
ansible-vault rekey secrets.yml

Utiliser Vault dans un playbook

---
- name: Déploiement avec secrets
hosts: production
vars_files:
- vars/common.yml
- secrets.yml # Fichier chiffré avec Vault

tasks:
- name: Configurer la base de données
mysql_user:
name: app_user
password: "{{ db_password }}" # Depuis secrets.yml
priv: "appdb.*:ALL"
state: present

- name: Configurer l'API
template:
src: api_config.j2
dest: /etc/app/config.json
vars:
api_secret: "{{ api_key }}"

Exécuter avec Vault

# Demander le mot de passe interactivement
ansible-playbook deploy.yml --ask-vault-pass

# Utiliser un fichier de mot de passe
ansible-playbook deploy.yml --vault-password-file ~/.vault_pass.txt

# Utiliser un script pour obtenir le mot de passe
ansible-playbook deploy.yml --vault-password-file get_vault_pass.sh

Fichier de mot de passe

# Créer un fichier de mot de passe
echo "MonMotDePasseVault" > ~/.vault_pass.txt
chmod 600 ~/.vault_pass.txt

# Configurer dans ansible.cfg
cat >> ansible.cfg << EOF
[defaults]
vault_password_file = ~/.vault_pass.txt
EOF

Script pour récupérer le mot de passe

#!/bin/bash
# get_vault_pass.sh - Récupère le mot de passe depuis un gestionnaire de secrets

# Exemple avec pass (passwordstore.org)
pass show ansible/vault

# Exemple avec AWS Secrets Manager
aws secretsmanager get-secret-value \
--secret-id ansible-vault \
--query SecretString \
--output text

# Exemple avec 1Password CLI
op read "op://DevOps/Ansible Vault/password"

Vault IDs : gérer plusieurs clés

# Créer des fichiers avec différents Vault IDs
ansible-vault create --vault-id dev@prompt secrets_dev.yml
ansible-vault create --vault-id prod@prompt secrets_prod.yml

# Utiliser avec des fichiers de mots de passe
ansible-vault create --vault-id dev@.vault_dev secrets_dev.yml

# Exécuter avec plusieurs Vault IDs
ansible-playbook deploy.yml \
--vault-id dev@.vault_dev \
--vault-id prod@.vault_prod

Chiffrer des variables individuelles

---
# Au lieu de chiffrer tout le fichier
db_host: localhost
db_user: app_user
db_password: !vault |
$ANSIBLE_VAULT;1.1;AES256
66386439653936393039346235323131386335333132333239336631643366326362333733363264
3939666233316362313938396331626664626134623239360a356430646364633338336564383661
...

# Créer une variable chiffrée
ansible-vault encrypt_string 'SuperSecretPassword' --name 'db_password'

Bonnes pratiques avancées 🏆

1. Structure de projet recommandée

ansible-project/
├── ansible.cfg
├── inventories/
│ ├── production/
│ │ ├── hosts.yml
│ │ └── group_vars/
│ │ ├── all.yml
│ │ └── webservers.yml
│ └── staging/
│ ├── hosts.yml
│ └── group_vars/
├── roles/
│ ├── common/
│ ├── webserver/
│ └── database/
├── playbooks/
│ ├── deploy.yml
│ ├── rollback.yml
│ └── maintenance.yml
├── collections/
│ └── requirements.yml
├── group_vars/
│ └── all/
│ ├── vars.yml
│ └── vault.yml
└── README.md

2. Utiliser des tags stratégiquement

---
- name: Configuration complète
hosts: webservers

tasks:
- name: Installer les paquets
apt:
name: "{{ item }}"
state: present
loop:
- nginx
- python3
tags:
- install
- packages

- name: Configurer Nginx
template:
src: nginx.conf.j2
dest: /etc/nginx/nginx.conf
tags:
- config
- nginx

- name: Déployer l'application
copy:
src: app/
dest: /var/www/app/
tags:
- deploy
- app

# Exécuter uniquement certaines tâches
# ansible-playbook deploy.yml --tags "config"
# ansible-playbook deploy.yml --skip-tags "deploy"

3. Gestion des erreurs robuste

---
- name: Gestion d'erreurs avancée
hosts: all

tasks:
- name: Tâche qui peut échouer
command: /opt/script.sh
register: script_result
ignore_errors: yes

- name: Traiter le résultat
block:
- debug:
msg: "Script réussi : {{ script_result.stdout }}"
rescue:
- debug:
msg: "Script échoué : {{ script_result.stderr }}"
- include_tasks: rollback.yml
always:
- name: Nettoyage
file:
path: /tmp/script-lock
state: absent

Conclusion 🎯

Ansible offre des fonctionnalités avancées puissantes pour gérer des infrastructures complexes de manière sécurisée et automatisée. Les rôles et collections permettent de créer des composants réutilisables, Vault protège les secrets, et l'intégration CI/CD automatise les déploiements.

Points clés à retenir :

  • Rôles : modulariser et réutiliser le code
  • Collections : packages complets de fonctionnalités
  • Vault : chiffrer les données sensibles
  • CI/CD : automatiser les déploiements
  • Stratégies : blue-green, canary, rollback automatique

La maîtrise de ces concepts permet de créer des infrastructures as code robustes, maintenables et sécurisées.

Ressources utiles 📚