From fae3cc8838addfce698fb053a3da7716d8468363 Mon Sep 17 00:00:00 2001 From: Daniel Allaire Date: Mon, 14 Sep 2026 21:44:03 -0400 Subject: [PATCH] l edge servait du snakeoil, et deux ecritures d une meme regle MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Le certificat bouchon de Debian sur les trois noms. serveur_nginx l a pour defaut, avec un commentaire d avant la PKI ; un locataire le remplace en group_vars, l inventaire du site est dynamique et n en a pas. Les autres replis rendaient un service muet — celui-la rend du TLS qui RESSEMBLE a du TLS : le cadenas s affiche et rien n est prouve. site_inventaire construisait sa propre liste d expositions, avec edge = le groupe de l application. Vrai tant que le site n avait pas d edge. client_pki retient un FQDN si son edge est un groupe de cet hote : aucun ne correspondait, et le certificat ne portait que le nom de la machine. La boucle est remplacee par un appel a expositions_des_applications. Et la cicatrice de site-forge-01 — un cert renouvele n atteint personne tant que son consommateur n est pas recharge — a ete refaite sur la machine suivante. Les 6 noms sont maintenant servis et verifies contre l AC du site. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01Crgis8CxCWkAGFA1ecBz3q --- CHANGELOG.md | 65 ++++++++++++++++++++++++++++++++++++++ scripts/site_inventaire.py | 51 ++++++++++++++++++++++++------ 2 files changed, 107 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4b4e333..3691307 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,70 @@ # CHANGELOG — Set-OPS +## 2026-09-14 (23) — Du TLS qui ressemblait a du TLS, et une regle qu'un tenant n'a jamais eu besoin d'ecrire + +Trois defauts de plus sur le chemin de l'edge, et le premier est le plus grave de la +journee. + +### L'edge servait `ssl-cert-snakeoil.pem` + +Le certificat bouchon de Debian, sur les trois noms. `serveur_nginx` l'a pour DEFAUT, +avec un commentaire qui date d'avant la PKI : *« a remplacer par des certificats de l'AC +interne plus tard »*. Un locataire le remplace dans `group_vars/serveur_nginx.yml` ; +l'inventaire du site est DYNAMIQUE et n'a pas de group_vars. + +LES AUTRES REPLIS RENDAIENT UN SERVICE MUET OU UNE REGLE INERTE. Celui-la rend **du TLS +qui ressemble a du TLS** : le cadenas s'affiche, la connexion est chiffree, et rien n'est +prouve — le certificat n'est signe par personne et ne porte aucun des noms servis. C'est +la seule sorte de panne qui rassure. + +### Deux ecritures d'une meme regle, et seule l'une a appris + +`site_inventaire.py` construisait sa PROPRE liste d'expositions, avec `edge` = le groupe +de l'application. Le commentaire disait pourquoi : *« le site n'a pas d'edge, donc chaque +service se sert lui-meme »*. C'etait vrai jusqu'a hier. + +`client_pki` retient un FQDN si son `edge` est un GROUPE DE CET HOTE. L'edge appartient a +`serveur_nginx` ; cette boucle rendait `serveur_grafana`, `serveur_icingaweb2`... Aucun +nom ne correspondait. La boucle est remplacee par un appel a +`expositions_des_applications` — la regle n'existe plus qu'une fois. + +### La cicatrice refaite sur la machine suivante + +`site-forge-01` porte ce commentaire depuis des semaines : *« Un cert renouvele sur disque +reste servi perime tant que le consommateur n'est pas recharge. La cicatrice est deja dans +le depot ; on ne la refait pas. »* Elle a ete refaite sur `site-edge-01`, qui n'avait pas +de `client_pki_reload_services`. + + disque : forge, pki, dns, sauvegarde, observatoire, vigie, site-edge-01 + servi : site-edge-01 + +### Ou en est l'edge + + certificat servi les 6 noms, signe par l'AC du site + verification TLS verif_tls=0 depuis le poste, contre la racine du site + vhosts forge, observatoire, vigie — en 443 + +### CE QUI RESTE, ET C'EST UNE VRAIE PIECE + +Les trois noms repondent en TLS **verifie**, puis rien : `http=000`. L'edge ne joint pas +ses amonts, et le devis le dit lui-meme : + + note : serveur_nginx declare un port `derive` que le plan du site ne resout pas + — aucune regle emise. + +`serveur_nginx` declare bien `egress port: derive, pair: expositions`. Ce flux n'a JAMAIS +eu besoin d'etre resolu a la frontiere : chez un locataire, les passerelles de zone sont +tenues par le SDN de Proxmox, et le trafic edge -> amont ne traverse pas le boitier. **Au +site, elles sont tenues par la frontiere** — et c'est le premier endroit ou un edge doit +franchir la bordure pour atteindre ce qu'il relaie. + +Resoudre `expositions` en une regle PAR AMONT (son hote, son port) est la piece qui +manque. Elle se voit maintenant parce que le site est la premiere fabric ou un edge et +ses services vivent dans des zones differentes. + +Et `forge` relaie en `http://10.37.33.11:443` — du clair vers un port TLS, d'ou son `400`. +L'amont d'une exposition deja servie en TLS doit etre `https://`. + ## 2026-09-14 (22) — L'edge du site est debout, et quatre replis silencieux l'ont retarde `site-edge-01` est nee, deployee, et sert `forge`, `observatoire` et `vigie` en 443. Le diff --git a/scripts/site_inventaire.py b/scripts/site_inventaire.py index 710a116..4cda723 100755 --- a/scripts/site_inventaire.py +++ b/scripts/site_inventaire.py @@ -31,6 +31,7 @@ from pathlib import Path sys.path.insert(0, str(Path(__file__).resolve().parent)) import yaml # noqa: E402 import underlay as U # noqa: E402 +from inventory_rules import expositions_des_applications # noqa: E402 from inventory_rules import integrations_universelles # noqa: E402 # L'inventaire des tenants passe par ce compte ; le site n'a aucune raison d'en differer. @@ -386,15 +387,28 @@ def inventaire() -> dict: # LES EXPOSITIONS : le nom du SERVICE, pas celui de la machine. Un nom de service # survit au demenagement du service ; un nom de machine, non. # - # `edge` nomme le GROUPE qui sert ce FQDN — c'est ce qu'attend `hosts_statiques`. - # Chez un tenant c'est l'edge nginx, qui termine le TLS pour tout le monde. Le site - # n'a pas d'edge : chaque service se sert lui-meme, donc le groupe est le sien. La - # forme reste la meme, ce qui la remplit change. - expositions: list[dict] = [] - for nom_app, app in applications.items(): - for fqdn in (app.get("expose") or []): - expositions.append({"fqdn": str(fqdn), "edge": str(app.get("groupe") or ""), - "application": nom_app}) + # `edge` nomme le GROUPE qui sert ce FQDN — c'est ce qu'attend `hosts_statiques`, et + # c'est de la que `client_pki` tire les SAN du certificat. + # + # ON APPELLE LA FONCTION PARTAGEE, ON NE LA REECRIT PLUS (2026-09-14). + # + # Cette boucle disait : « le site n'a pas d'edge, donc chaque service se sert + # lui-meme, donc le groupe est le sien ». C'etait vrai — jusqu'au jour ou le site a + # eu un edge. La meme regle vivait alors a DEUX endroits : ici, et dans + # `expositions_des_applications`, qui lit le registre des domaines. Seule la seconde + # a appris ; celle-ci est restee sur l'ancienne verite. + # + # CE QUE CA A COUTE. `client_pki` retient un FQDN si son `edge` est un GROUPE DE + # CET HOTE. L'edge appartient a `serveur_nginx` ; cette boucle rendait + # `serveur_grafana`, `serveur_icingaweb2`... Aucun nom ne correspondait, et le + # certificat de `site-edge-01` ne portait QUE celui de la machine — du TLS correct + # sur trois noms que personne ne peut appeler. + # + # Deux ecritures d'une meme regle finissent par diverger. Celle-ci n'existe plus. + expositions = expositions_des_applications( + {"applications": applications}, + {"domaines_publics": (U.lire_plan_site("domaines.yml") or {}).get("domaines_publics") or {}}, + ) # --- LES GARDES DU PLAN, LA OU LE PLAN EST LU ---------------------------- # @@ -666,6 +680,25 @@ def inventaire() -> dict: # un. Les deux autres modes d'Icinga Web 2 (`ldap`, `external`) supposent # l'un ou l'autre ; ici, nginx authentifie et l'application le croit. "serveur_icingaweb2_auth": "locale", + # L'EDGE SERT LE CERTIFICAT DE L'AC INTERNE, PAS LE BOUCHON DE DEBIAN. + # + # `serveur_nginx` a pour DEFAUT `ssl-cert-snakeoil.pem`, avec un commentaire + # qui date d'avant la PKI : « a remplacer par des certificats de l'AC interne + # plus tard ». Chez un locataire, `group_vars/serveur_nginx.yml` le remplace. + # L'inventaire du site est DYNAMIQUE et n'a pas de group_vars : l'edge est + # donc ne en servant du snakeoil. + # + # C'EST LE PLUS GRAVE DES REPLIS DE LA JOURNEE. Les autres rendaient un + # service muet ou une regle inerte — celui-la rend du TLS qui RESSEMBLE a du + # TLS. Le cadenas s'affiche, la connexion est chiffree, et rien n'est prouve : + # le certificat servi n'est signe par personne et ne porte aucun des noms. + # + # Le chemin est celui que `client_pki` ecrit, et le meme que celui des + # locataires — une seule convention, pas deux. + "serveur_nginx_certificat": + "/etc/step/certs/{{ ansible_fqdn | default(ansible_hostname) }}.crt", + "serveur_nginx_cle": + "/etc/step/certs/{{ ansible_fqdn | default(ansible_hostname) }}.key", # Le depot du site, pour les machines du site qui y deposent. Vide s'il n'y # en a pas — `client_backup` refuse alors, plutot que de viser un nom qui # ne repond pas : mieux vaut un deploiement qui s'arrete qu'une sauvegarde