Automatiser la gestion d’infrastructure avec Ansible : de la configuration manuelle à l’Infrastructure as Code
Quand on administre une infrastructure auto-hébergée composée de multiples services — CKAN, Nextcloud, Keycloak, Gitea, Superset — la tentation est grande de tout configurer à la main, serveur par serveur. Ça fonctionne au début, mais dès que l’environnement grandit ou qu’il faut reconstruire un nœud, la dette technique explose. Ansible propose une approche radicalement différente : décrire l’état souhaité de chaque machine dans des fichiers YAML versionnés, puis laisser l’outil appliquer la configuration de manière idempotente.
Pourquoi passer à l’Infrastructure as Code
L’Infrastructure as Code (IaC) consiste à traiter la configuration de vos serveurs exactement comme du code applicatif : versionné dans Git, relu en pull request, testé avant déploiement. Les avantages sont concrets. La reproductibilité permet de recréer un environnement complet à partir de zéro en une commande. La traçabilité offre un historique clair de chaque modification apportée à l’infrastructure. L’auditabilité rend visible qui a changé quoi, quand, et pourquoi. Enfin, la scalabilité permet d’ajouter un nouveau serveur en l’inscrivant simplement dans l’inventaire.
Ansible se distingue des autres outils d’IaC (Terraform, Puppet, Chef) par son architecture sans agent : il se connecte en SSH aux machines cibles, exécute les tâches, et se déconnecte. Pas de daemon à installer, pas de PKI à maintenir. Pour une infrastructure open source de taille modeste à moyenne, c’est un atout majeur.
Structurer un projet Ansible pour une infrastructure multi-services
Un projet Ansible bien organisé repose sur trois piliers : l’inventaire, les rôles et les playbooks. L’inventaire décrit vos machines et les regroupe par fonction. Les rôles encapsulent la logique de configuration d’un service donné. Les playbooks orchestrent l’application des rôles sur les bons groupes de machines.
Voici une structure type pour un projet gérant une infrastructure comme celle d’askem.eu :
infrastructure/
├── inventory/
│ ├── production.yml
│ └── staging.yml
├── roles/
│ ├── common/ # Paquets de base, sécurité SSH, fail2ban
│ ├── docker/ # Installation et configuration de Docker
│ ├── nginx/ # Reverse proxy, certificats TLS
│ ├── keycloak/ # SSO et gestion d'identité
│ ├── ckan/ # Portail de données ouvertes
│ ├── nextcloud/ # Collaboration et stockage
│ ├── gitea/ # Forge Git auto-hébergée
│ ├── monitoring/ # Prometheus, Grafana, Loki
│ └── backup/ # Stratégie de sauvegarde automatisée
├── playbooks/
│ ├── site.yml # Playbook principal
│ ├── deploy-ckan.yml
│ └── update-tls.yml
└── group_vars/
├── all.yml
└── production.yml
L’inventaire : cartographier son infrastructure
L’inventaire YAML décrit chaque machine et son appartenance à un ou plusieurs groupes. Il peut aussi contenir des variables spécifiques à chaque hôte ou groupe :
all:
children:
webservers:
hosts:
proxy-01:
ansible_host: 10.0.1.10
nginx_worker_processes: 4
appservers:
hosts:
app-01:
ansible_host: 10.0.1.20
services:
- ckan
- keycloak
- nextcloud
app-02:
ansible_host: 10.0.1.21
services:
- gitea
- superset
monitoring:
hosts:
mon-01:
ansible_host: 10.0.1.30
Les rôles : encapsuler la logique de configuration
Chaque rôle gère un aspect précis de l’infrastructure. Prenons l’exemple d’un rôle common qui sécurise la base de chaque serveur :
# roles/common/tasks/main.yml
---
- name: Mettre à jour les paquets système
apt:
upgrade: safe
update_cache: yes
cache_valid_time: 3600
- name: Installer les paquets de base
apt:
name:
- curl
- htop
- unattended-upgrades
- fail2ban
- ufw
state: present
- name: Configurer le pare-feu UFW
ufw:
rule: allow
port: "{{ item }}"
proto: tcp
loop:
- "22"
- "80"
- "443"
- name: Activer le pare-feu
ufw:
state: enabled
default: deny
- name: Durcir la configuration SSH
lineinfile:
path: /etc/ssh/sshd_config
regexp: "{{ item.regexp }}"
line: "{{ item.line }}"
loop:
- { regexp: '^#?PermitRootLogin', line: 'PermitRootLogin no' }
- { regexp: '^#?PasswordAuthentication', line: 'PasswordAuthentication no' }
notify: restart sshd
L’idempotence est la propriété clé : chaque tâche vérifie l’état actuel avant d’agir. Si le pare-feu est déjà configuré correctement, Ansible ne touche à rien. On peut relancer le playbook autant de fois qu’on veut sans effet de bord.
Gérer les secrets avec Ansible Vault
Une infrastructure réelle contient des mots de passe de base de données, des clés API, des certificats. Ansible Vault permet de chiffrer ces données directement dans le dépôt Git, sans compromettre la sécurité :
# Chiffrer un fichier de variables sensibles ansible-vault encrypt group_vars/production/vault.yml # Exécuter un playbook avec déchiffrement ansible-playbook -i inventory/production.yml playbooks/site.yml --ask-vault-pass # Ou utiliser un fichier de mot de passe (pour la CI/CD) ansible-playbook -i inventory/production.yml playbooks/site.yml \ --vault-password-file ~/.vault_pass
Les variables chiffrées sont utilisées comme n’importe quelle autre variable dans les templates et les tâches. L’intégration avec Gitea Actions permet d’automatiser le déploiement tout en gardant les secrets protégés.
Intégrer Ansible dans une chaîne CI/CD
L’étape suivante consiste à déclencher les playbooks automatiquement. Avec Gitea Actions (déjà couvert sur ce site), on peut créer un workflow qui exécute Ansible à chaque push sur la branche principale du dépôt d’infrastructure :
# .gitea/workflows/deploy.yml
name: Deploy infrastructure
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install Ansible
run: pip install ansible
- name: Run playbook
env:
ANSIBLE_VAULT_PASSWORD: ${{ secrets.VAULT_PASSWORD }}
SSH_PRIVATE_KEY: ${{ secrets.DEPLOY_KEY }}
run: |
echo "$SSH_PRIVATE_KEY" > /tmp/deploy_key
chmod 600 /tmp/deploy_key
echo "$ANSIBLE_VAULT_PASSWORD" > /tmp/vault_pass
ansible-playbook -i inventory/production.yml playbooks/site.yml \
--vault-password-file /tmp/vault_pass \
--private-key /tmp/deploy_key
Chaque modification de l’infrastructure passe par une pull request, est relue, puis appliquée automatiquement. Plus de SSH en direct sur les serveurs pour modifier une configuration à la volée.
Bonnes pratiques pour un projet Ansible durable
Quelques principes éprouvés pour maintenir un projet Ansible sur la durée. Premièrement, versionner tout : inventaires, rôles, playbooks, variables (chiffrées). Le dépôt Git est la source de vérité unique. Deuxièmement, séparer les environnements avec des inventaires distincts pour staging et production, en partageant les mêmes rôles. Troisièmement, tester avant de déployer en utilisant le mode --check (dry run) et l’option --diff pour visualiser les changements avant de les appliquer. Quatrièmement, documenter les rôles avec un fichier README.md dans chaque rôle décrivant ses variables, ses dépendances et son usage. Enfin, limiter la portée : un playbook qui prend plus de 10 minutes à s’exécuter est probablement trop large — découpez-le en playbooks ciblés.
Aller plus loin
Ansible peut aussi gérer le provisionnement de conteneurs Docker (via le module community.docker), orchestrer des mises à jour rolling sur plusieurs serveurs, ou encore générer dynamiquement des fichiers de configuration Nginx à partir de templates Jinja2. Combiné à un inventaire dynamique qui interroge votre hyperviseur ou votre cloud provider, il devient le point d’entrée unique pour toute opération sur l’infrastructure.
Pour une infrastructure comme celle d’askem.eu, le passage à Ansible représente un investissement initial de quelques jours qui se rentabilise dès la première reconstruction de serveur ou le premier audit de sécurité. L’infrastructure cesse d’être un savoir tacite dans la tête de l’administrateur pour devenir un artefact versionné, testable et partageable.
