flux : sans voir son site, un ecosysteme qui en depend ne regenere pas ses pare-feux
Sur le runner d un locataire (ni underlay.yml ni plan du site), make flux reecrivait des regles amputees de tout lien au site : AXFR du DNS public, collecte de la fabric, insemination. Le generateur s abstient et le dit ; les regles committees font foi. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
be06def899
commit
f3e8883083
2 changed files with 81 additions and 0 deletions
|
|
@ -644,6 +644,22 @@ def _sources_admin_ssh_site() -> list[str]:
|
||||||
return sorted(set(srcs))
|
return sorted(set(srcs))
|
||||||
|
|
||||||
|
|
||||||
|
PAIRES_DU_SITE = {"fabric", "frontiere", "runner_site", "dns_public_site", "voisins_site"}
|
||||||
|
|
||||||
|
|
||||||
|
def _depend_du_site(data: dict) -> bool:
|
||||||
|
"""Un groupe porte par cet ecosysteme recoit-il un flux d'une paire qui vient du site ?"""
|
||||||
|
flux = charger_flux()
|
||||||
|
for g, membres in _enfants(data).items():
|
||||||
|
if not (membres.get("hosts") or {}):
|
||||||
|
continue
|
||||||
|
for fl in flux.get(g, []):
|
||||||
|
p = fl.get("pair")
|
||||||
|
if fl.get("sens") == "ingress" and PAIRES_DU_SITE & set(p if isinstance(p, list) else [p]):
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
def generer_nftables(flux_par_role: dict[str, list[dict]], site: bool = False) -> list[Path]:
|
def generer_nftables(flux_par_role: dict[str, list[dict]], site: bool = False) -> list[Path]:
|
||||||
if site:
|
if site:
|
||||||
data = _inventaire_site()
|
data = _inventaire_site()
|
||||||
|
|
@ -656,6 +672,25 @@ def generer_nftables(flux_par_role: dict[str, list[dict]], site: bool = False) -
|
||||||
else:
|
else:
|
||||||
data = yaml.safe_load(_inventaire().read_text(encoding="utf-8")) or {}
|
data = yaml.safe_load(_inventaire().read_text(encoding="utf-8")) or {}
|
||||||
admin_ssh = _sources_admin_ssh()
|
admin_ssh = _sources_admin_ssh()
|
||||||
|
# UN ECOSYSTEME QUI DEPEND DE SON SITE NE SE GENERE PAS SANS LE VOIR (2026-09-30).
|
||||||
|
#
|
||||||
|
# Le runner d'un locataire ne porte ni `underlay.yml` ni le plan du site. Les paires
|
||||||
|
# qui en dependent — `fabric`, `frontiere`, `runner_site`, `dns_public_site`,
|
||||||
|
# `voisins_site` — ne s'y resolvent a rien, et les regles sortaient AMPUTEES sans un
|
||||||
|
# mot : a la reconstruction de Technolibre, son runner a reecrit trois pare-feux
|
||||||
|
# sans le transfert de zone depuis le DNS public du site, sans la collecte de la
|
||||||
|
# fabric, sans l'insemination par le runner du site. Deployes, ils auraient coupe
|
||||||
|
# trois liens avec le site.
|
||||||
|
#
|
||||||
|
# On n'ecrit donc RIEN : les fichiers committes, generes par qui voit le site (le
|
||||||
|
# poste de l'exploitant, le runner du site), font foi — et le runner les deploie.
|
||||||
|
import underlay as underlay_mod
|
||||||
|
if _depend_du_site(data) and underlay_mod.chemin() is None:
|
||||||
|
print("note : cet ecosysteme depend de son site (fabric, frontiere, runner ou DNS "
|
||||||
|
"public du site), et le site n'est pas visible ici (aucun underlay.yml) : "
|
||||||
|
"rien n'est regenere — les regles committees font foi. Les generer depuis un "
|
||||||
|
"poste qui voit le site.", file=sys.stderr)
|
||||||
|
return []
|
||||||
actifs_noms = set(_hotes_du_groupe(data, "hotes_actifs"))
|
actifs_noms = set(_hotes_du_groupe(data, "hotes_actifs"))
|
||||||
ip_par_hote = _ip_par_hote(data)
|
ip_par_hote = _ip_par_hote(data)
|
||||||
ports_plan = _ports_du_plan_site() if site else _ports_du_plan()
|
ports_plan = _ports_du_plan_site() if site else _ports_du_plan()
|
||||||
|
|
|
||||||
46
scripts/tests/test_flux_sans_site.py
Normal file
46
scripts/tests/test_flux_sans_site.py
Normal file
|
|
@ -0,0 +1,46 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Sans voir son site, un ecosysteme qui en depend ne regenere pas ses pare-feux.
|
||||||
|
|
||||||
|
POURQUOI (2026-09-30). Le runner d'un locataire ne porte ni `underlay.yml` ni le plan du
|
||||||
|
site : `make flux` y resolvait a rien les paires venues du site (`fabric`, `frontiere`,
|
||||||
|
`runner_site`, `dns_public_site`, `voisins_site`) et reecrivait des regles AMPUTEES — sans le
|
||||||
|
transfert de zone depuis le DNS public du site, sans la collecte de la fabric, sans
|
||||||
|
l'insemination. Le generateur doit s'abstenir : les fichiers committes font foi.
|
||||||
|
"""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
RACINE = Path(__file__).resolve().parents[2]
|
||||||
|
sys.path.insert(0, str(RACINE / "scripts"))
|
||||||
|
|
||||||
|
import resoudre_flux as rf # noqa: E402
|
||||||
|
import underlay # noqa: E402
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> int:
|
||||||
|
try:
|
||||||
|
import yaml
|
||||||
|
data = yaml.safe_load(rf._inventaire().read_text(encoding="utf-8")) or {}
|
||||||
|
except Exception as e: # pas d'instance montee ici
|
||||||
|
print(f"SAUTE aucune instance lisible ({type(e).__name__})")
|
||||||
|
return 0
|
||||||
|
if not rf._depend_du_site(data):
|
||||||
|
print("SAUTE l'instance montee ne depend pas de son site : rien a garder")
|
||||||
|
return 0
|
||||||
|
vrai = underlay.chemin
|
||||||
|
underlay.chemin = lambda: None # un runner de locataire : le site est invisible
|
||||||
|
try:
|
||||||
|
ecrits = rf.generer_nftables(rf.charger_flux())
|
||||||
|
finally:
|
||||||
|
underlay.chemin = vrai
|
||||||
|
if ecrits:
|
||||||
|
print(f"ECHEC site invisible, et pourtant {len(ecrits)} pare-feu(x) regeneres (amputes)")
|
||||||
|
return 1
|
||||||
|
print("OK — site invisible : aucun pare-feu regenere, les regles committees font foi.")
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
sys.exit(main())
|
||||||
Loading…
Reference in a new issue