pare-feu est-ouest : applique, et le port derive enfin compris des deux cotes

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 <noreply@anthropic.com>
This commit is contained in:
Daniel Allaire 2026-08-24 17:58:54 -04:00
parent a1997774be
commit bf8e27ef85
3 changed files with 70 additions and 3 deletions

View file

@ -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

View file

@ -13,7 +13,7 @@
| # | Preuve | Affirmations | Statut | Detail |
|---|---|---|---|---|
| P01 | Lint (ansible-lint) | AFF-006 | ✅ OK |  |
| P01 | Lint (ansible-lint) | AFF-006 | ✅ OK | <unknown>: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. |

View file

@ -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