84 lines
3.8 KiB
Python
84 lines
3.8 KiB
Python
|
|
#!/usr/bin/env python3
|
||
|
|
"""La cle d'amorcage inscrite au plan du SITE est-elle CELLE de ce runner ?
|
||
|
|
|
||
|
|
LE PLAN PORTE UNE TRANSCRIPTION, ET UNE TRANSCRIPTION PREND DU RETARD (2026-09-13).
|
||
|
|
|
||
|
|
`runner_cle_publique`, dans `<SITE>/plan/10-intrants.yml`, recopie la cle publique du
|
||
|
|
runner du site. Elle est deposee par cloud-init sur le SEUL hote d'un tenant qui porte
|
||
|
|
`serveur_ops_tenant` — c'est ce qui rend l'insemination possible.
|
||
|
|
|
||
|
|
En reconstruisant `site-ops-01`, `setops` a recu une paire NEUVE. Cette ligne, elle, n'a
|
||
|
|
pas bouge. Les deux se lisent pareil : meme algorithme, meme commentaire final
|
||
|
|
`setops@site-ops-01.genese.internal`. Seul le materiel differe, et aucun coup d'oeil ne
|
||
|
|
les distingue.
|
||
|
|
|
||
|
|
CE QUE CA A COUTE : quatorze machines clonees, puis `Permission denied (publickey)` sur
|
||
|
|
la seule que le site devait amorcer. Le message accusait une cle absente ; elle etait la,
|
||
|
|
au mauvais materiel — et le clone etant deja fait, la correction du plan ne suffit plus :
|
||
|
|
il faut RECREER la machine, puisque la cle se pose a la naissance.
|
||
|
|
|
||
|
|
CETTE GARDE NE DEMANDE RIEN AU RESEAU. Le runner du site EST la machine qui insemine :
|
||
|
|
sa cle est sous sa main. Deux secondes ici valent la materialisation d'une flotte
|
||
|
|
entiere la-bas.
|
||
|
|
|
||
|
|
ELLE NE S'APPLIQUE QUE LORSQUE LES DEUX CLES NOMMENT LE MEME HOTE. Lancee depuis le poste
|
||
|
|
d'un exploitant, la cle locale est la SIENNE : comparer la declarerait fausse. Degrader,
|
||
|
|
jamais deviner — on se tait et on laisse passer.
|
||
|
|
"""
|
||
|
|
from __future__ import annotations
|
||
|
|
|
||
|
|
import sys
|
||
|
|
from pathlib import Path
|
||
|
|
|
||
|
|
RACINE = Path(__file__).resolve().parents[1]
|
||
|
|
sys.path.insert(0, str(RACINE / "scripts"))
|
||
|
|
|
||
|
|
|
||
|
|
def materiel_et_hote(ligne: str) -> tuple[str, str]:
|
||
|
|
"""(materiel de la cle, hote du commentaire) — ('', '') si la ligne n'est pas une cle."""
|
||
|
|
parts = ligne.split()
|
||
|
|
return (parts[1], parts[-1]) if len(parts) > 2 else ("", "")
|
||
|
|
|
||
|
|
|
||
|
|
def verifier() -> tuple[bool, str]:
|
||
|
|
try:
|
||
|
|
import underlay
|
||
|
|
plan = str((underlay.lire_plan_site("10-intrants.yml") or {})
|
||
|
|
.get("runner_cle_publique") or "").strip()
|
||
|
|
except Exception as e: # pas de site monte
|
||
|
|
return True, f"aucun plan de site lisible ({e.__class__.__name__}) — rien a comparer."
|
||
|
|
if not plan:
|
||
|
|
return True, "le plan du site ne declare aucune cle d'amorcage — rien a comparer."
|
||
|
|
|
||
|
|
pub = Path.home() / ".ssh" / "id_ed25519.pub"
|
||
|
|
if not pub.is_file():
|
||
|
|
return True, f"{pub} absent — cette machine n'est pas le runner du site."
|
||
|
|
|
||
|
|
mat_plan, hote_plan = materiel_et_hote(plan)
|
||
|
|
mat_local, hote_local = materiel_et_hote(pub.read_text(encoding="utf-8").strip())
|
||
|
|
|
||
|
|
if not (hote_plan and hote_plan == hote_local):
|
||
|
|
return True, f"cle locale de `{hote_local or 'inconnu'}`, plan de `{hote_plan or 'inconnu'}` — pas le meme hote, aucune comparaison."
|
||
|
|
|
||
|
|
if mat_plan != mat_local:
|
||
|
|
return False, (
|
||
|
|
"la cle d'amorcage du plan n'est PAS celle de ce runner.\n"
|
||
|
|
f" au plan ...{mat_plan[-20:]}\n"
|
||
|
|
f" reelle ...{mat_local[-20:]}\n"
|
||
|
|
"Les deux portent le meme commentaire ; seul le materiel differe.\n"
|
||
|
|
"\n"
|
||
|
|
"Toute machine DEJA creee porte la perimee : la corriger ne suffit pas,\n"
|
||
|
|
"il faut la RECREER — la cle se pose a la naissance.\n"
|
||
|
|
"\n"
|
||
|
|
" 1. relever : cat ~/.ssh/id_ed25519.pub\n"
|
||
|
|
" 2. corriger : runner_cle_publique dans <SITE>/plan/10-intrants.yml\n"
|
||
|
|
" 3. recreer : make raser HOTE=<runner> ... puis make creer-vm HOTE=<runner>")
|
||
|
|
|
||
|
|
return True, f"cle d'amorcage conforme (...{mat_local[-20:]}, {hote_local})."
|
||
|
|
|
||
|
|
|
||
|
|
if __name__ == "__main__":
|
||
|
|
ok, message = verifier()
|
||
|
|
print(("OK : " if ok else "Refus: ") + message, file=sys.stdout if ok else sys.stderr)
|
||
|
|
raise SystemExit(0 if ok else 2)
|