Le stockage jumbo (iSCSI, Ceph) est porté par un réseau indépendant de deux
switches 10G, sans câble commun avec la fabric convergée des sleipnir. Le
modèle l'ignorait : le devis déclarait les VLAN 20/30/31 sur les switches
convergés et les mettait dans leurs trunks. C'était faux.
Chaque réseau porte une `fabric` (`principal` par défaut). Le devis ne
configure que celle du routeur, et énonce explicitement ce qu'il ne couvre
pas au lieu de le taire — VLAN, trunks et spanning-tree d'une autre fabric
ne le regardent pas.
Les `deny` de l'ACL couvrent en revanche toutes les fabrics : la règle porte
sur l'adresse de destination, pas sur le câblage. Si un chemin s'ouvre un
jour vers le stockage, il est déjà fermé.
Preuves : 24 OK, 0 échec.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Deux incohérences visibles à la relecture du devis complet.
`bifrost-01` portait le SVI Vlan10 -> 10.0.0.1 et était déclaré dans
`underlay.hotes` à 10.0.0.2. Une interface VLAN n'a qu'une adresse primaire :
les deux ne pouvaient pas être vraies. L'entrée datait d'avant la désignation
du routeur, quand 10.0.0.1 était une passerelle abstraite. Le routeur est
déclaré à l'adresse du SVI qu'il porte, et `make underlay` refuse désormais
la divergence.
La partie B créait `vlan 40` alors que son trunk ne le transporte pas — le
transit ne relie que le routeur à la frontière. VLAN exclu de la partie B,
comme il l'est déjà des trunks généraux.
Preuves : 24 OK, 0 échec ; garde de cohérence exercée.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Sans MLAG, le routage est porté par un unique switch (`underlay.routeur`).
Le devis émettait un jeu unique de SVI sans dire à quel switch il
s'adressait : appliqué sur les trois, il aurait créé autant de conflits
d'adresses qu'il y a de zones.
Il se scinde désormais en deux :
- partie A (switch routeur) : VLANs, SVI, ACL, trunks, routes ;
- partie B (switches d'accès, L2 pur) : mêmes VLANs pour commuter les trames
étiquetées, une adresse de gestion par switch tirée de `underlay.hotes`
avec `ip default-gateway` vers le routeur, et les trunks. Aucun SVI de
zone, aucune ACL, aucune route.
Gardes : `make underlay` refuse un `routeur` inconnu des hôtes déclarés ; la
partie B avertit qu'un seul de ses blocs de gestion va sur chaque machine.
Sans routeur désigné, l'en-tête signale le risque de duplication au lieu de
laisser croire que le devis est applicable partout.
Preuves : 24 OK, 0 échec.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
La bordure devient un artefact dérivé, comme le devis switch — et le chemin
qui y mène est enfin déclaré.
`make devis-opnsense` (+ preuve P24) dérive la politique de bordure du
registre des flux : les flux `pair: externe`, que `resoudre_flux.py` saute
volontairement parce qu'ils relèvent de la frontière et non du pare-feu
d'hôte. Aucun port, aucune adresse, aucun nom d'hôte dans le générateur.
Le lien manquait dans tous les fichiers : le devis switch ne contenait pas
une seule `ip route`. Un réseau underlay portant `passerelle_sortie` le
déclare — il vit dans l'underlay et non dans un tenant parce que la
frontière route vers TOUS les supernets tenants par le même saut, donc il
ne peut dériver d'aucun `index`. `devis-reseau` en tire deux routes :
l'aller (sortie générale) et le retour vers l'administration, dont l'absence
a coûté la passe de déploiement du 2026-07-29 — la réponse revient au
pare-feu par une autre interface que celle où l'état a été créé, et se fait
jeter en silence.
Les réseaux d'administration viennent de l'intrant `nftables_admin_ssh` :
même source unique que la garde anti-lockout des nftables et l'alias
SETOPS_ADMIN. Les trois pare-feux et les routes ne peuvent plus diverger.
La frontière est réglable depuis la console (section « Frontière » du
panneau Intrants) ; les identifiants d'API restent interdits d'écriture par
le GUI et vivent dans la voûte.
Correctifs de la même passe :
- le panneau refusait d'enregistrer les intrants de la frontière : le
garde-fou confondait une référence de voûte `{{ vault_* }}` préservée
avec un secret soumis. Il regarde désormais la valeur, pas le nom.
- `supprimer_vm_debian.yml` ne chargeait que `proxmox.vault.yml` pour ses
secrets ; retirer ce reliquat aurait cassé `make detruire`. Aligné sur le
playbook de clonage, voûte unique en dernier.
- documentation : la voûte est unique, `proxmox.vault.yml` n'est qu'un
reliquat de compatibilité.
Preuves : 24 OK, 0 échec. Cas de rejet du validateur d'underlay exercés un
par un ; résolution du jeton Proxmox vérifiée en exécution réelle.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Le modele derive l'adressage par tenant (VLAN 1000+index*10+zone), mais la
fabric physique qui porte la flotte (mgmt switches/Proxmox/OOB, iSCSI, Ceph
public+cluster) n'appartient a aucun tenant. Elle est desormais codifiee.
- scripts/underlay.py + make underlay : charge/affiche/valide underlay.yml
(VLAN < 1000, sous-reseaux hors des supernets tenant 10.(10+index).0.0/16).
- underlay.yml gitignore (comme le vault) ; gabarit public underlay.yml.example ;
surchargeable par SETOPS_UNDERLAY.
- devis_reseau : section 0. Underlay + VLAN underlay sur le trunk, selon dialecte.
- P23 : underlay.py --verifier ; sautee si underlay.yml absent (comme P16 sans vault).
23/23 preuves. Doc : docs/audit/README.md, wiki page reseau, CHANGELOG.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>