| **D-01** | OPNsense est une frontière **nord/sud**, pas la passerelle des zones | le routage inter-zone reste au débit ligne ; la bordure ne voit pas l'est-ouest | `frontiere-opnsense.md` §1 | — |
| **D-02** | Le **lien de transit** vit dans l'underlay, pas dans un tenant | la frontière route vers tous les tenants par le même saut : il ne peut dériver d'aucun `index` | `frontiere-opnsense.md` §6 | P23 |
| **D-04** | Un point de routage porte **le même dernier octet** sur tous ses sous-réseaux — **dans l'adressage dérivé des tenants seulement** | on retient une adresse, pas treize. Dans l'underlay, l'adressage est dicté par les participants d'un lien physique : la règle y imposait un seuil arbitraire et empruntait sa valeur à la nomenclature d'un tenant | `frontiere-opnsense.md` §4 | P20 |
| **D-52** | Dans l'underlay, une passerelle doit être **l'adresse d'un hôte déclaré** sur ce réseau | remplace le comptage d'octets par une règle plus forte : elle attrape les passerelles fantômes | `underlay.py` | P23 |
| **D-49** | **Aucun commutateur ne route.** La frontière est le seul équipement L3 | l'EVPN a retiré les VLAN tenants du fil, puis la fusion du lien de sortie a rendu les nœuds de sortie **adjacents** à la frontière : plus un seul flux à router | `underlay.yml` | P23 |
| **D-50** | `passerelle` = la passerelle du sous-réseau, **où qu'elle vive** ; le SVI se **dérive** du rôle de son porteur | la clé signifiait « adresse du SVI du switch » — une hypothèse, pas une donnée. Un même moteur sert désormais les deux postures | `devis_reseau.py` | P23 |
| **D-51** | **Deux** commutateurs en paire, pas trois en étoile | le centre d'une étoile est sur **tous** les chemins : point de panne unique du plan de données. Deux liens vers deux commutateurs donnent la redondance qu'une étoile ne peut pas donner | `underlay.yml` | — |
| **D-06** | Les réseaux déclarent leur **fabric** ; un devis ne parle que de la sienne | le stockage jumbo vit sur ses propres commutateurs — un devis est une configuration, pas un inventaire | `sdn-evpn.md` §4 | P23 |
| **D-07** | **Pas d'ACL** sur cette fabric (`acl_inter_tenant: false`) | le matériel ne sait pas lier une ACL à un SVI ; des règles jamais liées auraient l'air d'isoler | `frontiere-opnsense.md` §1 | — |
| **D-43** | Les objets SDN d'un tenant (zone, VNets, sous-réseaux) sont **dérivés du seed** et émis par `make devis-sdn` | ajouter un tenant implique 13 objets de cluster ; les créer à la main dans un dépôt où tout dérive était la dernière lacune | `sdn-evpn.md` §2 | P30 |
| **D-44** | Le **nommage SDN dérive du tenant** : zone `<PRÉFIXE><index>`, VNet `<préfixe><index><zone>` | se lit sans table de correspondance ; les zones faites à la main (`VRF0017`) sont remplacées tant qu'elles sont vides. Seule contrainte conservée : **8 caractères**, imposée par Proxmox | `sdn-evpn.md` §2 | P30 |
| **D-08** | Le **routage tenant passe au SDN EVPN** — une zone par tenant | une zone EVPN est un VRF : l'isolation devient structurelle, pas réglementaire | `sdn-evpn.md` | P23 (MTU) |
| **D-09** | Le **filtrage inter-zone d'un tenant** se fait au même niveau (EVPN) | là où le routage a lieu | `sdn-evpn.md` §3 | — |
| **D-31** | Le filtrage est-ouest est appliqué **deux fois** : hyperviseur **puis** nftables d'hôte | défense en profondeur ; les deux dérivent du même registre par les mêmes fonctions, donc ne peuvent pas diverger | `sdn-evpn.md` §3 | P25 |
| **D-32** | **Tout** ce qui entre ou sort d'un tenant passe par la frontière | un VRF n'a qu'une sortie ; conséquence : la frontière devient un **prérequis de déploiement** | `sdn-evpn.md` §3 | — |
| **D-10** | L'**inter-tenant passe obligatoirement par la frontière** | il sort du VRF, donc traverse une bordure en `block` par défaut : il ne peut plus être oublié | `sdn-evpn.md` §3 | — |
| **D-11** | La **sortie générale est déclarée** dans le registre des flux | `block out` est un vrai default-deny ; un besoin oublié ne se manifeste pas par un refus clair | `frontiere-opnsense.md` §8 | P09 |
| **D-29** | L'**overlay EVPN plafonne à 1450** ; le transport doit donc dépasser 1500 | choix d'exploitation ; l'encapsulation VXLAN coûte 50 octets | `sdn-evpn.md` §5 | P23 (MTU du transport) |
| **D-30** | L'**ICMP « fragmentation nécessaire » est déclaré**, dans les deux sens | à 1450, tout ce qui traverse la frontière dépend de la découverte de MTU de chemin ; une bordure en default-deny la casse en silence | `roles/serveur_debian/meta/flux.yml` | P09 |
| **D-12** | Nommage : **`bifrost`** aux frontières, **`sleipnir`** à la fabric | Bifröst est le pont vers l'extérieur ; Sleipnir traverse les mondes sans en sortir | `frontiere-opnsense.md` §6 | — |
## 2. Qui possède quoi
| # | Décision | Pourquoi | Détail | Garde |
|---|---|---|---|---|
| **D-13** | Un **hébergeur** sert plusieurs **tenants** et a son tenant par défaut | Chezlepro est les deux à la fois, ce qui masquait la distinction | `frontiere-opnsense.md` §2 | — |
| **D-14** | `underlay.yml` appartient à l'**hébergeur**, monté par symlink | ce sont ses commutateurs, ses câbles ; le moteur est générique, un tenant n'en possède pas | `sdn-evpn.md`, `underlay.yml.example` | — |
| **D-15** | Ce symlink **ne suit pas**`make instance-utiliser` | basculer le tenant actif ne change pas la fabric | `frontiere-opnsense.md` §2 | — |
| **D-16** | Les intrants de la **frontière** se lisent chez l'hébergeur | un hébergeur n'a qu'une frontière pour tous ses tenants | `frontiere-opnsense.md` §2 | — |
| **D-17** | L'hébergeur **n'est pas déclaré** : le symlink le désigne | une seconde déclaration ouvrirait deux valeurs contradictoires | `frontiere-opnsense.md` §2 | — |
| **D-35** | Le **cluster Proxmox** appartient à l'hébergeur ; seuls le **golden template** et les **défauts de placement** restent au tenant | recopié chez chaque tenant, l'inventaire du cluster avait déjà divergé — deux listes de stockages contradictoires pour le même matériel | `config-proxmox.md` | P27 |
| **D-36** | Le panneau **nomme le propriétaire** de chaque section d'intrants | éditer une section « hébergeur » vaut pour tous ses tenants ; l'écran ne le disait pas | `scripts/inventory_gui.py` (`INTRANTS_SCHEMA`) | — |
| **D-37** | Chaque tenant a son **pool Proxmox** ; les noms courts de VM restent **identiques** d'un tenant à l'autre | 11 serveurs sur 14 sont homonymes — c'est la preuve que la nomenclature est un gabarit ; le coût est humain (la console affiche le nom), et le pool le corrige sans rien renommer | `devis_proxmox_pools.py` | P28 |
| **D-45** | L'**affinité de VM** (garder un groupe sur le même hyperviseur) attend **Proxmox 9** ; tenue à la main d'ici là | les *resource affinity rules* n'existent qu'en 9 ; en 8.4 seuls les groupes HA épinglent à des **nœuds**, pas des VM entre elles. Sans ressource HA déclarée, rien ne déplace ni ne sépare les VM — le sujet ne devient réel qu'en activant la HA | `sdn-evpn.md` | — |
| **D-46** | Un hébergeur porte **trois** catégories, pas deux : son **tenant**, ses **opérations**, le **plan de contrôle** | Chezlepro est hébergeur ET tenant, ce qui masquait des besoins n'appartenant à aucun tenant | `hebergeur-exploitation.md` §2 | — |
| **D-47** | Les **services d'exploitation** de l'hébergeur vivent dans **son dépôt**, et leurs VM se rattachent à un **pont VLAN, jamais un VNet** | un service qui observe la fabric ne peut pas dépendre d'elle : l'EVPN tombe, et la supervision tombe avec la raison de la panne | `hebergeur-exploitation.md` §1, §4 | — |
| **D-48** | Les **hyperviseurs** sont gérables par Ansible ; « hors flotte » ne vaut que pour les **commutateurs** et la **frontière** | ce sont des Debian joignables en SSH ; c'est la seule façon d'y poser un exportateur de métriques | `hebergeur-exploitation.md` §5 | — |
| **D-53** | Le **réseau et l'underlay** de l'hébergeur méritent leur **propre dépôt**, séparé de son tenant | `underlay.yml` et le cluster décrivent une infrastructure ; le dépôt de tenant décrit une organisation. Les mêler oblige à trancher qui possède quoi à chaque commit | `hebergeur-exploitation.md` §7 | — |
| **D-54** | `10.0.0.0/24` est réservé à l'**IPAM, la gestion des équipements et l'OOB** — accès sysadmin | aucun hyperviseur, aucune VM, aucun trafic tenant ; c'est la raison d'être des VLAN 11 et 40 | `underlay.yml` | — |
| **D-18** | Chaque tenant a un **responsable désigné** | sans lui, « qui peut décider de déménager cette organisation ? » se pose au pire moment | `migration-tenant.md` §3 | — |
| **D-38** | Toute authentification **web** passe par Keycloak ; LDAP est la **source unique** des comptes | une identité, un mot de passe ; aucun service ne tient son propre répertoire d'humains | `authentification.md` §1-2 | — |
| **D-39** | Les protocoles qui ne parlent pas OIDC (IMAP, SMTP) se lient **directement à LDAP** | le chemin varie, la source ne varie pas | `authentification.md` §2 | — |
| **D-40** | L'accès de secours passe par **`sudo` sur l'hôte**, pas par un compte web permanent | `service → Keycloak → LDAP` est en série : sans secours, une panne exclut tout le monde, y compris pour réparer | `authentification.md` §4 | — |
| **D-41** | Le formulaire de connexion locale n'est **pas proposé au repos** (`<rôle>_connexion_locale: false`) | il contourne la politique de mot de passe, le MFA et surtout la **révocation centrale** ; `sudo` est le mécanisme de réouverture | `authentification.md` §3 | — |
| **D-42** | Chaque rôle **déclare sa position** d'authentification (`meta/authentification.yml`), gardée par une preuve | une directive qu'aucune garde ne vérifie finit par ne plus être vraie — c'était le cas des 28 lignes d'intégration recopiées | `authentification.md` §5 | P29 |
| **D-19** | **Une seule voûte** par instance (`group_vars/all/vault.yml`) | un mot de passe, un endroit | `config-proxmox.md` | P18 |
| **D-20** | La liste des secrets se **recense**, elle ne s'écrit pas | trois copies manuelles ont existé, toutes ont divergé | `intrants-communs.md` §H | P18 |
| **D-21** | L'**empreinte du root CA n'est pas un secret** : elle se dérive à chaud | un `from-zero` régénère l'AC ; figée en voûte, elle serait périmée | `roles/client_pki/README.md` | — |
| **D-22** | Migrer un tenant, c'est **révoquer**, pas transmettre | sinon l'ancien hébergeur garde à vie l'accès aux secrets d'un client parti | `migration-tenant.md` §6 | — |
## 4. La méthode
| # | Décision | Pourquoi | Détail | Garde |
|---|---|---|---|---|
| **D-23** | Les cibles **hors flotte** reçoivent un **devis**, pas un rôle | commutateurs, frontière et SDN sont des objets de cluster ; un rôle boucle sur des hôtes | `sdn-evpn.md` §7 | — |
| **D-24** | Un devis **n'écrit rien** : il se relit, puis s'applique | proportionné au risque — une config ratée partitionne tout un cluster | `frontiere-opnsense.md` §7 | — |
| **D-25** | Le dépôt **n'affirme pas que ses devis s'appliquent**, il affirme qu'ils **dérivent** | leur syntaxe dépend d'un matériel que le dépôt ne possède pas | `audit/affirmations.md` §10 | — |
| **D-26** | Un modèle peut porter un **underlay** ; tous les hébergeurs n'ont pas le même matériel | générique public, étoffés en privé | `exemples/modeles/socle/README.md` | P17 |
| **D-27** | **Migration** : le receveur est prouvé prêt **avant** tout gel | l'interruption se réduit au delta et à la propagation DNS | `migration-tenant.md` §4 | — |
| **D-28** | Le mandat de migration est **signé par le tenant**, pas convenu entre hébergeurs | il n'y a pas de registre central pour arbitrer ; une organisation n'est pas la propriété de son hébergeur | `migration-tenant.md` §2 | — |
| **D-33** | Une intégration **universelle** est déclarée par le **rôle**, jamais recopiée par serveur | 28 des 57 lignes du plan disaient oui à ce qui vaut pour tous : elles n'existaient que pour être oubliées — et quatre l'avaient été | `integrations-vm.md` §Politique | P26 |
| **D-34** | Une **exemption** se dérive du **service rendu** (`sauf_role`), jamais d'un nom d'hôte | l'AC ne s'enrôle pas auprès d'elle-même ; l'exemption doit suivre step-ca si on le déplace | `roles/client_pki/meta/integration.yml` | P26 |
| Décision | Tenue du … au … | Renversée par | Pourquoi | Ce qu'il en reste |
|---|---|---|---|---|
| L'isolation inter-tenant est portée par des **ACL de commutateur** | 2026-07-07 → 08-03 | `059d76a` | le matériel ne sait pas lier une ACL à une interface de routage | `acl_inter_tenant: true` reste le défaut : une autre fabric peut en être capable |
| Le **routage inter-zone** est porté par les commutateurs L3 | 2026-07-07 → 08-03 | `e5ce2b9` | sans ACL, l'isolation devenait déclarative ; EVPN la rend structurelle | `routage_tenants: switch` reste le défaut et reste généré |
| L'`underlay.yml` vit à la racine du moteur, gitignoré | 2026-07-24 → 08-02 | `0eae97c` | consommé par deux générateurs, validé par une preuve, versionné nulle part | `SETOPS_UNDERLAY` permet toujours de le pointer ailleurs |
| **D-05** — un seul commutateur route, les autres en L2 pur | 2026-07-07 → 08-04 | 2026-08-04 | deux décisions séparées (EVPN, puis fusion du lien de sortie) ont vidé le rôle sans qu'on regarde leur effet cumulé : les trois SVI n'avaient plus aucun consommateur | le moteur sait toujours émettre des SVI — le modèle public s'en sert |
| **D-03** — le `/29` de transit, SVI en `.6`, `.3` réservée CARP | 2026-07-24 → 08-04 | 2026-08-04 | élargi en `/24` pour y loger les nœuds de sortie ; l'exemption d'invariant sous le `/24` tombe alors, et le `.1` revient à la passerelle | le plan `.1` passerelle / `.2 .3` pare-feux survit, décalé d'un cran |