client_backup : le premier rapport a Icinga part d'un marqueur a lui ; le pare-feu ne compte que ses critiques
La copie de l'AC d'Icinga est deposee aussi par client_sante, plus tot : sur une flotte neuve elle ne changeait jamais ici, et rien ne partait (reconstruction de Chezlepro). client_backup retient desormais l'empreinte de l'Icinga qui l'a entendu, apres le rapport. eprouver_parefeu ne s'arrete plus sur les critiques presents avant l'activation. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
249d37d2c4
commit
20a5e44803
5 changed files with 70 additions and 19 deletions
|
|
@ -113,6 +113,8 @@ client_backup_icinga_hote: "{{ (groups['serveur_icinga'] | default([]) | first)
|
||||||
client_backup_icinga_utilisateur: "setops-depot"
|
client_backup_icinga_utilisateur: "setops-depot"
|
||||||
client_backup_icinga_motdepasse: "{{ vault_icinga_api_depot | default('') }}"
|
client_backup_icinga_motdepasse: "{{ vault_icinga_api_depot | default('') }}"
|
||||||
client_backup_ca_verification: "/etc/setops/icinga-ca.crt"
|
client_backup_ca_verification: "/etc/setops/icinga-ca.crt"
|
||||||
|
# L'Icinga auquel ce noeud a deja rapporte (empreinte de son AC) — voir tasks/verifier.yml.
|
||||||
|
client_backup_marque_icinga: "/etc/setops/client_backup-icinga-entendu"
|
||||||
client_backup_icinga_ca_source: "/var/lib/icinga2/ca/ca.crt"
|
client_backup_icinga_ca_source: "/var/lib/icinga2/ca/ca.crt"
|
||||||
|
|
||||||
# `ttl` du resultat passif : au-dela, Icinga perime le service de lui-meme — c'est ce qui
|
# `ttl` du resultat passif : au-dela, Icinga perime le service de lui-meme — c'est ce qui
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
daemon_reload: true
|
daemon_reload: true
|
||||||
|
|
||||||
# PREMIER RAPPORT A UN ICINGA QUI NE NOUS A JAMAIS ENTENDUS — voir `tasks/verifier.yml`.
|
# PREMIER RAPPORT A UN ICINGA QUI NE NOUS A JAMAIS ENTENDUS — voir `tasks/verifier.yml`.
|
||||||
# Trois temps, dans cet ordre (les gestionnaires s'executent dans l'ordre de ce fichier) :
|
# Trois temps, puis la trace, dans cet ordre (les gestionnaires s'executent dans l'ordre de ce fichier) :
|
||||||
# deposer, pour que le depot porte un instantane de CETTE incarnation ; verifier le depot ;
|
# deposer, pour que le depot porte un instantane de CETTE incarnation ; verifier le depot ;
|
||||||
# verifier qu'il se restaure. Les unites sont `oneshot` : chacune rend la main une fois son
|
# verifier qu'il se restaure. Les unites sont `oneshot` : chacune rend la main une fois son
|
||||||
# rapport parti, et echoue — bruyamment — si la sauvegarde refuse (etat d'avant non remis)
|
# rapport parti, et echoue — bruyamment — si la sauvegarde refuse (etat d'avant non remis)
|
||||||
|
|
@ -26,3 +26,12 @@
|
||||||
name: setops-verification-restauration.service
|
name: setops-verification-restauration.service
|
||||||
state: started
|
state: started
|
||||||
listen: Premier rapport a Icinga
|
listen: Premier rapport a Icinga
|
||||||
|
|
||||||
|
- name: Retenir l'Icinga qui nous a entendus
|
||||||
|
ansible.builtin.copy:
|
||||||
|
content: "{{ client_backup_icinga_empreinte }}\n"
|
||||||
|
dest: "{{ client_backup_marque_icinga }}"
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
mode: "0600"
|
||||||
|
listen: Premier rapport a Icinga
|
||||||
|
|
|
||||||
|
|
@ -37,16 +37,6 @@
|
||||||
delegate_to: "{{ client_backup_icinga_hote }}"
|
delegate_to: "{{ client_backup_icinga_hote }}"
|
||||||
register: client_backup_ca_icinga
|
register: client_backup_ca_icinga
|
||||||
|
|
||||||
# UN ICINGA QUI NE NOUS A JAMAIS ENTENDUS (2026-09-30). Ses services `sauvegarde` et
|
|
||||||
# `restauration` sont CRITIQUES tant qu'aucun rapport n'est arrive — c'est voulu, le silence
|
|
||||||
# doit alerter. Mais les minuteurs ne rapportent que toutes les 4 h (depot) et le DIMANCHE
|
|
||||||
# (restauration) : apres chaque reconstruction, Icinga restait rouge jusqu'a une semaine,
|
|
||||||
# et on declenchait les controles a la main.
|
|
||||||
#
|
|
||||||
# Le noeud ne peut pas demander a Icinga s'il l'a deja entendu : son compte ne sait que
|
|
||||||
# DEPOSER. Le signal fiable est ICI — l'AC d'Icinga que le noeud recopie. Un Icinga refait a
|
|
||||||
# une AC neuve ; un noeud refait n'en a pas encore de copie. Dans les deux cas cette tache
|
|
||||||
# change, et le noeud rapporte aussitot (voir les gestionnaires).
|
|
||||||
- name: Déposer l'AC d'Icinga pour la vérification du pair
|
- name: Déposer l'AC d'Icinga pour la vérification du pair
|
||||||
when: client_backup_ca_presente.stat.exists
|
when: client_backup_ca_presente.stat.exists
|
||||||
ansible.builtin.copy:
|
ansible.builtin.copy:
|
||||||
|
|
@ -55,6 +45,44 @@
|
||||||
owner: root
|
owner: root
|
||||||
group: root
|
group: root
|
||||||
mode: "0644"
|
mode: "0644"
|
||||||
|
|
||||||
|
# UN ICINGA QUI NE NOUS A JAMAIS ENTENDUS (2026-09-30). Ses services `sauvegarde` et
|
||||||
|
# `restauration` sont CRITIQUES tant qu'aucun rapport n'est arrive — c'est voulu, le silence
|
||||||
|
# doit alerter. Mais les minuteurs ne rapportent que toutes les 4 h (depot) et le DIMANCHE
|
||||||
|
# (restauration) : apres chaque reconstruction, Icinga restait rouge jusqu'a une semaine.
|
||||||
|
#
|
||||||
|
# Le noeud ne peut pas demander a Icinga s'il l'a deja entendu : son compte ne sait que
|
||||||
|
# DEPOSER. Il retient donc LUI-MEME a quel Icinga il a rapporte — l'empreinte de son AC. Un
|
||||||
|
# Icinga refait a une AC neuve ; un noeud refait n'a pas de marqueur.
|
||||||
|
#
|
||||||
|
# UN MARQUEUR A LUI, PAS LA COPIE DE L'AC. La premiere version se fiait au changement de
|
||||||
|
# `icinga-ca.crt` — or `client_sante` depose le MEME fichier, plus tot dans le deploiement :
|
||||||
|
# sur une flotte neuve il etait deja la, « ok », et rien n'etait notifie. Vu a la
|
||||||
|
# reconstruction de Chezlepro du 2026-09-30 : `restauration` rouge sur sept noeuds, et le
|
||||||
|
# pare-feu arrete. L'epreuve precedente avait joue `client_backup` SEUL, et ne pouvait pas
|
||||||
|
# le voir.
|
||||||
|
#
|
||||||
|
# ECRIT APRES LE RAPPORT (dernier gestionnaire), jamais avant : un rapport rate laisserait
|
||||||
|
# sinon le noeud convaincu d'avoir ete entendu, et la passe suivante ne retenterait rien.
|
||||||
|
- name: Retenir l'empreinte de l'Icinga destinataire
|
||||||
|
when: client_backup_ca_presente.stat.exists
|
||||||
|
ansible.builtin.set_fact:
|
||||||
|
client_backup_icinga_empreinte: "{{ client_backup_ca_icinga.content | b64decode | hash('sha256') }}"
|
||||||
|
|
||||||
|
- name: A quel Icinga ce noeud a-t-il deja rapporte ?
|
||||||
|
when: client_backup_ca_presente.stat.exists
|
||||||
|
ansible.builtin.slurp:
|
||||||
|
src: "{{ client_backup_marque_icinga }}"
|
||||||
|
register: client_backup_icinga_entendu
|
||||||
|
failed_when: false
|
||||||
|
|
||||||
|
- name: Cet Icinga ne nous a jamais entendus — premier rapport
|
||||||
|
when:
|
||||||
|
- client_backup_ca_presente.stat.exists
|
||||||
|
- (client_backup_icinga_entendu.content | default('') | b64decode | trim) != client_backup_icinga_empreinte
|
||||||
|
ansible.builtin.debug:
|
||||||
|
msg: "Icinga {{ client_backup_icinga_empreinte[:12] }} n'a encore rien recu de {{ inventory_hostname }} : rapport immediat."
|
||||||
|
changed_when: true
|
||||||
notify: Premier rapport a Icinga
|
notify: Premier rapport a Icinga
|
||||||
|
|
||||||
- name: Installer curl pour le rapport passif
|
- name: Installer curl pour le rapport passif
|
||||||
|
|
|
||||||
|
|
@ -299,6 +299,11 @@ def eprouver(I: str, H: str, args: argparse.Namespace) -> int:
|
||||||
if hors or echecs:
|
if hors or echecs:
|
||||||
print(" REFUS D'ACTIVER : un flux reel hors des regles, ou un echec a comprendre d'abord.")
|
print(" REFUS D'ACTIVER : un flux reel hors des regles, ou un echec a comprendre d'abord.")
|
||||||
return 2
|
return 2
|
||||||
|
# LES CRITIQUES D'AVANT NE SONT PAS LES NOTRES (2026-09-30). Tout critique d'Icinga
|
||||||
|
# arretait la procedure — y compris ceux qui existaient avant l'activation : a la
|
||||||
|
# reconstruction de Chezlepro, des `restauration` rouges (rien a voir avec le pare-feu)
|
||||||
|
# l'ont arretee deux fois. On releve donc AVANT, et seul ce qui apparait apres compte.
|
||||||
|
crit_avant = set(critiques_icinga(I))
|
||||||
if activer(I, vmid, args) != 0:
|
if activer(I, vmid, args) != 0:
|
||||||
print(" ECHEC de l'activation.")
|
print(" ECHEC de l'activation.")
|
||||||
return 3
|
return 3
|
||||||
|
|
@ -307,8 +312,11 @@ def eprouver(I: str, H: str, args: argparse.Namespace) -> int:
|
||||||
change = sorted(k for k in avant if avant[k] != apres.get(k))
|
change = sorted(k for k in avant if avant[k] != apres.get(k))
|
||||||
print(f" apres : {sum(v == 'ok' for v in apres.values())}/{len(apres)} ok ; "
|
print(f" apres : {sum(v == 'ok' for v in apres.values())}/{len(apres)} ok ; "
|
||||||
f"changements : {', '.join(change) or 'aucun'}")
|
f"changements : {', '.join(change) or 'aucun'}")
|
||||||
crit = critiques_icinga(I)
|
crit_apres = critiques_icinga(I)
|
||||||
print(f" Icinga : {len(crit)} critique(s)" + (f" — {', '.join(crit)}" if crit else ""))
|
crit = sorted(set(crit_apres) - crit_avant)
|
||||||
|
print(f" Icinga : {len(crit)} critique(s) apparu(s)" + (f" — {', '.join(crit)}" if crit else "")
|
||||||
|
+ (f" ; {len(crit_avant)} deja present(s) avant, sans rapport avec le pare-feu"
|
||||||
|
if crit_avant else ""))
|
||||||
if change:
|
if change:
|
||||||
print(f" RETOUR ARRIERE : remettre `enable=0` sur la VM {vmid} "
|
print(f" RETOUR ARRIERE : remettre `enable=0` sur la VM {vmid} "
|
||||||
f"(/nodes/<noeud>/qemu/{vmid}/firewall/options).")
|
f"(/nodes/<noeud>/qemu/{vmid}/firewall/options).")
|
||||||
|
|
|
||||||
|
|
@ -60,15 +60,19 @@ def couverture() -> None:
|
||||||
|
|
||||||
# UN ICINGA NEUF ENTEND LE NOEUD TOUT DE SUITE (2026-09-30) : sinon `restauration` reste
|
# UN ICINGA NEUF ENTEND LE NOEUD TOUT DE SUITE (2026-09-30) : sinon `restauration` reste
|
||||||
# rouge jusqu'au dimanche apres chaque reconstruction.
|
# rouge jusqu'au dimanche apres chaque reconstruction.
|
||||||
|
# PAS SUR LA COPIE DE L'AC : `client_sante` la depose aussi, plus tot — sur une flotte
|
||||||
|
# neuve elle ne change donc jamais ici (reconstruction de Chezlepro, 2026-09-30).
|
||||||
taches = yaml.safe_load((RACINE / "roles/client_backup/tasks/verifier.yml").read_text())
|
taches = yaml.safe_load((RACINE / "roles/client_backup/tasks/verifier.yml").read_text())
|
||||||
depot_ac = [t for t in taches if "AC d'Icinga pour la" in t.get("name", "")]
|
notifiants = [t.get("name", "") for t in taches if t.get("notify") == "Premier rapport a Icinga"]
|
||||||
verifier(bool(depot_ac) and depot_ac[0].get("notify") == "Premier rapport a Icinga",
|
verifier(notifiants and all("AC d'Icinga pour la" not in n for n in notifiants)
|
||||||
"la copie de l'AC d'Icinga (Icinga neuf ou noeud neuf) declenche le premier rapport")
|
and any("jamais entendus" in n for n in notifiants),
|
||||||
|
"le premier rapport part d'un marqueur propre a client_backup, pas de la copie partagee de l'AC")
|
||||||
gest = yaml.safe_load((RACINE / "roles/client_backup/handlers/main.yml").read_text())
|
gest = yaml.safe_load((RACINE / "roles/client_backup/handlers/main.yml").read_text())
|
||||||
ordre = [g["ansible.builtin.systemd"]["name"] for g in gest if g.get("listen") == "Premier rapport a Icinga"]
|
ecoute = [g for g in gest if g.get("listen") == "Premier rapport a Icinga"]
|
||||||
|
ordre = [g.get("ansible.builtin.systemd", {}).get("name", "marqueur") for g in ecoute]
|
||||||
verifier(ordre == ["setops-sauvegarde.service", "setops-verification-depot.service",
|
verifier(ordre == ["setops-sauvegarde.service", "setops-verification-depot.service",
|
||||||
"setops-verification-restauration.service"],
|
"setops-verification-restauration.service", "marqueur"],
|
||||||
f"premier rapport : deposer, puis verifier le depot, puis la restauration ({ordre})")
|
f"premier rapport : deposer, verifier le depot, la restauration, PUIS retenir ({ordre})")
|
||||||
|
|
||||||
|
|
||||||
# --- 2. L'outil de noeud, avec des doublures ------------------------------------------
|
# --- 2. L'outil de noeud, avec des doublures ------------------------------------------
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue