Les modules Ansible raw, command et shell
Mise à jour :
Pour garantir des opérations stables et fiables, Ansible repose sur un principe fondamental : l’idempotence. Cela signifie qu’une tâche exécutée plusieurs fois doit produire le même résultat, sans modifier l’état du système si celui-ci est déjà conforme.
L’outil Ansible propose
une large palette de modules dédiés pour gérer les paquets, configurer des
services, manipuler des fichiers, … Ces modules, comme apt
pour installer
des logiciels sur un système basé sur Debian ou
copy
pour transférer des fichiers, sont conçus pour assurer l’idempotence. Cela
signifie que si vous demandez d’installer un paquet déjà présent sur un serveur,
Ansible ne tentera pas de le réinstaller, évitant ainsi des changements
superflus ou des comportements indésirables.
Cependant, il arrive que vous deviez exécuter des commandes personnalisées
sur un hôte distant, notamment dans des cas spécifiques où aucun module Ansible
dédié n’existe. C’est là qu’interviennent les modules raw
, command
, et
shell
, qui permettent d’exécuter des commandes directement sur les systèmes
cibles. Bien qu’efficaces, ces modules ne garantissent pas l’idempotence.
Ils exécutent simplement la commande demandée, peu importe l’état initial du
système. De ce fait, ils doivent être utilisés avec précaution et en dernier
recours.
Dans ce guide, je vais détailler l’utilisation des modules raw
, command
et
shell
, en expliquant leurs différences, leurs cas d’usage et leurs limites.
Vous comprendrez dans quels scénarios ils sont nécessaires et comment les
utiliser efficacement pour éviter les mauvaises pratiques dans vos codes
Ansible.
Le module raw
: L’exécution brute sans interprétation Python
Le module raw
est le plus basique et le plus direct des trois modules que nous
allons explorer. Contrairement aux modules command
et shell
, qui font appel
à des interpréteurs , le module raw
exécute des commandes brutes sur
l’hôte cible. Il envoie directement la commande via SSH, sans aucune
transformation ou interprétation par Ansible. C’est donc le module de dernier
recours, souvent utilisé lorsque l’infrastructure ne dispose pas encore des
prérequis nécessaires au bon fonctionnement des autres modules, notamment
Python.
Par exemple, si vous administrez un routeur ou un système embarqué où
Python n’est pas disponible et que vous souhaitez exécuter une commande basique,
le module raw
vous permet d’envoyer directement cette commande sans vous
soucier de l’installation de dépendances.
Malgré sa flexibilité, le module raw
présente plusieurs inconvénients
importants qui limitent son utilisation à des scénarios très spécifiques :
-
Absence de structuration des résultats : Contrairement aux autres modules Ansible, qui renvoient des résultats sous forme de dictionnaires structurés, le module
raw
renvoie simplement la sortie brute de la commande exécutée. Cela peut rendre l’analyse des résultats plus complexe, surtout si vous devez gérer les erreurs ou interpréter des données complexes. -
Sécurité limitée : Le module
raw
exécute des commandes directement sur le système sans passer par le shell, ce qui peut comporter des risques. Il n’y a pas de contrôle spécifique sur la commande envoyée, ni de protection contre des attaques d’injection de commandes. Il est donc primordial de bien valider les commandes exécutées pour éviter tout comportement imprévu ou dangereux.
Le module command
: Exécution simple sans shell
Le module command
est l’un des modules les plus simples d’Ansible. Il permet
d’exécuter des commandes basiques directement sur un hôte distant, mais sans
utiliser de shell. Contrairement au module shell
, qui exécute des commandes
via un interpréteur de shell (comme Bash), command
ne prend pas en charge des
fonctionnalités avancées comme les redirections (>
), les pipes (|
), ou les
chaînes de commandes multiples (&&
). Cette simplicité en fait un module plus
sûr, car il évite les risques associés à l’exécution de commandes complexes via
un shell.
Le module command
est particulièrement adapté pour les tâches qui nécessitent
l’exécution de commandes simples et non interactives. Par exemple, il peut
être utilisé pour exécuter des scripts. Comme il n’utilise pas de shell, il est
à privilégier lorsque vous avez besoin d’exécuter une commande sans manipulation
avancée et que la sécurité est une préoccupation, car il ne permet pas
l’exécution de scripts complexes ni l’utilisation de caractères spéciaux pouvant
représenter un risque d’injection.
Limites du module command
Bien que le module command
soit simple et sûr, il présente également certaines
limitations :
- Pas de gestion des redirections et pipes : Comme mentionné précédemment,
command
ne permet pas l’utilisation de redirections (>
,>>
), de pipes (|
), ou de chaînes de commandes (&&
). Si vous avez besoin de combiner plusieurs commandes ou de rediriger les sorties vers un fichier, vous devrez utiliser le moduleshell
.
Le module shell
: Exécution de commandes via un shell
Le module shell
d’Ansible est le plus flexible des trois modules que nous
explorons. Contrairement à command
, qui se limite à l’exécution de commandes
simples sans shell, shell
permet d’exécuter des commandes via l’interpréteur
de commandes natif de l’hôte distant (comme Bash ou sh). Cela signifie
que vous pouvez utiliser des fonctionnalités avancées du shell, telles que les
redirections de sortie, les pipes et la chaîne de commandes avec des
opérateurs logiques comme &&
ou ||
.
Le module shell
est particulièrement adapté aux situations où vous devez
exécuter des commandes complexes nécessitant un shell pour interpréter des
symboles spécifiques comme les pipes (|
), les redirections (>
, >>
), ou
pour exécuter plusieurs commandes en séquence avec des opérateurs comme &&
(si
la première commande réussit, la seconde est exécutée). Cela le rend très utile
pour des scripts complexes ou des commandes qui manipulent plusieurs flux de
données ou fichiers simultanément.
Limites du module shell
Malgré sa puissance, le module shell
comporte des risques et des
limitations qu’il est important de bien comprendre avant de l’utiliser dans
vos playbooks
Ansible.
-
Risques de sécurité : En utilisant le module
shell
, vous ouvrez la porte à des risques de sécurité supplémentaires, notamment les injections de commandes. Comme le shell interprète directement les commandes que vous envoyez, des variables ou des entrées non contrôlées peuvent mener à des exécutions inattendues ou dangereuses. Il est donc indispensable de bien valider et de limiter les commandes passées viashell
. -
Performance : L’utilisation du shell pour chaque commande peut entraîner une légère perte de performance, car le système doit lancer une nouvelle instance de shell à chaque exécution. Dans des environnements à grande échelle, cette surcharge peut s’accumuler, surtout si le module est utilisé de manière répétée.
Le module ansible.builtin.script
: transférer puis exécuter un script local
Le module script
permet d’envoyer un fichier script présent sur votre
poste de contrôle vers l’hôte distant puis de l’exécuter via le shell natif de
la cible.
Exemples :
# 1. Lancer un script Bash avec argument et idempotence via 'creates'- name: Initialiser la base si elle n’existe pas ansible.builtin.script: files/init_db.sh --env prod args: creates: /var/lib/app/db.sqlite
# 2. Utiliser un interpréteur spécifique- name: Exécuter un script Python en passant par python3 ansible.builtin.script: cmd: scripts/collect_metrics.py --json executable: python3
# 3. Changer de répertoire avant exécution- name: Lancer le script dans /opt/tools ansible.builtin.script: cmd: maintenance.sh chdir: /opt/tools
Les paramètres du module ansible.builtin.script
:
Le module ansible.builtin.script
accepte les paramètres suivants :
cmd
: La commande à exécuter.creates
: Un fichier ou un répertoire qui doit exister pour que la commande soit exécutée.removes
: Un fichier ou un répertoire qui doit exister pour que la commande soit exécutée.chdir
: Le répertoire dans lequel exécuter la commande.executable
: Le chemin vers l’interpréteur à utiliser pour exécuter la commande.
Gérer l’idempotence avec creates
et removes
Pour pallier l’absence d’idempotence, les modules command
permet de
spécifier des conditions sous forme de fichiers ou de répertoires existants avec
les options creates
et removes
. Par exemple, vous pouvez utiliser l’option
creates
pour indiquer qu’une commande ne doit être exécutée que si un certain
fichier n’existe pas encore.
Exemple avec creates
:
- name: Extraire une archive seulement si le fichier n'existe pas ansible.builtin.command: cmd: tar xzf archive.tar.gz creates: /path/to/extracted/file
Dans cet exemple, la commande tar
sera exécutée uniquement si le fichier
/path/to/extracted/file
n’existe pas encore. Cela permet de rendre la tâche
plus idempotente, en évitant d’extraire l’archive plusieurs fois.
De même, l’option removes
peut être utilisée pour indiquer qu’une commande
doit être exécutée seulement si un fichier ou un répertoire spécifique est
présent et qu’il doit être supprimé après l’exécution de la commande.
Exemple avec removes
:
- name: Supprimer un fichier après l'exécution d'une commande ansible.builtin.command: cmd: rm /tmp/tempfile removes: /tmp/tempfile
Dans cet exemple, Ansible exécutera la commande rm
pour supprimer le fichier
/tmp/tempfile
uniquement si ce fichier existe, ce qui ajoute une condition
simple mais efficace à l’exécution de la tâche.
Gestion des status changed
et failed
Un point important, les modules shell
et command
s’il ne plante pas retourne
toujours le status changed. Pour définir réellement quand une commande échoue ou
change quelque chose sur le système, vous devez utiliser les instructions
changed_when
et failed_when
.
Exemple de gestion des erreurs avec register
et failed_when
:
- name: Exécuter une commande et capturer le résultat ansible.builtin.shell: "cat /var/log/syslog" register: result
- name: Vérifier si la commande a échoué ansible.builtin.debug: msg: "La commande a échoué avec le message : {{ result.stderr }}" failed_when: result.rc != 0
Dans cet exemple, la commande cat
est utilisée pour lire le fichier de logs
système et le résultat est capturé dans la variable result
. Si la commande
échoue (par exemple, si le fichier n’existe pas), Ansible affiche le message
d’erreur renvoyé par la commande via result.stderr
.
Conclusion
Dans ce guide, nous avons exploré en détail les modules Ansible raw
, command
et shell
, en mettant en lumière leurs cas d’utilisation, leurs avantages,
ainsi que leurs limites. Ces modules permettent d’exécuter des commandes sur des
hôtes distants, mais ils ne garantissent pas l’idempotence, une propriété
clé pour maintenir la stabilité et la répétabilité des actions dans un
environnement automatisé.
Le module raw
est à utiliser en dernier recours, principalement sur des
systèmes dépourvus de Python. Le module command
est idéal pour des tâches
simples et sûres, mais sans la flexibilité des commandes shell. Enfin, le module
shell
offre une grande liberté, avec la possibilité de manipuler des flux
complexes et de chaîner des commandes, mais il introduit des risques accrus en
termes de sécurité et d’absence d’idempotence.
En maîtrisant l’utilisation de raw
, command
et shell
, vous pourrez gérer
des tâches spécifiques et complexes dans vos playbooks Ansible, tout en veillant
à maintenir un environnement sécurisé et stable.