Aller au contenu
Infrastructure as Code medium

Module Ansible lineinfile : modifier une ligne dans un fichier existant

11 min de lecture

Logo Ansible

Le module ansible.builtin.lineinfile modifie une seule ligne dans un fichier existant : ajouter si absente, remplacer une ligne matchant une regexp, ou supprimer. C'est l'outil de base pour éditer un fichier de configuration dont on contrôle juste quelques paramètres — sshd_config, sudoers, /etc/hosts, /etc/sysctl.conf. Public visé : débutants et intermédiaires Ansible. Cette page couvre les 4 cas d'usage (ajouter, remplacer, supprimer, valider), les pièges classiques (regexp ancrée vs non-ancrée, idempotence cassée), et les alternatives quand lineinfile n'est pas le bon outil (blockinfile, template, replace).

  • Ajouter une ligne dans un fichier si elle n'y est pas déjà.
  • Remplacer une ligne matchant une regexp par une nouvelle valeur.
  • Supprimer une ligne identifiée par regexp.
  • Utiliser validate: pour ne jamais écrire un fichier de config syntaxiquement cassé.
  • Reconnaître quand lineinfile n'est pas le bon outil (et préférer template, blockinfile, replace).
  • Connaissance de base d'Ansible (cf. Premiers pas).
  • Notions de regex POSIX étendueslineinfile utilise du regex Python style.
  • Un nœud cible avec un fichier de config simple à modifier (Linux).

Le cas le plus simple — ajouter une ligne si absente

Section intitulée « Le cas le plus simple — ajouter une ligne si absente »

C'est l'usage par défaut quand on ne précise ni regexp ni state :

- name: Activer le forwarding IPv4 dans sysctl
ansible.builtin.lineinfile:
path: /etc/sysctl.conf
line: "net.ipv4.ip_forward=1"
state: present
create: false

Comportement :

  • Si la ligne net.ipv4.ip_forward=1 est déjà dans le fichier (matching exact) → ok (rien à faire).
  • Sinon → la ligne est ajoutée à la fin du fichier.

create: false (défaut) refuse de créer le fichier s'il n'existe pas — task échoue. Mettre create: true pour qu'Ansible crée le fichier s'il manque.

Le pattern idiomatique pour modifier un paramètre de config :

- name: Désactiver le login root SSH
ansible.builtin.lineinfile:
path: /etc/ssh/sshd_config
regexp: '^\s*#?\s*PermitRootLogin\s'
line: "PermitRootLogin no"
state: present
validate: "sshd -t -f %s"
notify: Restart sshd

