From bf8e27ef859789db37c0bdf3e89e946692101cf3 Mon Sep 17 00:00:00 2001 From: Daniel Allaire Date: Mon, 24 Aug 2026 17:58:54 -0400 Subject: [PATCH] pare-feu est-ouest : applique, et le port `derive` enfin compris des deux cotes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit verifier_ports traitait depuis toujours un port non numerique comme « pas une ecoute fixe ». Le generateur est-ouest l'envoyait tel quel a l'API Proxmox : « invalid port 'derive' », six regles refusees. Une meme notion, comprise d'un cote et pas de l'autre. Sauter est la bonne reponse : depuis que le resolveur est la seule porte, PowerDNS n'ecoute que sur 127.0.0.1:5300 -- aucune regle est-ouest n'a d'objet pour lui. Les trois groupes t*-srv-powerdns sont retires. Mais un flux qu'on n'applique pas doit SE VOIR : le devis recense et affiche les ports sautes avec leur raison. Sans cette note, sauter proprement serait devenu un trou silencieux. Les deux devis sont clos. Flotte verifiee : DNS, Internet, apt, cache joignable. Co-Authored-By: Claude Opus 5 --- CHANGELOG.md | 37 +++++++++++++++++++++++++++++++++ docs/audit/preuve-2026-08-24.md | 4 ++-- scripts/devis_proxmox_fw.py | 32 +++++++++++++++++++++++++++- 3 files changed, 70 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index be52938..d14e6be 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,42 @@ # CHANGELOG — Set-OPS +## 2026-08-24 — Les deux pare-feu appliqués, et un `derive` qui n'était compris que d'un côté + +``` +frontiere a creer : 0 | a retirer : 0 | inchange : 65 + 15 routes +est-ouest a creer : 0 | a mettre a jour : 0 | a retirer : 0 +``` + +Flotte vérifiée après coup, sur les cinq hôtes : DNS interne, Internet, `apt` sans erreur, +et le cache d'artefacts joignable (`HTTP 200`). + +### Un port `derive` que seul un générateur sur deux savait lire + +J'avais déclaré le port de PowerDNS `derive` — il vaut 53 seul sur son hôte, 5300 derrière +le résolveur. `verifier_ports` traite depuis toujours un port non numérique comme « pas une +écoute fixe ». Le générateur est-ouest, lui, l'envoyait **tel quel** à l'API Proxmox : + +``` +dport: derive -> 400 « invalid format - invalid port 'derive' » six règles refusées +``` + +Une même notion, comprise d'un côté et pas de l'autre. Elle l'est désormais des deux. + +**Et sauter est la bonne réponse, pas un contournement** : depuis que le résolveur du +tenant est la seule porte, l'autoritatif n'écoute que sur `127.0.0.1:5300`. Aucune règle +est-ouest n'a d'objet pour lui — les trois groupes `t*-srv-powerdns` sont devenus périmés +et ont été retirés. + +**Mais un flux qu'on n'applique pas doit se voir.** Le devis recense et affiche les ports +sautés, avec la raison. Sans cette note, sauter proprement serait devenu un trou +silencieux — la faute que ce dépôt traque sous tous ses déguisements. + +### Le même piège qu'à la frontière, une heure plus tôt + +Là aussi le premier essai a signalé des échecs, et là aussi une partie du travail était +déjà écrite : le devis suivant est passé de « 6 à créer, 10 à mettre à jour » à « 0 à +créer, 1 à mettre à jour ». Un refus partiel n'est pas un refus. + ## 2026-08-24 — La frontière appliquée, et une contrainte qui n'était écrite nulle part `a creer : 0 | a retirer : 0 | inchange : 65 + 15 routes` — le devis est clos. La flotte de diff --git a/docs/audit/preuve-2026-08-24.md b/docs/audit/preuve-2026-08-24.md index 8181112..7934a0e 100644 --- a/docs/audit/preuve-2026-08-24.md +++ b/docs/audit/preuve-2026-08-24.md @@ -13,7 +13,7 @@ | # | Preuve | Affirmations | Statut | Detail | |---|---|---|---|---| -| P01 | Lint (ansible-lint) | AFF-006 | ✅ OK |  | +| P01 | Lint (ansible-lint) | AFF-006 | ✅ OK | :1: SyntaxWarning: invalid decimal literal | | P02 | Tests unitaires (inventory_host) | — | ✅ OK | >>> le verrou tient : aucune VM n'aurait ete touchee | | P03 | Diff-vide du plan — TOUTES les instances | AFF-001, AFF-004, AFF-030, AFF-031, AFF-032 | ✅ OK | 4 instance(s) verifiee(s) — OPS-Chezlepro-lab, OPS-Chezlepro, OPS-Technolibre, OPS-Patient0 : plan et inventaire applique coincident. | | P04 | Groupes <-> playbooks homonymes | AFF-008 | ✅ OK | | @@ -37,7 +37,7 @@ | P22 | Plan de recette a jour (genere du wiki) | AFF-002 | ✅ OK | Plan de recette à jour (22 sections). | | P23 | Underlay sans collision avec la plage tenant | AFF-103 | ✅ OK | Underlay conforme : 7 reseau(x), aucune collision avec la plage tenant. | | P24 | Frontiere nord/sud : acces d'administration declare | AFF-104 | ✅ OK | CONFORME : frontiere nord/sud, 62 regles, 15 routes, admin=10.0.0.0/24,10.17.0.0/24,10.29.19.41/32,192.168.254.2/32,192.168.255.2/32. | -| P25 | Pare-feu Proxmox : est-ouest intra-tenant derive | AFF-107 | ✅ OK | CONFORME : pare-feu Proxmox, 3 tenant(s), 54 groupe(s), 86 regle(s). | +| P25 | Pare-feu Proxmox : est-ouest intra-tenant derive | AFF-107 | ✅ OK | CONFORME : pare-feu Proxmox, 3 tenant(s), 51 groupe(s), 80 regle(s). | | P26 | Integrations universelles : aucun hote laisse de cote | AFF-108 | ✅ OK | 15 hote(s) x 5 integration(s) universelle(s) : aucune lacune, aucune recopie (0 exemption(s) derivee(s) du service rendu). | | P27 | Propriete des intrants : hebergeur et tenant separes | AFF-109 | ✅ OK | 8 cle(s) de cluster chez l'hebergeur, aucune recopiee dans les group_vars du tenant. | | P28 | Pools Proxmox : un par tenant, sans collision | AFF-110 | ✅ OK | CONFORME : 3 pool(s) Proxmox, 35 VM placee(s), aucun nom ni VMID en collision. | diff --git a/scripts/devis_proxmox_fw.py b/scripts/devis_proxmox_fw.py index 0bed9c7..b1a6273 100644 --- a/scripts/devis_proxmox_fw.py +++ b/scripts/devis_proxmox_fw.py @@ -90,9 +90,30 @@ def _verifier_unicite(noms: list[str], tenant: str) -> None: vus[nom] = role +# Les ports DERIVES ne sont pas des ecoutes fixes : ils dependent de ce que l'hote porte. +# Le pare-feu de l'hyperviseur, lui, ne connait que des nombres. +# +# CONSTATE LE 2026-08-24, A L'APPLICATION : `dport: derive` est parti tel quel vers l'API, +# qui a repondu « invalid port 'derive' » -- six regles refusees. `verifier_ports` savait +# deja sauter un port non numerique ; ce generateur-ci ne le savait pas. +# +# CE QUE CA VEUT DIRE POUR POWERDNS, le seul role concerne : depuis que le resolveur du +# tenant est la seule porte, l'autoritatif n'ecoute que sur 127.0.0.1:5300. Aucune regle +# est-ouest n'a d'objet pour lui — sauter est donc la BONNE reponse, pas un contournement. +# +# Les ports sautes sont RECENSES et affiches avec le devis : un flux qu'on n'applique pas +# doit se voir, sinon c'est un trou silencieux. +PORTS_DERIVES: set[str] = set() + + def _ports(fl: dict) -> list[str]: p = fl["port"] - return [str(x) for x in (p if isinstance(p, list) else [p])] + tous = [str(x) for x in (p if isinstance(p, list) else [p])] + fixes = [x for x in tous if x.isdigit()] + for x in tous: + if not x.isdigit(): + PORTS_DERIVES.add(x) + return fixes def construire(tenants: list[tuple[str, str, dict]]) -> dict: @@ -370,6 +391,15 @@ def main(argv: list[str]) -> int: f"{total_g} groupe(s), {total_r} regle(s).") return 0 print(json.dumps(devis, indent=2, ensure_ascii=False) if args.json else rendre(devis)) + # UN FLUX QU'ON N'APPLIQUE PAS DOIT SE VOIR. Sauter un port derive est la bonne + # reponse, mais le taire en ferait un trou silencieux. + if PORTS_DERIVES and not args.json: + print(f"\n note : {len(PORTS_DERIVES)} port(s) DERIVE(s) non rendus ici — " + f"{', '.join(sorted(PORTS_DERIVES))}.") + print(" Un port derive depend de ce que l'hote porte ; le pare-feu de " + "l'hyperviseur ne connait que des nombres.") + print(" Cas connu : PowerDNS derriere le resolveur du tenant n'ecoute que sur " + "127.0.0.1 — aucune regle est-ouest n'a d'objet pour lui.") return 0