diff --git a/CHANGELOG.md b/CHANGELOG.md index b6055db..126be84 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,59 @@ # CHANGELOG — Set-OPS +## 2026-09-09 (8) — L'hote de supervision saturait par sa propre demonstration + +« mon-01 tape dans l'fond. » Il tapait, en effet. + + load average: 5,10 sur 4 coeurs + 8 processus check_disk, 70 a 99 % de CPU chacun, jusqu'a 28 minutes de vie + +`check_disk` 2.4.0-3+deb13u1 ne rend jamais la main sur cet hote (etat `R`, il boucle). +Icinga en relancait un a CHAQUE intervalle pour le service `disk` de son hote de +DEMONSTRATION, et aucun ne mourait. **L'hote de supervision etait sature par la +configuration d'exemple livree avec le paquet.** + +### Ce qui a ete retire, et pourquoi l'hote plutot que les services + +`conf.d/hosts.conf` definit `object Host NodeName` — un `localhost` de demonstration avec +`vars.disks`, `vars.http_vhosts`, `vars.os`. Les `apply Service` s'y accrochent : `disk`, +`http`, `swap`, `apt`, `load`, `procs`, `users`, `ssh`, `icinga`. Aucun ne decrit cet +ecosysteme, et trois etaient **rouges en permanence** — `swap` sur une VM sans swap, `http` +sur un port ou rien n'ecoute, `apt` pour un paquet a mettre a jour. + +On retire l'HOTE, pas les services : sans lui les `apply` ne s'accrochent a rien, et on ne +touche pas a un fichier que le paquet remplacera a la prochaine mise a jour. + +**Et ca garde ce qui servait** : `apply Service "ping4"` vise tout hote ayant une adresse, +donc les notres. Il est vert 14/14 au tenant. Retirer `services.conf` l'aurait emporte +avec le reste. + + avant : load 5,10 — 8 check_disk — 3 alarmes rouges permanentes + apres : load 0,77 — 0 check_disk — certificat 14/14, sante 14/14, ping4 14/14 + +### Trouve en verifiant : la supervision du SITE croyait tout mort + + hotes UP : 1/7 (site) 14/14 (tenant) + +Nos `object Host` sont verifies par `hostalive`, c'est-a-dire un ping. Le site est decoupe +en zones separees ; l'ICMP inter-zones n'etait declare nulle part, donc la frontiere +l'avalait — 100 % de perte, mesure. Et **Icinga SUPPRIME les notifications des services +d'un hote DOWN** : une supervision qui croit tout mort n'alerte plus de rien, tout en ayant +l'air de fonctionner. + +Le flux est desormais declare des DEUX cotes (`serveur_icinga` en egress, `serveur_debian` +en ingress) — et le registre a refuse la premiere moitie seule, ce qui est exactement sa +raison d'etre. `CODES_ICMP` apprend `echo-request` (un TYPE, pas un code de +destination-unreachable). Les regles d'hote sont posees sur les 21 machines. + +**Ce qui reste ouvert, et je le dis parce que le probleme n'est pas resolu :** le +generateur de la frontiere ne sait pas traduire un TYPE ICMP pour un pair INTERNE. Il le +note et n'emet rien : + + note : serveur_icinga declare un port `echo-request` que le plan du site ne resout pas + +Le site reste donc a 1/7. Corriger `devis_opnsense.py` pour l'ICMP interne est le prochain +geste — et c'est un geste sur le generateur de la frontiere, pas une retouche. + ## 2026-09-09 (7) — Le contrat des sondes ETAIT celui de Nagios, sans le savoir Question posee : « tu connais le paquet `monitoring-plugins` ? » diff --git a/docs/audit/preuve-2026-09-09.md b/docs/audit/preuve-2026-09-09.md index 760391b..bd08891 100644 --- a/docs/audit/preuve-2026-09-09.md +++ b/docs/audit/preuve-2026-09-09.md @@ -21,7 +21,7 @@ | P06 | Validateurs de registres (serveurs/apps/bases/domaines) | AFF-003 | ✅ OK | Registre des domaines valide. | | P07 | GUI (node --check) | AFF-033 | ✅ OK | JS du GUI : syntaxe valide (node --check), 1 nom(s) surveille(s) sans reference orpheline. | | P08 | Orchestration (couches + graphe) | AFF-070 | ✅ OK | Orchestration coherente : 41 groupes classes, aucun cycle, aucune arete en arriere. | -| P09 | Flux reseau (schema + matrice) | AFF-071 | ✅ OK | Flux coherents : 39 rôles, 101 flux, schéma + matrice OK. | +| P09 | Flux reseau (schema + matrice) | AFF-071 | ✅ OK | Flux coherents : 39 rôles, 103 flux, schéma + matrice OK. | | P10 | Handlers <-> notify | AFF-034, AFF-035 | ✅ OK | Tout notify pointe vers un handler du meme role (49 roles). | | P11 | Syntaxe des playbooks (--syntax-check) | AFF-083 | ✅ OK | serveur_resolveur_site | | P12 | Existence des runbooks cites | AFF-010, AFF-011, AFF-012, AFF-083 | ✅ OK | 17/17 runbooks/registres cites presents. | @@ -61,7 +61,7 @@ | P46 | Plancher /etc/hosts : un seul role en decide | — | ✅ OK | Un seul maitre du plancher — roles/hosts_statiques/tasks/main.yml : manage_etc_hosts: false ; et le gabarit maitre est pose (roles/hosts_statiques/templates/hos | | P47 | Zones inverses : couvrir l'occupe, et rien de plus | — | ✅ OK | Les zones inverses couvrent l'occupe et rien de plus (5 cas evalues, dont un site a quatre zones et un tenant a une). | | P48 | La carte d'orientation designe ce qui existe, et compte juste | — | ✅ OK | La carte designe 89 chemin(s) qui existent, et ses 7 chiffres correspondent a la mesure. | -| P49 | Registre des flux : la matrice d'audit est a jour | — | ✅ OK | Le registre des flux reproduit exactement ce que les `meta/flux.yml` declarent (119 lignes). | +| P49 | Registre des flux : la matrice d'audit est a jour | — | ✅ OK | Le registre des flux reproduit exactement ce que les `meta/flux.yml` declarent (121 lignes). | | P50 | Silences : un refus muet est declare, place en dernier, et motive | — | ✅ OK | 2 silence(s) declare(s), tous en sequence > 1 (la plus haute des 175 regles `pass`), tous non consignes et tous motives. | | P51 | Collections : toutes declarees, toutes epinglees | — | ✅ OK | 3 collection(s) et 2 bibliotheque(s) Python declarees et epinglees : ansible.posix==1.6.2, community.general==10.3.0, community.postgresql==3.10.2 | | P52 | Materialiser n'exige pas d'entrer dans le tenant | — | ✅ OK | `creer-vm` confirme par l'agent invite (API des hyperviseurs, deja utilisee pour creer), sans exiger d'entrer dans le tenant. | diff --git a/docs/registre-flux.md b/docs/registre-flux.md index 709a0ef..3bf5696 100644 --- a/docs/registre-flux.md +++ b/docs/registre-flux.md @@ -27,6 +27,7 @@ | `serveur_collabora` | ingress | 9980 | tcp | edge | clair | Éditeur servi au navigateur via l'edge (WebSocket WOPI ; TLS terminé à l'edge). | | `serveur_collabora` | ingress | 9980 | tcp | localhost | clair | Vérifications WOPI serveur→Collabora depuis Nextcloud co-localisé. | | `serveur_debian` | ingress | 22 | tcp | flotte, externe | ssh | Plan de gestion : administration et déploiement Ansible par SSH (inter-nœud ; l'accès depuis l'extérieur est filtré à l'OPNsense). | +| `serveur_debian` | ingress | echo-request | icmp | serveur_icinga | n-a | La supervision verifie que ce noeud repond (hostalive). Sans lui, elle le tient pour mort et supprime ses notifications. | | `serveur_debian` | ingress | frag-needed | icmp | externe | n-a | ICMP « fragmentation nécessaire » entrant : sans lui, un distant ne peut pas nous demander de réduire nos paquets — les transferts se figent. | | `serveur_debian` | egress | 80 | tcp | externe | clair | Dépôts apt en clair et redirections HTTP des miroirs (l'intégrité vient de la signature des paquets, pas du transport). | | `serveur_debian` | egress | 123 | udp | externe | n-a | Synchronisation d'horloge (NTP). Une dérive fait échouer la validation des certificats step-ca et l'authentification SSO. | @@ -49,6 +50,7 @@ | `serveur_icinga` | ingress | 5665 | tcp | serveur_backup | tls-requis | Le depot de sauvegarde depose ses resultats passifs (portee : process-check-result sur « sauvegarde: * »). | | `serveur_icinga` | ingress | 5665 | tcp | serveur_debian | tls-requis | Rapport passif de sante de chaque noeud (unites systemd en echec). | | `serveur_icinga` | egress | 5432 | tcp | serveur_postgresql | tls-requis | Base relationnelle du moteur Icinga (verify-full). | +| `serveur_icinga` | egress | echo-request | icmp | serveur_debian | n-a | La supervision verifie que ses hotes repondent (hostalive) : sans ce flux, elle les tient tous pour morts et supprime leurs notifications. | | `serveur_icingaweb2` | ingress | 8080 | tcp | edge | clair | Interface web servie via l'edge (TLS terminé à l'edge ; SSO possible via oauth2-proxy). | | `serveur_icingaweb2` | egress | 636 | tcp | serveur_openldap | tls-requis | Authentification des utilisateurs sur l'annuaire (LDAPS). | | `serveur_icingaweb2` | egress | 5432 | tcp | serveur_postgresql | tls-requis | Lecture d'IcingaDB (base relationnelle, verify-full). | @@ -111,7 +113,7 @@ ## Synthèse chiffrement - **clair** : 37 flux -- **n-a** : 3 flux +- **n-a** : 5 flux - **ssh** : 8 flux - **starttls** : 6 flux - **tls** : 10 flux diff --git a/roles/serveur_debian/meta/flux.yml b/roles/serveur_debian/meta/flux.yml index be36a19..d6cf99d 100644 --- a/roles/serveur_debian/meta/flux.yml +++ b/roles/serveur_debian/meta/flux.yml @@ -42,6 +42,19 @@ flux: chiffrement: n-a raison: "ICMP « fragmentation nécessaire » sortant : c'est ainsi que nos hôtes signalent l'overlay à 1450 aux correspondants distants." + # LA FACE RECEPTRICE DU PING DE SUPERVISION. + # + # `serveur_icinga` declare l'egress ; le registre REFUSE un egress sans son ingress en + # face, et il a bien fait : c'est precisement l'oubli qui a coute cinq `TimeoutError` + # sur le rapport de sante quelques heures plus tot. Ici la garde l'a dit tout de suite. + - sens: ingress + port: echo-request + protocole: icmp + pair: serveur_icinga + chiffrement: n-a + partage: true + raison: "La supervision verifie que ce noeud repond (hostalive). Sans lui, elle le tient pour mort et supprime ses notifications." + - sens: egress port: 123 protocole: udp diff --git a/roles/serveur_icinga/meta/flux.yml b/roles/serveur_icinga/meta/flux.yml index d048fda..e8dd274 100644 --- a/roles/serveur_icinga/meta/flux.yml +++ b/roles/serveur_icinga/meta/flux.yml @@ -64,6 +64,32 @@ flux: chiffrement: tls-requis partage: true raison: "Rapport passif de sante de chaque noeud (unites systemd en echec)." + # LA SUPERVISION DOIT POUVOIR JOINDRE CE QU'ELLE SUPERVISE (mesure du 2026-09-09). + # + # Nos `object Host` sont verifies par `hostalive`, c'est-a-dire un ping. Sans ce flux, + # l'Icinga du SITE tenait 6 de ses 7 machines pour MORTES — et Icinga SUPPRIME les + # notifications des services d'un hote DOWN. Une supervision qui croit tout mort + # n'alerte plus de rien : c'est pire que pas de supervision, parce qu'elle a l'air de + # fonctionner. + # + # Les hotes acceptent deja tout l'ICMP localement (`serveur_debian`) ; c'est la + # FRONTIERE qui filtre l'inter-zones, et elle ne connait que ce qui est declare. Le + # tenant ne le voyait pas : ses zones se parlent deja. Le site, decoupe en pattes + # separees, non. + # + # Le pair est `serveur_debian` — tout noeud — pour la meme raison que le rapport de + # sante : une integration universelle n'est pas un role porte au plan, et la frontiere + # ne resout que les roles portes. + # + # CE QUE CE PING APPORTE, malgre le `ttl` qui fait deja parler le silence : un signal + # INDEPENDANT du chemin de rapport. Si le rapport passif casse, le ping le distingue + # d'une machine reellement tombee. + - sens: egress + port: echo-request + protocole: icmp + pair: serveur_debian + chiffrement: n-a + raison: "La supervision verifie que ses hotes repondent (hostalive) : sans ce flux, elle les tient tous pour morts et supprime leurs notifications." - sens: egress port: 5432 protocole: tcp diff --git a/roles/serveur_icinga/tasks/main.yml b/roles/serveur_icinga/tasks/main.yml index be35c55..e31d477 100644 --- a/roles/serveur_icinga/tasks/main.yml +++ b/roles/serveur_icinga/tasks/main.yml @@ -219,6 +219,36 @@ # 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. +# L'HOTE D'EXEMPLE LIVRE PAR ICINGA : RETIRE (mesure du 2026-09-09). +# +# `conf.d/hosts.conf` definit `object Host NodeName` — un `localhost` de demonstration +# avec `vars.disks`, `vars.http_vhosts`, `vars.os`. Les `apply Service` de +# `conf.d/services.conf` s'y accrochent : `disk`, `http`, `swap`, `apt`, `load`, `procs`, +# `users`. Aucun ne decrit cet ecosysteme, et trois etaient ROUGES EN PERMANENCE : +# +# swap : SWAP CRITICAL - 0% free (une VM sans swap) +# http : connect to 127.0.0.1:80 (rien n'ecoute la) +# apt : 1 package upgradable +# +# Trois alarmes qui ne peuvent que rester rouges, dans le seul endroit qui doit rester +# lisible. C'est deja une raison suffisante — une supervision creuse est pire qu'aucune. +# +# MAIS LE QUATRIEME NE FAISAIT PAS QUE MENTIR, IL NUISAIT. `check_disk` +# 2.4.0-3+deb13u1 ne rend jamais la main sur cet hote (etat `R`, boucle, quels que soient +# ses arguments). Icinga en relancait un a CHAQUE intervalle, et aucun ne mourait : +# +# 8 processus check_disk, 70 a 99 % de CPU chacun, jusqu'a 28 minutes de vie +# charge 5,10 sur 4 coeurs — l'hote de supervision sature par sa propre demonstration +# +# On retire l'HOTE plutot que les services : sans lui, les `apply` ne s'accrochent a rien, +# et on ne touche pas a un fichier que le paquet remplacera a la prochaine mise a jour. +# Les hotes de cet ecosysteme sont declares par `setops-hotes.conf`. +- name: Retirer l'hote de demonstration livre par Icinga + ansible.builtin.file: + path: /etc/icinga2/conf.d/hosts.conf + state: absent + notify: Redemarrer icinga2 + # LES SONDES DECLAREES PAR LES ROLES (docs/supervision-conception.md). # # On lit les `meta/supervision.yml` sur le CONTROLEUR, pas sur la cible : c'est le depot diff --git a/scripts/resoudre_flux.py b/scripts/resoudre_flux.py index 8e62b64..313d2ad 100644 --- a/scripts/resoudre_flux.py +++ b/scripts/resoudre_flux.py @@ -332,6 +332,12 @@ def _supernets_voisins() -> list[str]: # au lieu d'en gagner une. Constate le 2026-08-06 sur les 14 hotes a la fois. CODES_ICMP = { "frag-needed": "icmp type destination-unreachable icmp code frag-needed", + # `echo-request` est un TYPE, pas un code de destination-unreachable — d'ou l'absence + # de `icmp code` ici. La supervision s'en sert pour `hostalive` : sans ce flux, + # l'Icinga du site tenait 6 de ses 7 machines pour mortes, et Icinga SUPPRIME les + # notifications des services d'un hote DOWN. Une supervision qui croit tout mort + # n'alerte plus de rien (2026-09-09). + "echo-request": "icmp type echo-request", }