Logique :

  • regexp identifie la ligne à remplacer — ici toute ligne qui commence par PermitRootLogin (avec ou sans # de commentaire, espaces optionnels).
  • Si la regexp matche une ligne existante → cette ligne est remplacée par la valeur de line.
  • Si aucune ligne ne matche → la ligne est ajoutée à la fin du fichier.
  • validate: "sshd -t -f %s" lance sshd -t -f /tmp/<temp> sur le fichier candidat avant de l'écrire en place. Si la validation échoue, le fichier original n'est pas touché.

%s est remplacé par le chemin temporaire qu'Ansible utilise pour le fichier candidat — pas le chemin du fichier final. C'est mandatory pour les configs critiques (sshd, sudoers, nginx, postgres) où une faute de frappe peut tout casser.

Validation par module — le tableau des configs critiques

Section intitulée « Validation par module — le tableau des configs critiques »
FichierValidate à utiliser
/etc/ssh/sshd_configsshd -t -f %s
/etc/sudoers ou /etc/sudoers.d/*visudo -cf %s
/etc/nginx/nginx.conf ou vhostnginx -t -c %s
/etc/httpd/conf/httpd.confhttpd -t -f %s (Apache RHEL)
/etc/named.confnamed-checkconf %s
/etc/postgresql/main/pg_hba.conf(pas de validateur natif — vérifier après reload)
/etc/cron.d/*(pas de validateur — crontab -T côté user)

Sur tout fichier de config qui peut casser un service, l'omission de validate: est une erreur qui peut sortir le serveur d'accès distant — règle non négociable du pilier Security du WAF.

Pour enlever une ligne, mettre state: absent. Le regexp identifie la ligne ; line n'est pas requis.

- name: Retirer une ligne d'allowlist obsolète dans /etc/hosts.allow
ansible.builtin.lineinfile:
path: /etc/hosts.allow
regexp: '^sshd:\s+192\.168\.42\.\d+'
state: absent

Si plusieurs lignes matchent la regexp, toutes sont supprimées. Si aucune ne matche, la task est ok (idempotent).

Cas n°4 — backrefs pour préserver une partie de la ligne

Section intitulée « Cas n°4 — backrefs pour préserver une partie de la ligne »

Quand vous voulez modifier une seule valeur dans une ligne mais conserver le reste tel quel (espaces, commentaires…), utilisez backrefs: true + groupes de capture dans la regexp :

- name: Augmenter MaxAuthTries SSH sans toucher au reste de la ligne
ansible.builtin.lineinfile:
path: /etc/ssh/sshd_config
regexp: '^(\s*MaxAuthTries\s+).*$'
line: '\g<1>3'
backrefs: true
validate: "sshd -t -f %s"

Comportement avec backrefs: true :

  • Si la regexp matche → ligne remplacée en utilisant les groupes \g<1>, \g<2>, etc.
  • Si la regexp ne matche pasla ligne n'est PAS ajoutée. Différence cruciale par rapport au comportement par défaut.

C'est volontaire : avec backrefs, on suppose que la ligne existe déjà sous une forme reconnaissable. Si elle n'existe pas, c'est suspect — au lieu d'ajouter une ligne par défaut, Ansible préfère ne rien faire.

insertafter et insertbefore — placer la ligne ailleurs qu'à la fin

Section intitulée « insertafter et insertbefore — placer la ligne ailleurs qu'à la fin »

Par défaut, une nouvelle ligne (cas où la regexp ne matche rien) est ajoutée à la fin du fichier. Pour la placer ailleurs :

# Ajouter une ligne JUSTE APRÈS [main] dans un .ini
- name: Forcer le user dans la section [main]
ansible.builtin.lineinfile:
path: /etc/something.conf
regexp: '^user='
line: "user=outscale"
insertafter: '^\[main\]'
# Ajouter une ligne JUSTE AVANT la première directive Listen
- name: Préfixer une directive Apache
ansible.builtin.lineinfile:
path: /etc/httpd/conf/httpd.conf
regexp: '^ServerTokens'
line: "ServerTokens Prod"
insertbefore: '^Listen'
validate: "httpd -t -f %s"

insertafter et insertbefore prennent une regexp. Valeurs spéciales :

  • EOF (défaut pour insertafter quand non précisé) : fin de fichier.
  • BOF : début de fichier.

lineinfile est précieux pour les petites modifications ciblées. Mais c'est rarement le bon choix quand :

SituationOutil préférable
Vous voulez gérer tout un fichier de configtemplate + Jinja2 (cf. Templates Jinja2)
Vous voulez ajouter/modifier plusieurs lignes liées (un bloc)blockinfile (cf. Module blockinfile)
Vous voulez remplacer un motif dans une ligne (même partielle)replace (cf. Module replace)
Vous gérez un fichier .ini ou .yamlini_file ou yaml modules dédiés — plus sûrs
Vous voulez modifier un fichier JSONreplace + regex, ou mieux : modifier en Python via script ou command

Règle simple : si vous écrivez 3 tasks lineinfile sur le même fichier, c'est probablement le moment de basculer sur template.

L'idempotence d'un lineinfile se vérifie par un double run :

Fenêtre de terminal
# 1er run — task = `changed` ou `ok` selon état initial
ansible-playbook configure-sshd.yml
# 2e run immédiat — task DOIT être `ok` (jamais `changed`)
ansible-playbook configure-sshd.yml

Si le 2e run rapporte changed: 1, votre regexp ne matche pas la ligne que vous venez d'écrire. Causes typiques :

  • Espaces ou tabulations dans la regexp qui ne matchent pas la ligne réelle.
  • Ancres ^ et $ manquantes — regexp trop lâche.
  • Caractères spéciaux non échappés (., *, [, ], \).

Tester la regexp manuellement sur le fichier après le 1er run :

Fenêtre de terminal
grep -E "<votre-regexp>" /etc/ssh/sshd_config
# Doit matcher exactement la ligne que vous venez d'écrire
SymptômeCauseSolution
Ligne ajoutée 2 fois (matching exact échoue)regexp non précisée + différence d'espacementToujours préciser regexp pour identifier le paramètre
changed à chaque run (idempotence cassée)regexp ne matche pas la ligne écrite par lineTester la regexp avec grep -E après le 1er run
backrefs: true mais ligne manquante non ajoutéeComportement volontaire de backrefsSi la ligne peut être absente : 2 tâches (1 sans backrefs pour ajouter, 1 avec pour remplacer)
validate qui échoue mais avec un message obscur%s non utilisé ou mauvais flag du validateurTester d'abord en CLI : sshd -t -f /etc/ssh/sshd_config
Service pas redémarré après modificationnotify: manquantAjouter notify: Restart sshd + un handler correspondant
Permission denied à l'écriturebecome: true manquantbecome: true au play ou à la tâche
Fichier sans \n final après lineinfileBug rare avec certains validatorsAjouter lineinfile final qui force une newline si nécessaire
  • lineinfile modifie une seule ligne — pour plusieurs, préférer blockinfile ou template.
  • regexp identifie la ligne par son paramètre, pas par son contenu exact (qui peut varier en espaces).
  • validate: "<cmd> -t -f %s" est mandatory sur tout fichier critique (sshd, sudoers, nginx).
  • state: absent + regexp = supprime toutes les lignes matchant.
  • backrefs: true = remplace si la regexp matche, ne fait rien si elle ne matche pas (volontaire).
  • insertafter / insertbefore placent la ligne uniquement quand la regexp principale ne matche pas (insertion).
  • Tester l'idempotence par un double run — changed au 2e run = regexp incorrecte.
  • 3 lineinfile sur le même fichier = passez à template.

Cette page a un lab d'accompagnement : labs/modules-fichiers/lineinfile/ dans stephrobert/ansible-training.

Challenge — sur db1.lab :

  1. Ajouter net.ipv4.ip_forward=1 dans /etc/sysctl.conf (ajout simple).
  2. Forcer PermitRootLogin no dans /etc/ssh/sshd_config (regexp + validate: "sshd -t -f %s").
  3. Réduire MaxAuthTries 3 en préservant l'indentation existante (backrefs: true).
  4. Ajouter AllowUsers ansible si la directive n'existe pas.

Validation pytest+testinfra :

Fenêtre de terminal
ansible-playbook labs/modules-fichiers/lineinfile/challenge/solution.yml
ansible-playbook labs/modules-fichiers/lineinfile/challenge/solution.yml # 2e run = changed=0
pytest -v labs/modules-fichiers/lineinfile/challenge/tests/

Les tests vérifient la présence de chaque directive, le succès de sshd -T, et l'idempotence via un double run sans changed.

Ce site vous est utile ?

Sachez que moins de 1% des lecteurs soutiennent ce site.

Je maintiens +700 guides gratuits, sans pub ni tracing. Aujourd'hui, ce site ne couvre même pas mes frais d'hébergement, d'électricité, de matériel, de logiciels, mais surtout de cafés.

Un soutien régulier, même symbolique, m'aide à garder ces ressources gratuites et à continuer de produire des guides de qualité. Merci pour votre appui.

Abonnez-vous et suivez mon actualité DevSecOps sur LinkedIn