L'exécution du playbook se termine en vert, l'unité WireGuard est active, la poignée de main fonctionne, et le nouveau peer n'atteint toujours rien. Voir un playbook annoncer un succès alors que le serveur tourne avec la configuration de la veille est particulièrement frustrant, car rien dans la sortie n'est faux. Ansible a fait exactement ce qu'on lui demandait : il a vérifié que l'unité était démarrée, et elle l'était déjà. Appliquer un fichier de configuration réécrit est une autre tâche, et cela n'arrive que si quelque chose demande au service de le relire.

Regardez ce qu'une seconde exécution rapporte vraiment

Lancez le playbook deux fois avec la configuration modifiée en place et comparez le récapitulatif. La seconde exécution doit montrer la tâche de l'unité comme ok et non changed, car un service déjà lancé est laissé tranquille par conception. C'est l'idempotence qui fonctionne correctement, et c'est aussi pourquoi le nouveau fichier n'atteint jamais le noyau.

Ajoutez une exécution de contrôle avec sortie diff pour voir quelles tâches toucheraient quoi que ce soit.

ansible-playbook -i inventory site.yml --check --diff
systemctl show wg-quick@wg0 -p ActiveEnterTimestamp -p NRestarts
stat -c '%y %n' /etc/wireguard/wg0.conf

Les trois horodatages racontent l'histoire avant même de lire une ligne de journal. Si le fichier de configuration est plus récent que le moment où l'unité est devenue active, l'interface en cours a été construite à partir d'un fichier plus ancien, et chaque symptôme en découle.

Ce n'est pas un défaut d'Ansible. Le même comportement apparaît avec tout outil de gestion de configuration qui sépare « assure-toi que ça tourne » de « assure-toi que ça tourne avec ceci ». La distinction paraît pédante jusqu'à ce qu'elle vous coûte un après-midi.

Démarré est un état, pas un rechargement

state: started affirme une condition sur l'unité. Il ne promet pas que le service relira ses entrées, et il ne peut pas savoir qu'un fichier qu'il n'a jamais ouvert a changé. Dans un déploiement wg-quick, les entrées comprennent la configuration de l'interface, les adresses, les routes, les entrées DNS et les éventuels hooks post-up.

C'est pourquoi un fichier mis à jour peut contenir un nouveau peer, une autre adresse ou une directive de routage modifiée pendant que l'interface vivante continue de servir l'ancien ensemble. La poignée de main réussit encore parce que les clés et les points de terminaison chargés sont toujours valides. C'est précisément ce qui rend la panne difficile à voir, et pourquoi les gens courent après le DNS pendant une heure avant de vérifier un horodatage.

Deux autres options du module sont souvent prises pour un correctif. daemon_reload fait relire les fichiers d'unité à systemd, ce qui est sans rapport avec un fichier de configuration WireGuard. state: reloaded demande à l'unité d'exécuter son action de rechargement, et savoir si cela fait ce qu'il faut dépend entièrement de l'unité. Ni l'une ni l'autre ne remplace le fait de savoir quelles entrées le processus en cours a réellement lues.

Installez le fichier, puis notifiez un handler

Le schéma qui conserve l'idempotence et applique quand même les changements est le schéma habituel : la tâche qui écrit le fichier notifie un handler, et le handler ne s'exécute que si le fichier a réellement changé. Une seconde exécution sans modification ne fait rien, et c'est ce que vous voulez.

- name: write the interface configuration
  ansible.builtin.template:
    src: wg0.conf.j2
    dest: /etc/wireguard/wg0.conf
    owner: root
    mode: "0600"
  notify: apply wg0

- name: ensure the interface unit is enabled
  ansible.builtin.systemd_service:
    name: wg-quick@wg0
    enabled: true
    state: started

- name: apply wg0
  listen: apply wg0
  ansible.builtin.systemd_service:
    name: wg-quick@wg0
    state: restarted

Les handlers s'exécutent à la fin du play, après les tâches qui les ont notifiés, donc une tâche plus loin dans le même play peut encore voir l'ancienne interface. Si l'ordre compte, videz les handlers explicitement avec meta: flush_handlers avant la tâche qui dépend de la nouvelle configuration.

Utilisez restart plutôt que reload, sauf si vous avez vérifié l'action de rechargement de l'unité. L'unité wg-quick amont en propose une et synchronise la configuration WireGuard, mais elle ne relance pas la configuration des adresses, des routes, du DNS ni des hooks. Un reload après l'ajout d'une directive de route semble donc réussir et ne change rien.

Comparez l'appareil vivant au fichier

Le contrôle qui ferme cette classe de bogues est une comparaison entre ce que le noyau détient et ce que dit le fichier. Deux commandes produisent une sortie comparable, et la différence est la dérive.

sudo wg showconf wg0
sudo wg-quick strip wg0
sudo diff <(sudo wg showconf wg0) <(sudo wg-quick strip wg0)

wg showconf imprime l'appareil vivant, y compris la clé privée, alors traitez cette sortie comme un secret et ne la collez pas dans un ticket. wg-quick strip imprime le fichier sans les clés propres à wg-quick, et c'est pourquoi les deux sont comparables.

Une différence dans la liste des peers signifie que le fichier n'a jamais été appliqué. Une différence limitée aux clés ou aux points de terminaison que vous attendiez signifie que quelque chose l'a appliqué partiellement. Aucune différence signifie que la configuration est à jour et que la panne est ailleurs, ce qui est déjà un résultat utile.

Payez le coût du redémarrage délibérément

Redémarrer l'interface coupe le tunnel, et si ce tunnel transporte votre session d'administration, le redémarrage met fin à la session qui l'a demandé. Placez le handler derrière une fenêtre de changement, ou lancez le playbook depuis un chemin d'administration qui ne dépend pas du redémarrage de l'interface.

Le coût est la raison pour laquelle les gens se tournent vers reload. C'est un réflexe raisonnable, et il devient correct une fois que vous savez quels changements un reload applique réellement. Pour les changements de peers et de clés sur l'unité wg-quick amont, cela suffit ; pour l'adressage, le routage et les hooks, non. Tirer cela au clair une fois coûte moins cher que de le découvrir pendant une fenêtre de changement.

La documentation du module systemd_service explique la différence entre started, restarted et reloaded, et elle mérite une lecture plutôt qu'une déduction depuis un récapitulatif vert. Tout dans ce parcours découle de cette seule distinction.

Articles similaires