
Cette page condense en une seule lecture tout ce qu'il faut avoir en tête le jour de l'EX294. Commandes ansible-*, modules essentiels par catégorie, ansible.cfg minimal, syntaxes Vault, FQCN, pièges YAML qui font perdre des points. À lire la veille de l'examen et à garder ouverte pendant les mocks (lab rhce/mock-ex294).
L'EX294 est performance-based : aucun QCM, vous écrivez des playbooks sur un environnement RHEL/AlmaLinux live. Le score se calcule sur des objectifs vérifiés automatiquement. Un playbook qui ne passe pas l'objectif = 0 sur cet objectif. Pas de point partiel.
Tableau "besoin → commande"
Section intitulée « Tableau "besoin → commande" »Ce tableau se lit par la colonne de gauche : en examen, on part d'un besoin
formulé dans l'énoncé, jamais d'un nom de commande. Les lignes ansible-vault
et ansible-galaxy sont les plus vite oubliées, parce qu'elles ne servent
qu'une ou deux fois sur les quatre heures. Les options --check, --limit et
--tags ne rapportent aucun point par elles-mêmes, mais elles réduisent le
temps de vérification d'une tâche déjà écrite : c'est là que se gagne la
marge finale.
| Besoin | Commande |
|---|---|
| Tester la connexion Ansible | ansible all -m ansible.builtin.ping |
| Lister inventaire | ansible-inventory --graph |
| Voir variables d'un host | ansible-inventory --host db1.lab |
| Doc d'un module | ansible-doc ansible.builtin.copy |
| Lister tous les modules d'une collection | ansible-doc -l community.general |
| Lancer un playbook | ansible-playbook -i inventory.yml site.yml |
| Mode dry-run | ansible-playbook --check --diff site.yml |
| Limiter à un host | ansible-playbook --limit web1.lab site.yml |
| Filtrer par tags | ansible-playbook --tags config site.yml |
| Vault encrypt fichier | ansible-vault encrypt secret.yml |
| Vault encrypt variable inline | ansible-vault encrypt_string 'value' --name 'key' |
| Vault edit | ansible-vault edit secret.yml |
| Vault rekey | ansible-vault rekey secret.yml |
| Lancer playbook avec vault | ansible-playbook --vault-password-file=.vault_pass site.yml |
| Inspecter config active | ansible-config dump --only-changed |
| Lister tâches sans exécuter | ansible-playbook --list-tasks site.yml |
| Lister hosts ciblés | ansible-playbook --list-hosts site.yml |
| Lint qualité production | ansible-lint --profile production site.yml |
| Installer collection | ansible-galaxy collection install -r requirements.yml |
| Installer rôle Galaxy | ansible-galaxy role install geerlingguy.docker |
ansible.cfg minimal pour l'examen
Section intitulée « ansible.cfg minimal pour l'examen »Ce fichier se pose avant même la lecture complète des tâches. Chaque ligne
supprime une perte de temps identifiée : host_key_checking = False évite les
invites de validation de clé SSH sur des hôtes fraîchement provisionnés,
become = True dispense d'écrire become: dans chaque play, et
callback_result_format = yaml rend les erreurs lisibles au lieu d'une ligne
JSON compacte. roles_path et collections_path pointent vers le répertoire de
travail : sans eux, un rôle créé pour une tâche ne sera pas trouvé par le
playbook de la tâche suivante.
[defaults]inventory = inventory/hosts.ymlremote_user = ansiblehost_key_checking = Falseroles_path = ./rolescollections_path = ./collectionsforks = 10callback_result_format = yamldeprecation_warnings = False
[privilege_escalation]become = Truebecome_method = sudobecome_user = root
[ssh_connection]pipelining = TrueÀ placer dans le répertoire de travail au début de l'examen, précédence locale > home > /etc.
Modules essentiels par catégorie EX294
Section intitulée « Modules essentiels par catégorie EX294 »Les tâches de l'examen sont formulées en langage naturel : « assurez-vous que le
service démarre au boot », « créez un utilisateur avec l'UID 2001 ». Le premier
geste consiste à traduire cette phrase en module, et c'est là que le temps
se perd quand l'inventaire mental est flou. Les tableaux qui suivent regroupent
les modules par domaine et les donnent sous leur FQCN complet : écrire
ansible.builtin.copy plutôt que copy supprime toute ambiguïté quand deux
collections exposent un module de même nom.
Fichiers et templates
Section intitulée « Fichiers et templates »Le choix se joue sur la portée de l'écriture : copy et template produisent
le fichier entier, lineinfile et blockinfile modifient un fichier existant.
Dès qu'un énoncé mentionne une valeur issue d'une variable, la réponse
attendue est template avec un fichier .j2.
| Module | Usage type |
|---|---|
ansible.builtin.copy | Déposer un fichier (avec content: ou src:) |
ansible.builtin.template | Déposer fichier paramétré Jinja2 (src: file.j2) |
ansible.builtin.file | État d'un fichier/dossier (state: directory|absent|touch) |
ansible.builtin.lineinfile | Une seule ligne dans un fichier (regexp: obligatoire) |
ansible.builtin.blockinfile | Bloc de lignes (marker: configurable) |
ansible.builtin.fetch | Récupérer un fichier de la cible vers le control node |
community.general.archive / ansible.builtin.unarchive | tar.gz, zip |
Paquets et services
Section intitulée « Paquets et services »Sur un service, le point noté est presque toujours double : state: started
pour l'exécution immédiate et enabled: true pour le démarrage au boot. Un
énoncé qui précise « et au redémarrage » vérifie explicitement le second.
| Module | Usage |
|---|---|
ansible.builtin.dnf | RHEL/AlmaLinux paquets (name:, state: present|latest|absent) |
ansible.builtin.systemd_service | Activer + démarrer (state: started, enabled: true) |
ansible.builtin.cron | Tâche planifiée |
Utilisateurs et groupes
Section intitulée « Utilisateurs et groupes »Le paramètre password: du module user attend un hash, jamais un mot de
passe en clair : il se produit avec le filtre password_hash('sha512').
Attention aussi au FQCN, authorized_key vient de ansible.posix et
sudoers de community.general, ce ne sont pas des modules ansible.builtin.
| Module | Usage |
|---|---|
ansible.builtin.user | Créer user (name:, uid:, group:, shell:, password:) |
ansible.builtin.group | Créer group (name:, gid:) |
ansible.posix.authorized_key | Déposer clé SSH (user:, key:) |
community.general.sudoers | Règle sudo dédiée |
RHEL spécifique (incontournable EX294)
Section intitulée « RHEL spécifique (incontournable EX294) »C'est la catégorie qui distingue l'EX294 d'un examen Ansible générique. Deux
réflexes à garder : firewalld demande permanent: true et immediate: true
ensemble, sinon la règle disparaît au redémarrage ou ne s'applique pas tout
de suite ; les modules SELinux et LVM exigent des paquets Python côté
cible, à installer dans une tâche préalable.
| Module | Usage |
|---|---|
ansible.posix.firewalld | permanent: true, immediate: true |
ansible.posix.seboolean | Activer un booléen SELinux (state: true, persistent: true) |
ansible.builtin.sefcontext (community.general) | Contexte SELinux |
community.general.lvol | Créer un LV |
community.general.filesystem | Formater (xfs, ext4) |
ansible.posix.mount | Monter + fstab |
Diagnostic et contrôle
Section intitulée « Diagnostic et contrôle »command et shell sont les seuls modules non idempotents de cette liste :
ils rapportent changed à chaque passage et font échouer la vérification du
second run, d'où le changed_when: false obligatoire sur toute lecture.
assert sert à contrôler soi-même l'état obtenu avant la fin du temps imparti.
| Module | Usage |
|---|---|
ansible.builtin.command / shell | Commandes (changed_when: false pour lecture) |
ansible.builtin.assert | Vérification d'une condition |
ansible.builtin.fail | Échec explicite |
ansible.builtin.debug | Affichage de variables (var: ou msg:) |
ansible.builtin.uri | HTTP request |
ansible.builtin.wait_for | Attendre un port / état |
Syntaxes critiques à connaître
Section intitulée « Syntaxes critiques à connaître »Ces sept formes ne s'improvisent pas sous chronomètre. Elles ont en commun
d'être des syntaxes exactes : un guillemet ou un deux-points de travers, et
la tâche ne s'exécute pas, ou s'exécute en produisant un état différent de celui
attendu. Les relire la veille est plus rentable que de réviser un module de
plus, car un module inconnu se retrouve avec ansible-doc pendant l'épreuve,
alors qu'une erreur de syntaxe silencieuse ne se voit qu'à la correction.
mode: toujours quoté
Section intitulée « mode: toujours quoté »Sans guillemets, la valeur est laissée à l'interprétation du parseur YAML,
et un mode: 644 écrit sans zéro initial part en décimal vers des
permissions incohérentes, sans le moindre message d'erreur. Quoter supprime
cette dépendance : "0644" désigne toujours le même mode.
mode: "0644" # ← TOUJOURS quoté : un 644 sans zéro donnerait 0o1204become: au niveau task ou play
Section intitulée « become: au niveau task ou play »Deux niveaux coexistent et le plus proche l'emporte : un become_user posé sur
une tâche prend le pas sur le become du play. C'est la façon d'écrire
un fichier au nom d'un compte applicatif dans un play qui tourne par ailleurs
en root ; sans become: true sur la tâche, become_user reste sans effet.
- name: Déployer la configuration applicative hosts: db1.lab become: true # ← niveau play : toutes les tâches en sudo tasks: - name: Poser le fichier de configuration au nom du compte applicatif ansible.builtin.copy: src: app.cfg dest: /opt/app/app.cfg mode: "0640" become: true become_user: appuser # ← override niveau taskregister: + when:
Section intitulée « register: + when: »Une variable enregistrée n'est pas une chaîne mais un dictionnaire exposant
stdout, stderr, rc et changed, d'où les suffixes de l'exemple. Un
when: qui teste la variable sans suffixe est toujours vrai, puisque le
dictionnaire n'est jamais vide : il faut viser .rc ou .stdout.
- name: Relever la version de l'application ansible.builtin.command: /usr/local/bin/myapp --version register: app_version changed_when: false # ← lecture seule, pas idempotent
- name: Afficher la version relevée ansible.builtin.debug: var: app_version.stdout when: app_version.rc == 0Boucles loop:
Section intitulée « Boucles loop: »loop remplace les anciennes formes with_* et expose chaque élément dans
item, adressable par item.name quand l'élément est un dictionnaire. Le
loop_control avec label n'est pas cosmétique en examen : sans lui, une
boucle sur des variables volumineuses noie la sortie et rend la relecture
des erreurs impraticable.
- name: Gérer le compte système ansible.builtin.user: name: "{{ item.name }}" uid: "{{ item.uid }}" loop: - { name: alice, uid: 2001 } - { name: bob, uid: 2002 } loop_control: label: "{{ item.name }}" # ← masque le contenu détaillé en sortieConditions when: avec opérateurs
Section intitulée « Conditions when: avec opérateurs »Une liste sous when: vaut un ET logique entre toutes les lignes, ce qui
dispense d'écrire and. Le filtre | int de la deuxième ligne est
indispensable : distribution_major_version est une chaîne, et la comparer
à un nombre lève une erreur de type au lieu de renvoyer un booléen.
when: - ansible_facts.os_family == "RedHat" - ansible_facts.distribution_major_version | int >= 9 - inventory_hostname in groups['webservers']Vault inline avec encrypt_string
Section intitulée « Vault inline avec encrypt_string »encrypt_string chiffre une valeur unique au lieu d'un fichier entier, ce
qui laisse le reste des variables lisible. La sortie se colle telle quelle dans
un fichier de variables : le marqueur !vault et le bloc indenté qui suit
font partie de la syntaxe et ne se réalignent pas.
ansible-vault encrypt_string 'SuperSecret' --name 'admin_password'admin_password: !vault | $ANSIBLE_VAULT;1.1;AES256 39373335366336323033666336323535...Multi vault-id par environnement
Section intitulée « Multi vault-id par environnement »Chaque --vault-id associe une étiquette à un fichier de mot de passe.
L'étiquette est inscrite dans l'en-tête du contenu chiffré, ce qui permet à
Ansible d'essayer en priorité la bonne clé et de faire cohabiter dans un même
dépôt des secrets de développement et de production.
ansible-playbook --vault-id dev@.vault_pass_dev --vault-id prod@.vault_pass_prod site.ymlPriorité des variables (descendante, RHCE objectif explicite)
Section intitulée « Priorité des variables (descendante, RHCE objectif explicite) »Cet ordre tombe rarement en question directe : il se présente sous forme d'une
tâche qui définit la même variable à deux endroits et attend une valeur précise.
Les deux extrémités sont les seules à connaître par cœur, --extra-vars gagne
toujours, defaults/main.yml perd toujours. Entre les deux, le couple à
retenir est celui d'un même rôle : vars/main.yml ne peut pas être surchargé
par un group_vars, alors que defaults/main.yml le peut. C'est ce qui décide
où placer une valeur que l'inventaire doit pouvoir modifier.
--extra-vars(CLI), prioritaire absolue- Block vars
- Task vars
include_varsset_fact/ registered vars- Play vars (
vars:) vars/main.ymld'un rôle- Host facts
host_vars/group_vars/(du plus spécifique au plus général)defaults/main.ymld'un rôle, prioritaire la plus basse- Command line role default
Mémoire pratique : --extra-vars écrase tout le reste. defaults/main.yml se fait écraser par tout le reste.
Structure d'un rôle conforme
Section intitulée « Structure d'un rôle conforme »La notation vérifie le comportement du rôle, pas son arborescence, mais cette
structure reste payante pour une raison précise : chaque répertoire porte une
sémantique de recherche. Un fichier déposé dans files/ est trouvé par
copy: sans indiquer de chemin, un .j2 placé dans templates/ est trouvé par
template: de la même façon. Se tromper de répertoire produit une erreur de
fichier introuvable pénible à diagnostiquer sous chronomètre. La commande
ansible-galaxy role init génère l'ensemble en une fois.
roles/myrole/├── defaults/main.yml # variables par défaut (faible précédence)├── vars/main.yml # variables internes (haute précédence)├── tasks/main.yml # tâches principales├── handlers/main.yml # handlers (notifiés par notify:)├── templates/ # *.j2├── files/ # fichiers à copy:├── meta/main.yml # dependencies, supported_platforms└── meta/argument_specs.yml # validation des inputs (Ansible 2.11+)Pièges YAML qui font perdre des points
Section intitulée « Pièges YAML qui font perdre des points »Ces pièges se répartissent en deux familles d'inégale gravité. Les erreurs de
syntaxe YAML, comme un name: qui se termine par deux-points, arrêtent le
playbook avec un message explicite et se corrigent en une minute. Les autres
coûtent bien plus cher : un permanent: true oublié sur firewalld laisse
l'exécution se terminer en ok, alors que la règle disparaîtra au redémarrage.
L'état final ne correspond pas à l'attendu et l'objectif est noté zéro,
sans qu'aucune ligne de la sortie n'ait signalé quoi que ce soit.
| Erreur | Conséquence |
|---|---|
mode: 644 (sans zéro initial) | YAML lit 644 en décimal, soit 0o1204 en octal : permissions silencieusement fausses. Toujours mode: "0644" |
name: Migration with_* vers loop: (terminé par :) | YAML 1.2 lit comme mapping. Quoter : name: "..." |
dnf: state=present name=httpd (vieux style) | Toujours YAML structuré : dnf: { state: present, name: httpd } ou multi-ligne |
Oublier permanent: true sur firewalld | Règle non persistante après reboot, permanent: true, immediate: true systématique |
Oublier python3-libselinux côté cible | template:/copy: plantent si SELinux=enforcing |
name: Démarrer httpd: finit par : | YAML mapping, quoter |
Confondre import_* (static) et include_* (dynamic) | Tags/conditions ne se propagent pas pareillement, voir Import vs Include |
Stratégie d'examen 4h chrono
Section intitulée « Stratégie d'examen 4h chrono »Ce découpage découle d'une contrainte du format : chaque objectif est noté séparément et il n'existe pas de point partiel. Terminer huit tâches simples rapporte donc davantage que d'en entamer quinze. D'où l'ordre proposé, lecture intégrale de l'énoncé, puis les tâches rapides, puis les longues. La demi-heure de marge finale n'est pas du confort : elle absorbe la tâche qui refuse de passer et qu'il faut reprendre depuis le début.
| Étape | Temps | Action |
|---|---|---|
| Lecture des consignes | 5-10 min | Lire les 12-15 tâches en entier avant d'écrire une ligne |
Setup ansible.cfg + inventaire | 5-10 min | Poser le ansible.cfg minimal + tester ansible all -m ping |
| Tâches faciles | 1h | Faire les 8-9 tâches simples d'abord (validation rapide) |
| Tâches complexes | 1h30 | Rôles, Vault, SELinux, LVM/XFS, les plus longues |
| Vérification | 30 min | Re-lancer chaque playbook, vérifier l'idempotence (changed=0 au 2e run) |
| Buffer | 30 min | Marge pour les pièges de dernière minute |
Règle d'or : vérifier au fur et à mesure. Ne pas attendre la fin pour relancer tous les playbooks, un bug détecté à la 4e heure coûte 30 min de panique.
Vérification systématique en fin d'examen
Section intitulée « Vérification systématique en fin d'examen »La vérification porte sur deux propriétés distinctes. L'idempotence d'abord :
un second passage doit afficher changed=0, faute de quoi la tâche modifie
l'état à chaque exécution. L'état réel de la cible ensuite, contrôlé par des
commandes ad hoc et non en relisant son propre playbook, ce qui reviendrait à
vérifier une intention plutôt qu'un résultat. Les modules systemd_service,
stat et command en mode ad hoc interrogent la machine sans rien y modifier.
# Pour chaque playbookansible-playbook playbook.yml # 1er runansible-playbook playbook.yml | grep -E 'changed=[1-9]' # 2e run : doit être vide
# Vérifier qu'un service est bien actif après rebootansible <host> -m ansible.builtin.systemd_service -a 'name=httpd' -b# → "ActiveState": "active"# → "UnitFileState": "enabled"
# Vérifier un fichier déposéansible <host> -m ansible.builtin.stat -a 'path=/tmp/file.txt' -b
# Vérifier un useransible <host> -m ansible.builtin.command -a 'id appuser' -bRessources d'urgence pendant l'examen
Section intitulée « Ressources d'urgence pendant l'examen »Aucun accès internet n'est fourni, mais la documentation locale est complète
et autorisée. Savoir la parcourir vite est un acquis à travailler avant le jour
J : ansible-doc affiche les paramètres d'un module et, en fin de sortie, des
exemples directement copiables. C'est le réflexe qui remplace la recherche
web, à condition d'être déjà familier de son format de sortie.
ansible-doc <module>, la doc complète est embarquée dans l'EE de l'examen.ansible-doc -l | grep <mot>, retrouver le FQCN d'un module par mot-clé.man ansible-playbook, options CLI rapides./usr/share/doc/ansible*/, docs locales sur RHEL.
L'examen vous autorise la documentation locale (ansible-doc, man). Aucun accès internet.
À retenir
Section intitulée « À retenir »- Performance-based : on écrit des playbooks. Pas de QCM.
ansible.cfgprojet en premier, précédence locale > home > /etc.- FQCN systématique :
ansible.builtin.copy, jamaiscopy. mode:toujours quoté ("0644").changed_when: falsesur toute commande de lecture.firewalld:permanent: true, immediate: true.python3-libselinuxcôté cible si SELinux enforcing.- Vérifier l'idempotence : 2e run doit avoir
changed=0. ansible-docest votre meilleur ami pendant l'examen.
Pour aller plus loin
Section intitulée « Pour aller plus loin »- Workflow VS Code et Dev Container : l'environnement dans lequel ces commandes seront réellement tapées le jour de l'examen.
- Doc pendant l'examen : ce que le mémo ne contient pas se trouve dans
ansible-doc, encore faut-il savoir chercher vite. - Versionner ses playbooks avec Git : les quelques commandes Git attendues à l'EX294, absentes des commandes
ansible-*.