From 63437b57261f9cc766db26aede8e3a85eb1aaf13 Mon Sep 17 00:00:00 2001 From: Daniel Allaire Date: Mon, 14 Sep 2026 10:08:50 -0400 Subject: [PATCH] le site pouvait inseminer un locataire, pas se configurer lui-meme MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Deux defauts qui s additionnaient, et un message qui accusait le mauvais. 1. Le site n avait AUCUN moyen d autoriser une cle d administration. Un locataire declare ssh_baseline_cles_admin ; cote site, rien ne transmettait cette liste. Ses machines n autorisaient que la cle de cloud-init. 2. Le rebond etait pose sans condition. Depuis le poste c est juste — aucune route directe. Depuis le runner du site, qui vit DANS le site, c est un detour qui casse : il doit s authentifier aupres de la frontiere ou sa cle n est pas autorisee. Et OpenSSH rend alors Host key verification failed / Connection closed by UNKNOWN port 65535 — un message qui accuse les cles d HOTE alors que l echec est une AUTHENTIFICATION, et sur le SAUTEUR, pas sur la cible. Le critere du rebond est desormais es-tu une MACHINE du site, pas es-tu dans un RESEAU du site : le poste porte 10.37.0.17, donc il est dans le reseau management, et il aurait perdu son rebond alors qu il en a besoin. L amorcage est circulaire et se rompt par le poste : lui seul entrait, il pose la cle, le runner est ensuite autonome. Verifie : 5/5 machines du site. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01Crgis8CxCWkAGFA1ecBz3q --- scripts/site_inventaire.py | 62 +++++++++++++++++++++++++++++++++++++- 1 file changed, 61 insertions(+), 1 deletion(-) diff --git a/scripts/site_inventaire.py b/scripts/site_inventaire.py index d3047c0..79c830a 100755 --- a/scripts/site_inventaire.py +++ b/scripts/site_inventaire.py @@ -71,6 +71,39 @@ GROUPE_SOCLE = ["serveur_debian", "serveur_durci"] GROUPE_FLOTTE = "hotes_actifs" + +def _controleur_est_une_machine_du_site() -> bool: + """Le controleur EST-IL l'une des machines que l'underlay declare ? + + C'EST LA BONNE QUESTION, ET LA PREMIERE VERSION POSAIT LA MAUVAISE. Elle demandait + « suis-je dans un reseau du site ? » — or le poste de l'exploitant porte `10.37.0.17`, + donc il est dans le reseau `management` du site, et il aurait perdu son rebond alors + qu'il en a besoin : ses paquets arrivent sur une autre patte de la frontiere, avec + d'autres regles. + + Etre DANS un reseau du site ne dit rien de ce qu'on peut atteindre. Etre une MACHINE + du site, si : la frontiere les laisse se parler entre elles. + + En cas de doute — adresses illisibles, underlay muet — on rend False : poser le rebond + est le comportement d'avant, donc le seul qu'on sache sur. Degrader, jamais deviner. + """ + import subprocess + try: + sortie = subprocess.run(["ip", "-4", "-o", "addr", "show"], + capture_output=True, text=True, timeout=5).stdout + except Exception: + return False + locales = {m.split("/")[0] for ligne in sortie.splitlines() for m in ligne.split() + if "/" in m and m[0].isdigit()} + if not locales: + return False + try: + declarees = {str(h.get("ip")) for h in underlay_mod.hotes(None) if h.get("ip")} + except Exception: + return False + return bool(locales & declarees) + + def plan_dir() -> Path | None: """Le `plan/` du SITE, a cote de son `underlay.yml` — derive du symlink, jamais redit. @@ -266,7 +299,34 @@ def inventaire() -> dict: communes["serveur_backup_pubkey"] = str(intrants["backup_pubkey"]) if intrants.get("cle_ssh"): communes["ansible_ssh_private_key_file"] = intrants["cle_ssh"] - if intrants.get("rebond"): + # LE SITE N'AVAIT AUCUN MOYEN D'AUTORISER UNE CLE D'ADMINISTRATION (2026-09-14). + # + # Un locataire declare `ssh_baseline_cles_admin` dans ses group_vars, et `ssh_baseline` + # les pose sur toute sa flotte. Cote site, rien ne transmettait cette liste : ses + # machines n'autorisaient donc que la cle posee par cloud-init a leur naissance. + # + # CE QUE CA COUTAIT, ET C'EST STRUCTUREL : le runner du SITE ne pouvait entrer sur + # AUCUNE machine du site. Il sait inseminer un locataire — c'est prouve — et il ne + # savait pas configurer l'hebergeur qui le porte. Tout le site avait ete deploye + # depuis le poste de l'exploitant, et rien ne disait que c'etait la seule voie. + if intrants.get("cles_admin"): + communes["ssh_baseline_cles_admin"] = intrants["cles_admin"] + # LE REBOND NE SERT QU'A CELUI QUI EST DEHORS (2026-09-14). + # + # Il etait pose sans condition. Depuis le poste de l'exploitant c'est juste : aucune + # route directe ne mene aux zones du site. Depuis le runner du site — qui vit DANS une + # de ces zones — c'est un detour qui casse : il doit s'authentifier aupres de la + # frontiere, ou sa cle n'est pas autorisee, et OpenSSH rend alors + # + # Host key verification failed. + # Connection closed by UNKNOWN port 65535 + # + # un message qui accuse les cles d'HOTE alors que l'echec est une authentification, et + # sur le SAUTEUR, pas sur la cible. Une heure de fausse piste. + # + # ON NE DEMANDE PAS UN INTRANT DE PLUS : le controleur sait ou il est. S'il porte deja + # une adresse dans un reseau du site, il n'a personne a sauter. + if intrants.get("rebond") and not _controleur_est_une_machine_du_site(): communes["ansible_ssh_common_args"] = ( f"-o ProxyJump={intrants['rebond']} -o StrictHostKeyChecking=no")