Chapitre 1623 minIntermédiaire
Exercices Ansible corrigés type E6 SISR
Par Josselyn C., prof de BTS SIO. Mis à jour le .
À la fin de ce chapitre, tu sauras
- écrire un inventaire et un playbook à partir d'un besoin ;
- trouver les erreurs d'un playbook qui ne marche pas ;
- traiter un cas de synthèse de bout en bout ;
- expliquer ses choix comme devant la commission de l'E6.
7 exercices corrigés
Ce chapitre rassemble des exercices Ansible corrigés de difficulté croissante, dans l'esprit des tâches demandées pendant l'heure de réalisation de l'E6 SISR et des questions de l'entretien : écrire un inventaire, corriger un playbook, construire un rôle, gérer des serveurs Windows, lire un résultat, puis un cas de synthèse complet. Chaque exercice se suffit à lui-même ; les rappels de cours renvoient aux chapitres concernés.
Exercice 1 : l'inventaire de l'agence de Marseille
Exercice 1 sur 7 Écrire l'inventaire et ses variables Réussi À revoir
L'agence de Marseille a quatre serveurs dans son réseau des serveurs, 10.30.1.160/28 (passerelle 10.30.1.174) : deux serveurs web Debian 13, mrs-web1 (.161) et mrs-web2 (.162), un serveur de base de données Debian 13, mrs-bdd (.163), et un serveur de fichiers Windows Server 2025, mrs-fichiers (.164), membre du domaine ad.sorbier.example.
- Écris l'inventaire YAML
inventaire/marseille.yml, avec un groupemarseillequi contient les groupesmarseille_linux(lui-même découpé enmarseille_webetmarseille_bdd) etmarseille_windows. - Écris les fichiers de variables nécessaires pour que les serveurs Linux utilisent le compte
ansibleet que le serveur Windows utilise WinRM en HTTPS avec Kerberos et le comptesvc-ansible. - Donne la commande qui vérifie la structure, et celle qui liste les hôtes de
marseillequi ne sont pas des serveurs web.
Voir la réponseMasquer la réponse de l'exercice 1
inventaire/marseille.yml:
---
all:
children:
marseille:
children:
marseille_linux:
children:
marseille_web:
hosts:
mrs-web1:
ansible_host: 10.30.1.161
mrs-web2:
ansible_host: 10.30.1.162
marseille_bdd:
hosts:
mrs-bdd:
ansible_host: 10.30.1.163
marseille_windows:
hosts:
mrs-fichiers:
ansible_host: mrs-fichiers.ad.sorbier.example
Le serveur Windows est désigné par son nom complet : Kerberos a besoin d'un nom, pas d'une adresse.
inventaire/group_vars/marseille_linux.yml:
---
ansible_user: ansible
inventaire/group_vars/marseille_windows/vars.yml :
---
ansible_connection: winrm
ansible_port: 5986
ansible_winrm_transport: kerberos
ansible_user: svc-ansible@AD.SORBIER.EXAMPLE
ansible_password: "{{ vault_mdp_svc_ansible }}"
et vault_mdp_svc_ansible dans inventaire/group_vars/marseille_windows/vault.yml, chiffré par ansible-vault. Si Marseille fait partie du même inventaire que le siège, on peut aussi placer marseille_windows comme groupe enfant de windows et réutiliser ses variables, sans les recopier.
ansible-inventory -i inventaire/marseille.yml --graphetansible -i inventaire/marseille.yml 'marseille:!marseille_web' --list-hosts, qui affichemrs-bddetmrs-fichiers.
Tu avais trouvé ?
Exercice 2 : le playbook qui ne marche pas
Exercice 2 sur 7 Six erreurs Réussi À revoir
Moussa a écrit ce playbook pour durcir SSH sur les serveurs Linux. Il contient six erreurs ou mauvaises pratiques, dont certaines empêchent l'exécution avec ansible-core 2.22. Trouve-les, explique-les et donne la version corrigée.
---
- name: Durcir SSH
hosts: linux
become: true
vars:
interdire_root: "yes"
tasks:
- name: Interdire la connexion de root
ansible.builtin.lineinfile:
path: /etc/ssh/sshd_config
regexp: "^#?PermitRootLogin"
line: PermitRootLogin no
when: interdire_root
- name: Afficher la distribution
ansible.builtin.debug:
msg: "Distribution : {{ ansible_distribution }}"
- name: Redémarrer SSH
ansible.builtin.service:
name: sshd
state: restarted
- name: Déposer la bannière
ansible.builtin.copy:
src: files/banniere.txt
dest: /etc/issue.net
mode: 644
Voir la réponseMasquer la réponse de l'exercice 2
when: interdire_rootavec une chaîne : depuis ansible-core 2.19, une condition doit être un booléen ;"yes"est une chaîne, la tâche échoue (« Conditionals must have a boolean result »). Écrireinterdire_root: true, ouwhen: interdire_root | bool.ansible_distributionen variable de premier niveau : l'injection des facts est dépréciée depuis 2.20 et disparaîtra en 2.24. Écrireansible_facts['distribution'].- Le redémarrage dans une tâche ordinaire : SSH est redémarré à chaque exécution, même sans changement, et la tâche n'est jamais idempotente. Il faut un handler, notifié par la modification du fichier.
- Le nom du service : sur Debian, le service s'appelle
ssh, passshd(le nomsshdexiste comme alias sur certaines versions, maissshest le bon nom). Etreloadedsuffit : il relit la configuration sans couper les sessions ouvertes. - Pas de validation : une erreur dans
sshd_configempêcherait SSH de redémarrer, et Ansible ne pourrait plus se connecter. Ajoutervalidate: /usr/sbin/sshd -t -f %s. mode: 644: sans guillemets ni zéro initial, c'est le nombre décimal 644, soit les droits octaux1204. Écriremode: "0644".
---
- name: Durcir SSH
hosts: linux
become: true
vars:
interdire_root: true
tasks:
- name: Interdire la connexion de root
ansible.builtin.lineinfile:
path: /etc/ssh/sshd_config
regexp: "^#?PermitRootLogin"
line: PermitRootLogin no
validate: /usr/sbin/sshd -t -f %s
when: interdire_root
notify: Recharger SSH
- name: Afficher la distribution
ansible.builtin.debug:
msg: "Distribution : {{ ansible_facts['distribution'] }}"
- name: Déposer la bannière
ansible.builtin.copy:
src: files/banniere.txt
dest: /etc/issue.net
owner: root
group: root
mode: "0644"
handlers:
- name: Recharger SSH
ansible.builtin.service:
name: ssh
state: reloaded
Pour aller plus loin, le rôle socle du chapitre 8 dépose plutôt un fichier dans /etc/ssh/sshd_config.d/, ce qui évite de modifier le fichier du paquet ligne par ligne. La bannière n'est affichée que si sshd_config contient Banner /etc/issue.net.
Tu avais trouvé ?
Exercice 3 : un premier rôle réutilisable
Exercice 3 sur 7 Écrire un rôle Réussi À revoir
Rappel : un rôle range ses variables réglables dans defaults/ et ses tâches dans tasks/ (chapitre 8). Écris le rôle outils (fichiers defaults/main.yml et tasks/main.yml) qui installe une liste de paquets réglable, par défaut tcpdump, dnsutils et rsync, et dépose le message d'accueil /etc/motd dont le texte est réglable. Puis écris le play qui l'applique aux serveurs Linux en ajoutant apachetop à la liste sur le seul srv-web, sans retirer les autres.
Voir la réponseMasquer la réponse de l'exercice 3
roles/outils/defaults/main.yml :
---
outils_paquets:
- tcpdump
- dnsutils
- rsync
outils_paquets_hote: []
outils_motd: "Serveur de Sorbier Logistique : accès réservé au service informatique."
roles/outils/tasks/main.yml :
---
- name: Installer les outils
ansible.builtin.apt:
name: "{{ outils_paquets + outils_paquets_hote }}"
state: present
update_cache: true
cache_valid_time: 3600
- name: Déposer le message d'accueil
ansible.builtin.copy:
content: "{{ outils_motd }}\n"
dest: /etc/motd
owner: root
group: root
mode: "0644"
Le play :
---
- name: Installer les outils sur les serveurs Linux
hosts: linux
become: true
roles:
- outils
et host_vars/srv-web.yml reçoit outils_paquets_hote: [apachetop]. Comme Ansible remplace les listes au lieu de les fusionner, on sépare la liste commune et la liste propre à l'hôte, et la tâche les additionne.
Tu avais trouvé ?
Exercice 4 : un rôle de sauvegarde
Exercice 4 sur 7 Le rôle sauvegarde Réussi À revoir
Chaque serveur Linux doit sauvegarder chaque nuit son dossier /etc avec un script fourni par l'équipe, files/sauvegarde-etc.sh. Écris le rôle sauvegarde (defaults/main.yml et tasks/main.yml) qui :
- installe
rsync; - crée le dossier
/var/backups/sorbier(propriétaireroot, droits0700) ; - dépose le script dans
/usr/local/sbin/sauvegarde-etc.sh(droits0750) ; - planifie son exécution chaque nuit, l'heure étant réglable (par défaut 2 h 15), avec la sortie dans
/var/log/sauvegarde-etc.log.
Puis écris le play qui l'applique aux serveurs Linux, en décalant l'heure à 3 h 15 pour srv-journaux.
Voir la réponseMasquer la réponse de l'exercice 4
roles/sauvegarde/defaults/main.yml :
---
sauvegarde_dossier: /var/backups/sorbier
sauvegarde_heure: 2
sauvegarde_minute: 15
roles/sauvegarde/tasks/main.yml :
---
- name: Installer rsync
ansible.builtin.apt:
name: rsync
state: present
- name: Créer le dossier des sauvegardes
ansible.builtin.file:
path: "{{ sauvegarde_dossier }}"
state: directory
owner: root
group: root
mode: "0700"
- name: Déposer le script de sauvegarde
ansible.builtin.copy:
src: sauvegarde-etc.sh
dest: /usr/local/sbin/sauvegarde-etc.sh
owner: root
group: root
mode: "0750"
- name: Planifier la sauvegarde chaque nuit
ansible.builtin.cron:
name: Sauvegarde de /etc
user: root
hour: "{{ sauvegarde_heure }}"
minute: "{{ sauvegarde_minute }}"
job: /usr/local/sbin/sauvegarde-etc.sh >> /var/log/sauvegarde-etc.log 2>&1
Le script va dans roles/sauvegarde/files/sauvegarde-etc.sh : copy le trouve sans chemin. Le name de la tâche cron sert d'identifiant : Ansible l'écrit en commentaire au-dessus de la ligne de la crontab et s'en sert pour la retrouver, ce qui rend la tâche idempotente. Le play :
---
- name: Planifier les sauvegardes de /etc
hosts: linux
become: true
roles:
- sauvegarde
et host_vars/srv-journaux.yml reçoit sauvegarde_heure: 3. Une sauvegarde qui reste sur le serveur ne protège pas d'une perte du serveur : une copie hors de la machine (vers un NAS, un serveur de sauvegarde) est indispensable, comme l'explique le cours Sauvegarde et PRA.
Tu avais trouvé ?
Exercice 5 : les serveurs Windows
Exercice 5 sur 7 Un socle Windows Réussi À revoir
Écris le playbook socle_windows.yml qui, sur tous les serveurs Windows de Sorbier :
- règle le fuseau horaire de Paris (
Romance Standard Time) ; - crée le dossier
C:\Outils; - installe les fonctionnalités
RSAT-AD-ToolsetWindows-Server-Backup; - sur les contrôleurs de domaine seulement, arrête et désactive le service
Spooler; - redémarre le serveur si l'installation des fonctionnalités l'exige.
Voir la réponseMasquer la réponse de l'exercice 5
---
- name: Appliquer le socle aux serveurs Windows
hosts: windows
tasks:
- name: Régler le fuseau horaire de Paris
ansible.windows.win_timezone:
timezone: Romance Standard Time
- name: Créer le dossier des outils
ansible.windows.win_file:
path: C:\Outils
state: directory
- name: Installer les outils AD et la sauvegarde Windows
ansible.windows.win_feature:
name:
- RSAT-AD-Tools
- Windows-Server-Backup
state: present
register: fonctionnalites
- name: Arrêter et désactiver le spouleur sur les contrôleurs
ansible.windows.win_service:
name: Spooler
state: stopped
start_mode: disabled
when: "'controleurs' in group_names"
- name: Redémarrer si nécessaire
ansible.windows.win_reboot:
when: fonctionnalites.reboot_required
Le chemin C:\Outils est écrit sans guillemets : entre guillemets doubles, \O serait interprété par YAML. La condition 'controleurs' in group_names vise srv-ad et srv-ad2. Le redémarrage est en dernier : si plusieurs tâches peuvent l'exiger, on enregistre chacune et on combine les conditions, ou on utilise ansible.windows.win_reboot_info pour demander à Windows s'il attend un redémarrage. Sur des contrôleurs de domaine, ajoute serial: 1 au play pour ne jamais redémarrer les deux en même temps.
Tu avais trouvé ?
Exercice 6 : lire le résultat d'une exécution
Exercice 6 sur 7 Analyser un récapitulatif Réussi À revoir
Chloé lance ansible-playbook site.yml et obtient ce récapitulatif :
PLAY RECAP *********************************************************************
srv-journaux : ok=12 changed=0 unreachable=0 failed=0 skipped=1 rescued=0 ignored=0
srv-recette : ok=0 changed=0 unreachable=1 failed=0 skipped=0 rescued=0 ignored=0
srv-web : ok=15 changed=3 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0
- Que s'est-il passé sur chaque hôte ?
- Quel est le code de retour de la commande ?
- Quelles commandes lances-tu pour enquêter et reprendre ?
Voir la réponseMasquer la réponse de l'exercice 6
srv-journaux: tout s'est bien passé, rien n'a changé (configuration déjà conforme), une tâche sautée par une condition.srv-recette: injoignable, aucune tâche n'a tourné (VM arrêtée, réseau, SSH, clé).srv-web: 15 tâches réussies dont 3 modifications, puis un échec, qui a arrêté le playbook pour cet hôte : les tâches suivantes n'ont pas été exécutées, et les handlers notifiés avant l'échec non plus (sauf--force-handlers).- 4 : ansible-core renvoie 4 dès qu'un hôte est injoignable, ce code passant avant le 2 d'un hôte en échec. Un script qui teste seulement « différent de 0 » détecte les deux cas.
- Remonter dans la sortie jusqu'à la tâche
fatal: [srv-web]pour lire le message. Relancer en détail sur ce seul hôte :ansible-playbook site.yml --limit srv-web -v, voire--start-at-task "<nom de la tâche>"après correction. Poursrv-recette:ansible srv-recette -m ansible.builtin.ping -vvv, qui montre la commande SSH et l'erreur exacte. Une fois corrigé, relancer tout le playbook : il est idempotent.
Tu avais trouvé ?
Exercice 7 : cas de synthèse, le site de suivi en recette
Exercice 7 sur 7 Industrialiser la recette Réussi À revoir
Antoine veut tester chaque évolution du site de suivi des livraisons sur la VM srv-recette (VM 186, 192.168.21.186, créée au chapitre 13) avant de l'appliquer à srv-web. Le site de recette doit répondre au nom suivi-recette.sorbier.example, avec la racine /var/www/suivi-recette. Tout doit passer par le dépôt sorbier-infra.
- Quelles modifications fais-tu dans l'inventaire ? Écris-les.
- Écris la tâche qui déclare dans le DNS de l'annuaire un alias
suivi-recetteverssrv-recette.ad.sorbier.example, et dis sur quel hôte elle s'exécute. - Le playbook
site.ymlappliquesocleau groupelinuxetwebau groupeserveurs_web. Que faut-il changer pour quesrv-recettereçoive les deux ? Donne la commande qui applique la configuration à la seule VM de recette. - Comment prouves-tu à Antoine que la configuration est idempotente et que rien n'a changé sur
srv-web? - Le certificat TLS du site de recette doit venir de l'AC interne. Où ranges-tu sa clé privée dans le dépôt, et comment ?
- La commission de l'E6 te demande : « Pourquoi ne pas avoir simplement copié la configuration de
srv-webà la main ? » Réponds en quelques phrases.
Voir la réponseMasquer la réponse de l'exercice 7
- Dans
inventaire/hosts.yml, ajoutersrv-recetteaux groupes concernés :
serveurs_web:
hosts:
srv-web:
ansible_host: 192.168.10.225
srv-recette:
ansible_host: 192.168.21.186
Comme serveurs_web est un enfant de linux, srv-recette est aussi dans linux. Puis inventaire/host_vars/srv-recette.yml :
---
web_nom_site: suivi-recette.sorbier.example
web_racine: /var/www/suivi-recette
web_certificat: /etc/ssl/certs/suivi-recette.sorbier.example.pem
web_cle_privee: /etc/ssl/private/suivi-recette.sorbier.example.key
Une organisation plus propre, à terme, sépare les environnements dans deux inventaires (inventaire/recette/ et inventaire/production/, chapitre 15).
- Sur un contrôleur de domaine,
srv-ad(la zone est répliquée par l'annuaire) :
- name: Déclarer l'alias du site de recette
hosts: srv-ad
tasks:
- name: Créer l'alias suivi-recette
ansible.windows.win_dns_record:
name: suivi-recette
type: CNAME
value: srv-recette.ad.sorbier.example
zone: ad.sorbier.example
state: present
Attention : suivi-recette.sorbier.example est dans la zone sorbier.example, pas dans ad.sorbier.example. Si le DNS interne ne porte pas la zone sorbier.example, il faut soit créer l'enregistrement dans cette zone là où elle est hébergée, soit nommer le site suivi-recette.ad.sorbier.example. C'est le genre de détail que la commission apprécie de te voir relever.
-
Rien dans
site.yml: il vise des groupes, etsrv-recetteest maintenant dans les deux. Pour l'appliquer à la seule recette :ansible-playbook site.yml --limit srv-recette. -
Deux exécutions de suite sur la recette : la seconde affiche
changed=0poursrv-recettedans le récapitulatif. Pour la production :ansible-playbook site.yml --limit srv-web --check --diff, qui doit annoncerchanged=0; et le diff Git de la demande de fusion montre que seuls l'inventaire ethost_vars/srv-recette.ymlont changé. Le pipeline vert (--syntax-checketansible-lint) complète la preuve. -
La clé privée est un secret : elle va dans un fichier chiffré, par exemple
inventaire/host_vars/srv-recette/vault.yml(avec les autres variables danshost_vars/srv-recette/vars.yml), sous forme de variable multilignevault_cle_tls_recette, chiffrée paransible-vault. Une tâcheansible.builtin.copyaveccontent: "{{ vault_cle_tls_recette }}",mode: "0600"etno_log: truela dépose sur le serveur. Le certificat, public, peut rester en clair dansfiles/. -
« Une copie à la main donne un serveur identique le jour de la copie, mais rien ne garantit qu'il le reste, ni que la copie était complète. Avec Ansible, la recette et la production sont construites par le même code, avec des variables différentes : ce que je teste en recette est exactement ce qui sera appliqué en production. Chaque modification est tracée dans Git, relue et contrôlée par le pipeline, et je peux reconstruire la recette en quelques minutes si la VM est perdue. Enfin, relancer le playbook corrige toute dérive : la deuxième exécution qui n'affiche aucun changement le prouve. »
Tu avais trouvé ?