Set-OPS-Public/roles/serveur_icinga/tasks/main.yml

272 lines
11 KiB
YAML
Raw Normal View History

---
# Recuperee UNE FOIS. Sans garde, chaque deploiement recontactait le serveur du
# fournisseur : cinq cles x quatorze hotes = soixante-dix allers-retours externes pour
# des cles deja installees, et autant d'occasions qu'un tiers lent fasse tomber le
# deploiement. Arbitrage rendu le 2026-08-09 : une plateforme souveraine ne depend pas
# de six serveurs etrangers pour redeployer ce qu'elle possede deja.
#
# CONSEQUENCE ASSUMEE : une rotation de cle amont n'est plus recuperee toute seule. Elle
# ne passe pas inapercue pour autant — `apt` refuse alors le depot, bruyamment. Pour
# forcer le rafraichissement : supprimer le fichier et rejouer le role.
- name: Cette ressource est-elle deja recuperee ? (Telecharger le trousseau de cles I)
ansible.builtin.stat:
path: "/tmp/icinga-archive-keyring.deb"
register: telecharger_le_trousseau_de_cles_icinga_present
- name: Telecharger le trousseau de cles Icinga
when: not telecharger_le_trousseau_de_cles_icinga_present.stat.exists
ansible.builtin.get_url:
url: "{{ serveur_icinga_keyring_url }}"
dest: "/tmp/icinga-archive-keyring.deb"
mode: "0644"
- name: Installer le trousseau de cles Icinga
ansible.builtin.apt:
deb: "/tmp/icinga-archive-keyring.deb"
state: present
- name: Ajouter le depot apt Icinga
ansible.builtin.apt_repository:
repo: "{{ serveur_icinga_depot_source }}"
filename: icinga
state: present
paquets tiers : passer par le cache du controleur, plus par Internet Trois depots tiers etaient en HTTPS, et client_artefacts pose Acquire::https::Proxy DIRECT — sans quoi le cache du site refuse les tunnels et aucun depot tiers n est joignable. La ligne est juste ; sa consequence ne l avait pas ete vue : ces trois depots CONTOURNENT le cache, et chaque VM neuve allait les chercher sur Internet a sa naissance. step-cli et alloy sont poses par des integrations UNIVERSELLES. Sans lien, une machine neuve n obtenait ni son client d autorite ni ses metriques — elle n entrait dans aucun flux chiffre. Dernier obstacle a une reconstruction hors ligne, et il tenait dans un mot. make cacher-paquets tire les 21 deb aux versions epinglees, empreinte SHA256 verifiee depuis l index du depot. Le role partage paquets_tiers les depose et les installe EN UN SEUL appel a apt — il sait resoudre un ensemble de fichiers locaux qui se dependent, la ou paquet par paquet echouerait sur l ordre (Icinga en apporte dix-sept). Six roles branches ; chacun retombe sur le depot distant pour ce que le cache n a PAS fourni, et rien d autre. Eprouve pour de vrai : packages.smallstep.com renvoye vers 127.0.0.1, step-cli desinstalle, cache local efface. Le role rejoue installe 0.30.6-1 depuis le cache et la machine obtient ses certificats. Zero echec. Deux defauts de mon propre outil, trouves en le construisant : Smallstep sert son index NON COMPRESSE (404 sur .gz) donc step-cli n etait jamais mis en cache ; et un depot injoignable faisait continue AVANT d incrementer le total, si bien que le script rapportait 20 sur 20 alors qu il en manquait un. Une garde qui ne peut pas echouer ne garde rien — troisieme fois cette semaine. Corrige puis eprouve en le faisant echouer. Reste hors ligne : NTP externe, et l expedition des alertes. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019f91zs9SDdwSzL2CVei6on
2026-09-05 08:22:14 -04:00
# LE CACHE DU CONTROLEUR D'ABORD, LE DEPOT DISTANT POUR LE RESTE (2026-09-03).
#
# Les depots tiers sont en HTTPS, et `client_artefacts` pose
# `Acquire::https::Proxy "DIRECT"` — ils CONTOURNENT donc le cache du site et sortent sur
# Internet a chaque construction de VM. `make cacher-paquets` les tire une fois, versions
# epinglees et empreintes verifiees ; ce role les depose depuis ce cache.
- name: Poser les paquets tiers depuis le cache du controleur
ansible.builtin.include_role:
name: paquets_tiers
vars:
paquets_tiers_noms: "{{ serveur_icinga_paquets }}"
- name: Installer Icinga 2, Icinga DB et Redis dedie
ansible.builtin.apt:
paquets tiers : passer par le cache du controleur, plus par Internet Trois depots tiers etaient en HTTPS, et client_artefacts pose Acquire::https::Proxy DIRECT — sans quoi le cache du site refuse les tunnels et aucun depot tiers n est joignable. La ligne est juste ; sa consequence ne l avait pas ete vue : ces trois depots CONTOURNENT le cache, et chaque VM neuve allait les chercher sur Internet a sa naissance. step-cli et alloy sont poses par des integrations UNIVERSELLES. Sans lien, une machine neuve n obtenait ni son client d autorite ni ses metriques — elle n entrait dans aucun flux chiffre. Dernier obstacle a une reconstruction hors ligne, et il tenait dans un mot. make cacher-paquets tire les 21 deb aux versions epinglees, empreinte SHA256 verifiee depuis l index du depot. Le role partage paquets_tiers les depose et les installe EN UN SEUL appel a apt — il sait resoudre un ensemble de fichiers locaux qui se dependent, la ou paquet par paquet echouerait sur l ordre (Icinga en apporte dix-sept). Six roles branches ; chacun retombe sur le depot distant pour ce que le cache n a PAS fourni, et rien d autre. Eprouve pour de vrai : packages.smallstep.com renvoye vers 127.0.0.1, step-cli desinstalle, cache local efface. Le role rejoue installe 0.30.6-1 depuis le cache et la machine obtient ses certificats. Zero echec. Deux defauts de mon propre outil, trouves en le construisant : Smallstep sert son index NON COMPRESSE (404 sur .gz) donc step-cli n etait jamais mis en cache ; et un depot injoignable faisait continue AVANT d incrementer le total, si bien que le script rapportait 20 sur 20 alors qu il en manquait un. Une garde qui ne peut pas echouer ne garde rien — troisieme fois cette semaine. Corrige puis eprouve en le faisant echouer. Reste hors ligne : NTP externe, et l expedition des alertes. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019f91zs9SDdwSzL2CVei6on
2026-09-05 08:22:14 -04:00
# CE QUE LE CACHE N'A PAS FOURNI, ET RIEN D'AUTRE. Les dependances Debian passent
# par le cache du site en HTTP ; seuls les paquets tiers non caches exigent Internet.
# Reinstaller ce que le cache vient de poser ferait un `update_cache` inutile — et
# hors ligne, il echouerait APRES un travail deja fait.
name: "{{ serveur_icinga_paquets | difference((paquets_tiers_disponibles | default({})).keys() | list) }}"
state: present
update_cache: true
paquets tiers : passer par le cache du controleur, plus par Internet Trois depots tiers etaient en HTTPS, et client_artefacts pose Acquire::https::Proxy DIRECT — sans quoi le cache du site refuse les tunnels et aucun depot tiers n est joignable. La ligne est juste ; sa consequence ne l avait pas ete vue : ces trois depots CONTOURNENT le cache, et chaque VM neuve allait les chercher sur Internet a sa naissance. step-cli et alloy sont poses par des integrations UNIVERSELLES. Sans lien, une machine neuve n obtenait ni son client d autorite ni ses metriques — elle n entrait dans aucun flux chiffre. Dernier obstacle a une reconstruction hors ligne, et il tenait dans un mot. make cacher-paquets tire les 21 deb aux versions epinglees, empreinte SHA256 verifiee depuis l index du depot. Le role partage paquets_tiers les depose et les installe EN UN SEUL appel a apt — il sait resoudre un ensemble de fichiers locaux qui se dependent, la ou paquet par paquet echouerait sur l ordre (Icinga en apporte dix-sept). Six roles branches ; chacun retombe sur le depot distant pour ce que le cache n a PAS fourni, et rien d autre. Eprouve pour de vrai : packages.smallstep.com renvoye vers 127.0.0.1, step-cli desinstalle, cache local efface. Le role rejoue installe 0.30.6-1 depuis le cache et la machine obtient ses certificats. Zero echec. Deux defauts de mon propre outil, trouves en le construisant : Smallstep sert son index NON COMPRESSE (404 sur .gz) donc step-cli n etait jamais mis en cache ; et un depot injoignable faisait continue AVANT d incrementer le total, si bien que le script rapportait 20 sur 20 alors qu il en manquait un. Une garde qui ne peut pas echouer ne garde rien — troisieme fois cette semaine. Corrige puis eprouve en le faisant echouer. Reste hors ligne : NTP externe, et l expedition des alertes. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019f91zs9SDdwSzL2CVei6on
2026-09-05 08:22:14 -04:00
when: (serveur_icinga_paquets
| difference((paquets_tiers_disponibles | default({})).keys() | list)) | length > 0
- name: Resoudre la base de donnees depuis le registre (role partage)
ansible.builtin.include_role:
name: resoudre_base
vars:
resoudre_base_groupe: "{{ serveur_icinga_groupe }}"
- name: Adopter les facts de base pour Icinga
ansible.builtin.set_fact:
serveur_icinga_entree: "{{ resoudre_base_entree }}"
serveur_icinga_db_password: "{{ resoudre_base_db_password }}"
serveur_icinga_db_host: "{{ resoudre_base_db_host }}"
no_log: true
reconstruction from-zero : sept defauts, tous invisibles sur une flotte debout Chezlepro reconstruit depuis zero en 10.17.x.x. Sept defauts sont tombes, et AUCUN n'etait detectable autrement — c'est tout l'argument de la reconstruction comme preuve. 1. aucune route vers le tenant sur le poste (posee a la main, jamais persistee) 2. backup-01 exigeait l'AC d'Icinga — dependance non declaree 3. ma correction inversait les couches : REFUSEE PAR P08 avant d'entrer 4. base Forgejo a moitie initialisee (sequelle de l'arret du n°2) 5. /etc/hosts : nom court avant le FQDN -> hostname -f faux sur les 14 machines 6. API Icinga jamais activee (garde `creates:` d'api setup) 7. restic refuse tout le lot si un chemin declare manque LE CINQUIEME DEPASSAIT ICINGA. hostname -f rend le PREMIER nom : toute la flotte se croyait appelee « mon-01 ». Visible sur le certificat d'Icinga, mais le meme piege attendait Postfix (myhostname), les journaux, les certificats. FQDN d'abord. CE QU'ON NE CORRIGE PAS : icinga2 api setup REECRIT NodeName d'apres le nom court et nomme ses certificats d'apres lui. Aligne avant, il est ecrase ; aligne apres, les certificats portent le mauvais nom. On adopte sa convention : le depot appelle l'API par le nom court, celui que le certificat porte. serveur_icinga_node_name derive desormais de l'INVENTAIRE, pas d'ansible_fqdn — un fait qui depend du resolveur et rendait « mon-01 » alors que le FQDN etait bon. Le commentaire ecrit pour avertir qu'une sequence accolade-diese casse les gabarits Jinja contenait cette sequence, et cassait le gabarit. Neuf hotes en echec pour un avertissement mal redige. Sept devis CONFORME, prouver 36/36, make test 0. Neuf sauvegardes reussies. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-13 03:36:56 -04:00
# --- Identite TLS de l'API (5665) ---
# ON NE TOUCHE PAS A `NodeName` — et il n'y a rien a corriger ici.
reconstruction from-zero : sept defauts, tous invisibles sur une flotte debout Chezlepro reconstruit depuis zero en 10.17.x.x. Sept defauts sont tombes, et AUCUN n'etait detectable autrement — c'est tout l'argument de la reconstruction comme preuve. 1. aucune route vers le tenant sur le poste (posee a la main, jamais persistee) 2. backup-01 exigeait l'AC d'Icinga — dependance non declaree 3. ma correction inversait les couches : REFUSEE PAR P08 avant d'entrer 4. base Forgejo a moitie initialisee (sequelle de l'arret du n°2) 5. /etc/hosts : nom court avant le FQDN -> hostname -f faux sur les 14 machines 6. API Icinga jamais activee (garde `creates:` d'api setup) 7. restic refuse tout le lot si un chemin declare manque LE CINQUIEME DEPASSAIT ICINGA. hostname -f rend le PREMIER nom : toute la flotte se croyait appelee « mon-01 ». Visible sur le certificat d'Icinga, mais le meme piege attendait Postfix (myhostname), les journaux, les certificats. FQDN d'abord. CE QU'ON NE CORRIGE PAS : icinga2 api setup REECRIT NodeName d'apres le nom court et nomme ses certificats d'apres lui. Aligne avant, il est ecrase ; aligne apres, les certificats portent le mauvais nom. On adopte sa convention : le depot appelle l'API par le nom court, celui que le certificat porte. serveur_icinga_node_name derive desormais de l'INVENTAIRE, pas d'ansible_fqdn — un fait qui depend du resolveur et rendait « mon-01 » alors que le FQDN etait bon. Le commentaire ecrit pour avertir qu'une sequence accolade-diese casse les gabarits Jinja contenait cette sequence, et cassait le gabarit. Neuf hotes en echec pour un avertissement mal redige. Sept devis CONFORME, prouver 36/36, make test 0. Neuf sauvegardes reussies. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-13 03:36:56 -04:00
#
# `icinga2 api setup` ECRIT lui-meme NodeName d'apres `hostname -f`, puis nomme ses
# certificats d'apres lui. Tant que `/etc/hosts` mettait le nom COURT en premier,
# `hostname -f` rendait « mon-01 » et le certificat devenait invérifiable en appelant par
# le nom complet. On a longuement tente d'aligner NodeName a la main, avant et apres
# `api setup` : efface a chaque fois.
#
# LA CAUSE ETAIT AILLEURS. Depuis que `hosts_statiques` place le FQDN en premier
# (2026-08-13), `hostname -f` rend le nom complet et Icinga s'emet spontanement un
# certificat CN et SAN = FQDN. Rien a forcer : il suffisait que la machine sache
# comment elle s'appelle.
- name: Configurer l'API Icinga 2
ansible.builtin.command:
cmd: icinga2 api setup
creates: /etc/icinga2/features-enabled/api.conf
notify: Redemarrer icinga2
- name: Activer la fonctionnalite icingadb dans Icinga 2
ansible.builtin.command:
cmd: icinga2 feature enable icingadb
creates: /etc/icinga2/features-enabled/icingadb.conf
notify: Redemarrer icinga2
- name: Activer et demarrer le Redis Icinga DB
when: not ansible_check_mode
ansible.builtin.systemd:
name: "{{ serveur_icinga_service_redis }}"
enabled: true
state: started
- name: Importer le schema Icinga DB dans PostgreSQL (une fois)
ansible.builtin.shell:
cmd: >-
PGPASSWORD='{{ serveur_icinga_db_password }}'
psql -h {{ serveur_icinga_db_host }} -U {{ serveur_icinga_entree.proprietaire }}
-d {{ serveur_icinga_entree.base }} -f {{ serveur_icinga_schema }}
&& touch /etc/icingadb/.schema-imported
creates: /etc/icingadb/.schema-imported
no_log: true
- name: Deployer la configuration Icinga DB
ansible.builtin.template:
src: config.yml.j2
dest: "{{ serveur_icinga_config }}"
owner: root
group: icingadb
mode: "0640"
no_log: true
notify: Redemarrer icingadb
reconstruction from-zero : sept defauts, tous invisibles sur une flotte debout Chezlepro reconstruit depuis zero en 10.17.x.x. Sept defauts sont tombes, et AUCUN n'etait detectable autrement — c'est tout l'argument de la reconstruction comme preuve. 1. aucune route vers le tenant sur le poste (posee a la main, jamais persistee) 2. backup-01 exigeait l'AC d'Icinga — dependance non declaree 3. ma correction inversait les couches : REFUSEE PAR P08 avant d'entrer 4. base Forgejo a moitie initialisee (sequelle de l'arret du n°2) 5. /etc/hosts : nom court avant le FQDN -> hostname -f faux sur les 14 machines 6. API Icinga jamais activee (garde `creates:` d'api setup) 7. restic refuse tout le lot si un chemin declare manque LE CINQUIEME DEPASSAIT ICINGA. hostname -f rend le PREMIER nom : toute la flotte se croyait appelee « mon-01 ». Visible sur le certificat d'Icinga, mais le meme piege attendait Postfix (myhostname), les journaux, les certificats. FQDN d'abord. CE QU'ON NE CORRIGE PAS : icinga2 api setup REECRIT NodeName d'apres le nom court et nomme ses certificats d'apres lui. Aligne avant, il est ecrase ; aligne apres, les certificats portent le mauvais nom. On adopte sa convention : le depot appelle l'API par le nom court, celui que le certificat porte. serveur_icinga_node_name derive desormais de l'INVENTAIRE, pas d'ansible_fqdn — un fait qui depend du resolveur et rendait « mon-01 » alors que le FQDN etait bon. Le commentaire ecrit pour avertir qu'une sequence accolade-diese casse les gabarits Jinja contenait cette sequence, et cassait le gabarit. Neuf hotes en echec pour un avertissement mal redige. Sept devis CONFORME, prouver 36/36, make test 0. Neuf sauvegardes reussies. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-13 03:36:56 -04:00
# `icinga2 api setup` active la fonctionnalite EN MEME TEMPS qu'il pose les certificats,
# et sa garde `creates:` la saute des que le fichier existe. Consequence mesuree le
# 2026-08-12 : apres un nettoyage des certificats, l'API restait DESACTIVEE — icinga2
# demarrait, se declarait `active`, et n'ecoutait sur rien. Exiger l'activation
# separement rend l'etat independant de l'ordre des nettoyages.
- name: API — exiger que la fonctionnalite soit activee
ansible.builtin.command:
cmd: icinga2 feature enable api
creates: /etc/icinga2/features-enabled/api.conf
icinga : le pair est verifie — mais pas avec un certificat step-ca Objectif : supprimer le `curl -k` du rapporteur. Fait, et la maniere a ete imposee par la mesure. SERVIR UN CERTIFICAT STEP-CA SUR L'API EST IMPOSSIBLE. Icinga le dit lui-meme : « Our certificate will expire soon, but we own the CA. Renewing. » Il renouvelle tout certificat expirant sous 30 jours ; les notres vivent 24 h ; possedant une AC, il re-emet avec la sienne et ecrase le notre a chaque demarrage. Collision entre deux politiques de PKI, et la notre n'est pas negociable. Deux decouvertes en chemin, toutes deux par le garde-fou `icinga2 daemon -C` ajoute au role, qui a ARRETE le deploiement avant de redemarrer la supervision : - cert_path/key_path/ca_path sont DEPRECIES depuis 2.8 ; les poser reveille un chemin de code herite qui exige en plus un objet Endpoint ; - l'identite de l'API est le CN du certificat. NodeName valait « mon-01 », donc le SAN aussi, alors qu'on appelle par le FQDN : aucune verification n'aurait pu reussir. NodeName est desormais aligne sur le FQDN. A LA PLACE : Icinga garde son AC (domaine de confiance FERME, legitime) et backup-01 verifie le pair contre CETTE AC, recuperee depuis mon-01 au deploiement. Le pair est authentifie ; seule la racine differe. Controle negatif — une verification qu'on ne teste pas est un ornement : avec la mauvaise AC (step-ca), curl refuse (« unable to get local issuer certificate ») ; avec la bonne, les neuf rapports passent. Sous-AC step-ca ecartee : elle poserait sur l'hote de supervision une cle capable d'EMETTRE pour n'importe quel nom, alors qu'on a choisi le sens du flux pour que compromettre mon-01 ne donne rien. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-12 08:33:50 -04:00
notify: Redemarrer icinga2
- name: API — durcir l'ApiListener (aucune config ni commande acceptee)
ansible.builtin.template:
src: api.conf.j2
dest: /etc/icinga2/features-available/api.conf
owner: root
group: nagios
mode: "0640"
notify: Redemarrer icinga2
supervision : c'est le DEPOT qui dit ou en sont les sauvegardes Icinga ne surveillait rien : aucun objet Host ni Service de Set-OPS, seulement la config Debian d'origine sur localhost. Superviser setops-sauvegarde.service aurait reproduit le defaut du jour meme : l'unite etait VERTE sur onze noeuds pendant qu'elle n'emportait rien. Le noeud sait qu'il a LANCE sa sauvegarde, pas qu'elle est ARRIVEE. backup-01 evalue donc ses depots et pousse un resultat passif par noeud vers l'API Icinga. Trois criteres, parce qu'un seul suffit a mentir : l'instantane existe, il est recent (26 h / 50 h), il contient au moins un fichier. Le sens du flux est delibere : le depot parle a la supervision, jamais l'inverse — compromettre mon-01 ne donne aucun acces aux sauvegardes. Le ttl de 6 h fait la fraicheur : si le rapporteur se tait, Icinga perime les services tout seul. C'est le silence qui a laisse le defaut vivre un mois. Deux erreurs corrigees par la mesure : - --data-urlencode refuse en Bad Request (l'API veut du JSON) ; le flux, le TLS et l'auth marchaient, seule la charge etait perdue. - le seuil « vide » en octets signalait a tort idm-01 (2363 o) : un export LDIF d'un annuaire a un compte pese cela. « Vide » se mesure en FICHIERS. Et le verdict est un AVERTISSEMENT : la machine ne distingue pas « les donnees ont disparu » de « il n'y en a pas encore ». Reserve assumee : curl -k — l'API presente le cert de sa propre AC, pas step-ca. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-11 21:39:05 -04:00
# --- Supervision des sauvegardes ---
# La liste des detenteurs d'etat appartient a `client_backup`. On la LIT chez lui plutot
# que de la recopier : deux listes finissent toujours par diverger, et la divergence se
# lirait « tout va bien » des deux cotes.
- name: Lire la liste des detenteurs d'etat chez client_backup
ansible.builtin.include_vars:
file: "{{ role_path }}/../client_backup/vars/main.yml"
name: _catalogue_sauvegarde
- name: Adopter la liste des detenteurs d'etat
ansible.builtin.set_fact:
client_backup_groupes_etat: "{{ _catalogue_sauvegarde.client_backup_groupes_etat }}"
# UN ECOSYSTEME PEUT N'AVOIR AUCUN DEPOT A LUI, ET C'EST LE CAS NORMAL DEPUIS QU'ILS
# DEPOSENT CHEZ LEUR HEBERGEUR (2026-09-02).
#
# Cette assertion exigeait un hote `serveur_backup` dans l'ecosysteme. C'etait juste tant
# que le depot y vivait : il etait le seul a voir ce qui arrivait vraiment, et il
# rapportait pour tout le monde.
#
# Depuis la bascule vers le depot du SITE, l'ecosysteme n'en a plus. Le site, lui, ne
# peut pas ouvrir ces depots — restic chiffre chez le client. C'est donc chaque NOEUD qui
# verifie le sien (`client_backup/tasks/verifier.yml`) et rapporte ici. Ce qui reste
# exige, c'est le secret d'API : sans lui, personne ne peut rien rapporter.
- name: Exiger le secret d'API pour les rapports passifs (Vault)
supervision : c'est le DEPOT qui dit ou en sont les sauvegardes Icinga ne surveillait rien : aucun objet Host ni Service de Set-OPS, seulement la config Debian d'origine sur localhost. Superviser setops-sauvegarde.service aurait reproduit le defaut du jour meme : l'unite etait VERTE sur onze noeuds pendant qu'elle n'emportait rien. Le noeud sait qu'il a LANCE sa sauvegarde, pas qu'elle est ARRIVEE. backup-01 evalue donc ses depots et pousse un resultat passif par noeud vers l'API Icinga. Trois criteres, parce qu'un seul suffit a mentir : l'instantane existe, il est recent (26 h / 50 h), il contient au moins un fichier. Le sens du flux est delibere : le depot parle a la supervision, jamais l'inverse — compromettre mon-01 ne donne aucun acces aux sauvegardes. Le ttl de 6 h fait la fraicheur : si le rapporteur se tait, Icinga perime les services tout seul. C'est le silence qui a laisse le defaut vivre un mois. Deux erreurs corrigees par la mesure : - --data-urlencode refuse en Bad Request (l'API veut du JSON) ; le flux, le TLS et l'auth marchaient, seule la charge etait perdue. - le seuil « vide » en octets signalait a tort idm-01 (2363 o) : un export LDIF d'un annuaire a un compte pese cela. « Vide » se mesure en FICHIERS. Et le verdict est un AVERTISSEMENT : la machine ne distingue pas « les donnees ont disparu » de « il n'y en a pas encore ». Reserve assumee : curl -k — l'API presente le cert de sa propre AC, pas step-ca. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-11 21:39:05 -04:00
ansible.builtin.assert:
that:
- serveur_icinga_api_motdepasse | length > 0
fail_msg: >-
vault_icinga_api_depot requis : sans lui, ni le depot ni les noeuds ne peuvent
rapporter l'etat de leurs sauvegardes, et personne ne les surveille.
supervision : c'est le DEPOT qui dit ou en sont les sauvegardes Icinga ne surveillait rien : aucun objet Host ni Service de Set-OPS, seulement la config Debian d'origine sur localhost. Superviser setops-sauvegarde.service aurait reproduit le defaut du jour meme : l'unite etait VERTE sur onze noeuds pendant qu'elle n'emportait rien. Le noeud sait qu'il a LANCE sa sauvegarde, pas qu'elle est ARRIVEE. backup-01 evalue donc ses depots et pousse un resultat passif par noeud vers l'API Icinga. Trois criteres, parce qu'un seul suffit a mentir : l'instantane existe, il est recent (26 h / 50 h), il contient au moins un fichier. Le sens du flux est delibere : le depot parle a la supervision, jamais l'inverse — compromettre mon-01 ne donne aucun acces aux sauvegardes. Le ttl de 6 h fait la fraicheur : si le rapporteur se tait, Icinga perime les services tout seul. C'est le silence qui a laisse le defaut vivre un mois. Deux erreurs corrigees par la mesure : - --data-urlencode refuse en Bad Request (l'API veut du JSON) ; le flux, le TLS et l'auth marchaient, seule la charge etait perdue. - le seuil « vide » en octets signalait a tort idm-01 (2363 o) : un export LDIF d'un annuaire a un compte pese cela. « Vide » se mesure en FICHIERS. Et le verdict est un AVERTISSEMENT : la machine ne distingue pas « les donnees ont disparu » de « il n'y en a pas encore ». Reserve assumee : curl -k — l'API presente le cert de sa propre AC, pas step-ca. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-11 21:39:05 -04:00
- name: Deployer le compte d'API du depot de sauvegarde
ansible.builtin.template:
src: setops-api-users.conf.j2
dest: "{{ serveur_icinga_api_conf }}"
owner: root
group: nagios
mode: "0640"
no_log: true
notify: Redemarrer icinga2
supervision : systemctl --failed entre dans Icinga (role client_sante) CE QU IL FERME. openipmi.service echouait a chaque demarrage sur les quatorze machines depuis le 2026-09-02, et systemctl --failed rendait ZERO partout : non parce qu elles allaient bien, mais parce qu aucune n avait redemarre depuis. Il a fallu qu un humain redemarre une machine pour que le defaut existe aux yeux de quelqu un. Un controle qui ne peut echouer qu au demarrage ne mesure rien tant que rien ne demarre. PASSIF, ET A DUREE DE VIE. Un controle actif ne voit pas la machine MUETTE. Ici c est le noeud qui parle, et le ttl de son envoi fait la fraicheur : sans nouvelle, Icinga perime le service tout seul. Le silence alerte autant que l echec. Le minuteur declenche AU DEMARRAGE autant que toutes les 15 min : les echecs de cette famille naissent au boot. CRITIQUE DES LA PREMIERE UNITE, jamais un seuil — une unite en echec est soit un vrai probleme soit du bruit a retirer, et un seuil ferait vivre le bruit. Les tolerances se nomment une par une, vide par defaut. CONTROLE NEGATIF. Unite factice sur obs-01, etat relu dans IcingaDB : CRITICAL, et le verdict NOMME l unite. Les treize autres OK. Apres nettoyage : 14/14 OK. UN CONFLIT EVITE. setops-sauvegardes.conf definissait les object Host ; un second fichier de controle aurait redefini les memes, et Icinga refuse un objet en double — la configuration entiere aurait ete rejetee, donc AUCUNE supervision, en voulant en ajouter. Les hotes vivent maintenant dans setops-hotes.conf, definis une fois. TROIS OBSTACLES. ${#tableau[@]} contient {# que Jinja lit comme un debut de commentaire (remede : comment_start_string en tete du gabarit). Ma premiere sonde a traduit un 403 « Missing permission: objects/query/service » en « 0 service » — encore un echec qui ecrasait permission ; l etat se lit dans IcingaDB. Et un echec apt transitoire sur mon-01, local et disparu au second essai : mesure avant conclusion. NON FAIT : le SITE n a pas recu client_sante. make prouver : CONFORME, 63 OK, 0 echec, 0 saute. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Crgis8CxCWkAGFA1ecBz3q
2026-09-09 20:32:08 -04:00
# LES HOTES D'ABORD : les fichiers de service s'y attachent, et Icinga refuse un service
# dont l'hote n'existe pas. L'ordre dans `conf.d` n'est pas garanti par le nom, mais
# Icinga charge tout le repertoire avant de resoudre — l'ordre de deploiement suffit.
- name: Deployer les hotes supervises (definis une seule fois)
ansible.builtin.template:
src: setops-hotes.conf.j2
dest: "{{ serveur_icinga_hotes_conf }}"
owner: root
group: nagios
mode: "0640"
notify: Redemarrer icinga2
supervision : c'est le DEPOT qui dit ou en sont les sauvegardes Icinga ne surveillait rien : aucun objet Host ni Service de Set-OPS, seulement la config Debian d'origine sur localhost. Superviser setops-sauvegarde.service aurait reproduit le defaut du jour meme : l'unite etait VERTE sur onze noeuds pendant qu'elle n'emportait rien. Le noeud sait qu'il a LANCE sa sauvegarde, pas qu'elle est ARRIVEE. backup-01 evalue donc ses depots et pousse un resultat passif par noeud vers l'API Icinga. Trois criteres, parce qu'un seul suffit a mentir : l'instantane existe, il est recent (26 h / 50 h), il contient au moins un fichier. Le sens du flux est delibere : le depot parle a la supervision, jamais l'inverse — compromettre mon-01 ne donne aucun acces aux sauvegardes. Le ttl de 6 h fait la fraicheur : si le rapporteur se tait, Icinga perime les services tout seul. C'est le silence qui a laisse le defaut vivre un mois. Deux erreurs corrigees par la mesure : - --data-urlencode refuse en Bad Request (l'API veut du JSON) ; le flux, le TLS et l'auth marchaient, seule la charge etait perdue. - le seuil « vide » en octets signalait a tort idm-01 (2363 o) : un export LDIF d'un annuaire a un compte pese cela. « Vide » se mesure en FICHIERS. Et le verdict est un AVERTISSEMENT : la machine ne distingue pas « les donnees ont disparu » de « il n'y en a pas encore ». Reserve assumee : curl -k — l'API presente le cert de sa propre AC, pas step-ca. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-11 21:39:05 -04:00
- name: Deployer les objets de supervision des sauvegardes
ansible.builtin.template:
src: setops-sauvegardes.conf.j2
dest: "{{ serveur_icinga_setops_conf }}"
owner: root
group: nagios
mode: "0640"
notify: Redemarrer icinga2
supervision : systemctl --failed entre dans Icinga (role client_sante) CE QU IL FERME. openipmi.service echouait a chaque demarrage sur les quatorze machines depuis le 2026-09-02, et systemctl --failed rendait ZERO partout : non parce qu elles allaient bien, mais parce qu aucune n avait redemarre depuis. Il a fallu qu un humain redemarre une machine pour que le defaut existe aux yeux de quelqu un. Un controle qui ne peut echouer qu au demarrage ne mesure rien tant que rien ne demarre. PASSIF, ET A DUREE DE VIE. Un controle actif ne voit pas la machine MUETTE. Ici c est le noeud qui parle, et le ttl de son envoi fait la fraicheur : sans nouvelle, Icinga perime le service tout seul. Le silence alerte autant que l echec. Le minuteur declenche AU DEMARRAGE autant que toutes les 15 min : les echecs de cette famille naissent au boot. CRITIQUE DES LA PREMIERE UNITE, jamais un seuil — une unite en echec est soit un vrai probleme soit du bruit a retirer, et un seuil ferait vivre le bruit. Les tolerances se nomment une par une, vide par defaut. CONTROLE NEGATIF. Unite factice sur obs-01, etat relu dans IcingaDB : CRITICAL, et le verdict NOMME l unite. Les treize autres OK. Apres nettoyage : 14/14 OK. UN CONFLIT EVITE. setops-sauvegardes.conf definissait les object Host ; un second fichier de controle aurait redefini les memes, et Icinga refuse un objet en double — la configuration entiere aurait ete rejetee, donc AUCUNE supervision, en voulant en ajouter. Les hotes vivent maintenant dans setops-hotes.conf, definis une fois. TROIS OBSTACLES. ${#tableau[@]} contient {# que Jinja lit comme un debut de commentaire (remede : comment_start_string en tete du gabarit). Ma premiere sonde a traduit un 403 « Missing permission: objects/query/service » en « 0 service » — encore un echec qui ecrasait permission ; l etat se lit dans IcingaDB. Et un echec apt transitoire sur mon-01, local et disparu au second essai : mesure avant conclusion. NON FAIT : le SITE n a pas recu client_sante. make prouver : CONFORME, 63 OK, 0 echec, 0 saute. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Crgis8CxCWkAGFA1ecBz3q
2026-09-09 20:32:08 -04:00
- name: Deployer les objets de supervision de la sante des noeuds
ansible.builtin.template:
src: setops-sante.conf.j2
dest: "{{ serveur_icinga_sante_conf }}"
owner: root
group: nagios
mode: "0640"
notify: Redemarrer icinga2
supervision : c'est le DEPOT qui dit ou en sont les sauvegardes Icinga ne surveillait rien : aucun objet Host ni Service de Set-OPS, seulement la config Debian d'origine sur localhost. Superviser setops-sauvegarde.service aurait reproduit le defaut du jour meme : l'unite etait VERTE sur onze noeuds pendant qu'elle n'emportait rien. Le noeud sait qu'il a LANCE sa sauvegarde, pas qu'elle est ARRIVEE. backup-01 evalue donc ses depots et pousse un resultat passif par noeud vers l'API Icinga. Trois criteres, parce qu'un seul suffit a mentir : l'instantane existe, il est recent (26 h / 50 h), il contient au moins un fichier. Le sens du flux est delibere : le depot parle a la supervision, jamais l'inverse — compromettre mon-01 ne donne aucun acces aux sauvegardes. Le ttl de 6 h fait la fraicheur : si le rapporteur se tait, Icinga perime les services tout seul. C'est le silence qui a laisse le defaut vivre un mois. Deux erreurs corrigees par la mesure : - --data-urlencode refuse en Bad Request (l'API veut du JSON) ; le flux, le TLS et l'auth marchaient, seule la charge etait perdue. - le seuil « vide » en octets signalait a tort idm-01 (2363 o) : un export LDIF d'un annuaire a un compte pese cela. « Vide » se mesure en FICHIERS. Et le verdict est un AVERTISSEMENT : la machine ne distingue pas « les donnees ont disparu » de « il n'y en a pas encore ». Reserve assumee : curl -k — l'API presente le cert de sa propre AC, pas step-ca. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-11 21:39:05 -04:00
- name: Valider la configuration Icinga 2 avant de la rendre vivante
ansible.builtin.command:
cmd: icinga2 daemon -C
changed_when: false
- name: Activer et demarrer Icinga 2 et Icinga DB
when: not ansible_check_mode
ansible.builtin.systemd:
name: "{{ item }}"
enabled: true
state: started
loop:
- "{{ serveur_icinga_service_icinga2 }}"
- "{{ serveur_icinga_service_icingadb }}"
reconstruction from-zero : sept defauts, tous invisibles sur une flotte debout Chezlepro reconstruit depuis zero en 10.17.x.x. Sept defauts sont tombes, et AUCUN n'etait detectable autrement — c'est tout l'argument de la reconstruction comme preuve. 1. aucune route vers le tenant sur le poste (posee a la main, jamais persistee) 2. backup-01 exigeait l'AC d'Icinga — dependance non declaree 3. ma correction inversait les couches : REFUSEE PAR P08 avant d'entrer 4. base Forgejo a moitie initialisee (sequelle de l'arret du n°2) 5. /etc/hosts : nom court avant le FQDN -> hostname -f faux sur les 14 machines 6. API Icinga jamais activee (garde `creates:` d'api setup) 7. restic refuse tout le lot si un chemin declare manque LE CINQUIEME DEPASSAIT ICINGA. hostname -f rend le PREMIER nom : toute la flotte se croyait appelee « mon-01 ». Visible sur le certificat d'Icinga, mais le meme piege attendait Postfix (myhostname), les journaux, les certificats. FQDN d'abord. CE QU'ON NE CORRIGE PAS : icinga2 api setup REECRIT NodeName d'apres le nom court et nomme ses certificats d'apres lui. Aligne avant, il est ecrase ; aligne apres, les certificats portent le mauvais nom. On adopte sa convention : le depot appelle l'API par le nom court, celui que le certificat porte. serveur_icinga_node_name derive desormais de l'INVENTAIRE, pas d'ansible_fqdn — un fait qui depend du resolveur et rendait « mon-01 » alors que le FQDN etait bon. Le commentaire ecrit pour avertir qu'une sequence accolade-diese casse les gabarits Jinja contenait cette sequence, et cassait le gabarit. Neuf hotes en echec pour un avertissement mal redige. Sept devis CONFORME, prouver 36/36, make test 0. Neuf sauvegardes reussies. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-13 03:36:56 -04:00
# --- Publier l'AC vers le depot de sauvegarde ---
# Le depot rapporte l'etat des instantanes a cette API et doit VERIFIER le pair. Il lui
# faut donc cette AC — mais lui est un SERVICE et nous une APPLICATION : il se deploie
# AVANT nous, et exiger son attente inverserait le graphe des couches (refuse par P08 le
# 2026-08-12). C'est donc a NOUS de la lui porter, une fois que `icinga2 api setup` l'a
# creee. Sens correct : l'application rejoint le service, jamais l'inverse.
- name: Publier l'AC d'Icinga vers le depot de sauvegarde
when: groups['serveur_backup'] | default([]) | length > 0
ansible.builtin.slurp:
src: "{{ serveur_icinga_ca }}"
register: serveur_icinga_ca_contenu
- name: Deposer l'AC sur le depot de sauvegarde
when: groups['serveur_backup'] | default([]) | length > 0
ansible.builtin.copy:
content: "{{ serveur_icinga_ca_contenu.content | b64decode }}"
dest: "{{ serveur_icinga_ca_destination_depot }}"
owner: root
group: root
mode: "0644"
delegate_to: "{{ groups['serveur_backup'] | first }}"
# --- A QUI PARLER -------------------------------------------------------------
- name: Déclarer le destinataire des alertes
ansible.builtin.template:
src: setops-users.conf.j2
dest: /etc/icinga2/conf.d/setops-users.conf
owner: root
group: nagios
mode: "0640"
when: serveur_icinga_destinataire | length > 0
notify: Redemarrer icinga2
# DIRE CE QU'ON NE FAIT PAS. Sans destinataire, Icinga notifie `root@localhost` — une
# adresse que personne ne lit. Le silence alerterait alors dans le vide.
- name: Dire que personne ne recevra les alertes
ansible.builtin.debug:
msg: >-
`serveur_icinga_destinataire` n'est pas renseigne : les notifications iront a
`root@localhost`, que personne ne lit. La supervision VERRA les defauts sans
pouvoir les dire. Declarer l'adresse au plan.
when: serveur_icinga_destinataire | length == 0