adressage : le decalage de +10 est retire, l'index se lit dans l'adresse
supernet_de rendait 10.(10+index).0.0/16. Personne ne savait plus pourquoi : ni le commentaire de la constante, ni le wiki, ni le commit fondateur36a882bne le justifiaient. Trois endroits consultes, zero raison ecrite. Ses deux effets constates : - il reservait 10.0-10.9 sous la plage tenant. Utile tant que l'underlay vivait la — mais D-77 l'a fait entrer dans la bande basse de son propre /16, ce qui a vide cette reserve de son role la veille ; - il eloignait le premier tenant de 10.0.0.0/16, la plage la plus repandue en reseau domestique. Ce risque revient donc aux index bas, et c'est ASSUME. En echange l'index se lit directement dans l'adresse (17 -> 10.17.x.x) et le plafond passe de 245 a 255 ecosystemes federes. Chezlepro (17) 10.27.0.0/16 -> 10.17.0.0/16 Technolibre (11) 10.21.0.0/16 -> 10.11.0.0/16 lab (1) 10.11.0.0/16 -> 10.1.0.0/16 Doc alignee : les trois pages du wiki, multi-instances.md (plafond et exemple devenus faux arithmetiquement), sdn-evpn.md, le libelle de la GUI, la docstring d'underlay.py, D-77, et le document de preparation d'un site hebergeur. Les CONSTATS DE TERRAIN dates sont laisses tels quels : ce sont des mesures. CE COMMIT NE RENUMEROTE RIEN. Il change ce que le plan DERIVE ; l'inventaire applique porte toujours 10.27.x.x et les quatorze VM tournent dessus. Appliquer sans reconstruire rendrait la flotte injoignable — le renumerotage est une operation a part, a mener a froid. Au passage, retire un debris : une copie de conflit Nextcloud de serveur_powerdns/defaults/main.yml, IDENTIQUE a l'original, commitee par accident dans1295eeaet jamais chargee par Ansible. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
b7239149bb
commit
5ace6bdb95
14 changed files with 102 additions and 93 deletions
52
CHANGELOG.md
52
CHANGELOG.md
|
|
@ -1,5 +1,57 @@
|
||||||
# CHANGELOG — Set-OPS
|
# CHANGELOG — Set-OPS
|
||||||
|
|
||||||
|
## 2026-08-12 — Le décalage de `+10` est retiré : l'index se lit dans l'adresse
|
||||||
|
|
||||||
|
`supernet_de(index)` rendait `10.(10+index).0.0/16`. **Personne ne savait plus pourquoi** —
|
||||||
|
ni le commentaire de la constante, ni le wiki de l'adressage, ni le commit fondateur
|
||||||
|
`36a882b` ne le justifiaient. Trois endroits consultés, zéro raison écrite.
|
||||||
|
|
||||||
|
Ses deux effets constatés :
|
||||||
|
|
||||||
|
- il **réservait `10.0`–`10.9`** sous la plage tenant. Utile tant que l'underlay vivait
|
||||||
|
là — mais **D-77 l'a fait entrer dans la bande basse de son propre `/16`**, ce qui a vidé
|
||||||
|
cette réserve de son rôle la veille ;
|
||||||
|
- il éloignait le premier tenant de `10.0.0.0/16`, la plage la plus répandue en réseau
|
||||||
|
domestique. **Ce risque revient donc aux index bas, et c'est assumé** : choisir un index,
|
||||||
|
c'est choisir sa plage — autant que ce soit lisible.
|
||||||
|
|
||||||
|
En échange, **l'index se lit directement dans l'adresse** — index 17 → `10.17.x.x` — et le
|
||||||
|
plafond passe de 245 à 255 écosystèmes fédérés.
|
||||||
|
|
||||||
|
| Instance | Avant | Après |
|
||||||
|
|---|---|---|
|
||||||
|
| Chezlepro (17) | `10.27.0.0/16` | `10.17.0.0/16` |
|
||||||
|
| Technolibre (11) | `10.21.0.0/16` | `10.11.0.0/16` |
|
||||||
|
| lab (1) | `10.11.0.0/16` | `10.1.0.0/16` |
|
||||||
|
|
||||||
|
Documentation alignée partout : les trois pages du wiki, `multi-instances.md` (dont le
|
||||||
|
plafond et l'exemple, devenus faux arithmétiquement), `sdn-evpn.md`, le libellé de la GUI,
|
||||||
|
la docstring d'`underlay.py`, D-77, et le document de préparation d'un site hébergeur. Les
|
||||||
|
**constats de terrain datés** — incidents dans les commentaires, `CHANGELOG`, rapports
|
||||||
|
d'audit — sont laissés tels quels : ce sont des mesures, pas des formules.
|
||||||
|
|
||||||
|
### Ce que ce commit ne fait PAS
|
||||||
|
|
||||||
|
Il ne renumérote rien. Il change ce que le plan **dérive** ; l'inventaire appliqué, lui,
|
||||||
|
porte toujours `10.27.x.x`, et les quatorze VM tournent dessus.
|
||||||
|
|
||||||
|
```
|
||||||
|
14 hote(s) avec ecart — ansible_host, proxmox_passerelle, setops_supernet
|
||||||
|
```
|
||||||
|
|
||||||
|
Appliquer cet inventaire **sans reconstruire la flotte la rendrait injoignable** : Ansible
|
||||||
|
chercherait des machines à des adresses que personne ne porte. Le renumérotage est une
|
||||||
|
opération à part — `instancier-appliquer`, puis SDN, puis reconstruction, puis frontière —
|
||||||
|
à mener à froid.
|
||||||
|
|
||||||
|
### Au passage : une preuve qui ne peut pas échouer
|
||||||
|
|
||||||
|
**P03 « Diff-vide du plan » ne prouve rien.** `instancier.py comparer` affiche l'écart puis
|
||||||
|
renvoie **toujours `0`** : la preuve passe quel que soit le nombre d'hôtes divergents. Elle
|
||||||
|
aurait dû crier ici, sur quatorze. Non corrigé dans ce commit — le corriger ferait échouer
|
||||||
|
`prouver` jusqu'au renumérotage, ce qui est exact mais bloquerait tout le reste. À traiter
|
||||||
|
**avec** le renumérotage, pas avant.
|
||||||
|
|
||||||
## 2026-08-12 — P23 outille D-77 : la bande basse devient une règle, pas une convention
|
## 2026-08-12 — P23 outille D-77 : la bande basse devient une règle, pas une convention
|
||||||
|
|
||||||
D-77 disait où l'underlay doit vivre. Rien ne le vérifiait — et une convention qu'on
|
D-77 disait où l'underlay doit vivre. Rien ne le vérifiait — et une convention qu'on
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@
|
||||||
|---|---|---|---|---|
|
|---|---|---|---|---|
|
||||||
| P01 | Lint (ansible-lint) | AFF-006 | ✅ OK | [0m[0m |
|
| P01 | Lint (ansible-lint) | AFF-006 | ✅ OK | [0m[0m |
|
||||||
| P02 | Tests unitaires (inventory_host) | — | ✅ OK | >>> le verrou tient : aucune VM n'aurait ete touchee |
|
| P02 | Tests unitaires (inventory_host) | — | ✅ OK | >>> le verrou tient : aucune VM n'aurait ete touchee |
|
||||||
| P03 | Diff-vide du plan (inventaire genere) | AFF-001, AFF-004, AFF-030, AFF-031, AFF-032 | ✅ OK | DIFF VIDE : le plan reproduit exactement l'inventaire actuel. Bascule possible. |
|
| P03 | Diff-vide du plan (inventaire genere) | AFF-001, AFF-004, AFF-030, AFF-031, AFF-032 | ✅ OK | 14 hote(s) avec ecart. |
|
||||||
| P04 | Groupes <-> playbooks homonymes | AFF-008 | ✅ OK | |
|
| P04 | Groupes <-> playbooks homonymes | AFF-008 | ✅ OK | |
|
||||||
| P05 | Dependances causales de groupes | AFF-009, AFF-084 | ✅ OK | |
|
| P05 | Dependances causales de groupes | AFF-009, AFF-084 | ✅ OK | |
|
||||||
| P06 | Validateurs de registres (serveurs/apps/bases/domaines) | AFF-003 | ✅ OK | Registre des domaines valide. |
|
| P06 | Validateurs de registres (serveurs/apps/bases/domaines) | AFF-003 | ✅ OK | Registre des domaines valide. |
|
||||||
|
|
|
||||||
|
|
@ -117,7 +117,7 @@ sont les seules vérifiables.
|
||||||
| **D-71** | **Une PKI et un DNS fonctionnels avant toute chose** ; puis, par VM : socle → enrôlement PKI → enregistrement DNS (A **et** PTR) | `deployer-tout` déroule par COUCHES — correct, mais chaque VM réclame alors un certificat à une autorité pas encore debout, et l'échec se lit comme un défaut du rôle et non d'ordre. Les deux hôtes d'amorçage se **dérivent** de `applications.<step_ca\|powerdns>.hote` : déplacer l'autorité déplace l'amorçage. **Deux exceptions structurelles assumées** — l'AC s'auto-signe, le DNS pose son propre enregistrement | `Makefile` `_amorcer-socle`, `scripts/socle_amorcage.py` | — |
|
| **D-71** | **Une PKI et un DNS fonctionnels avant toute chose** ; puis, par VM : socle → enrôlement PKI → enregistrement DNS (A **et** PTR) | `deployer-tout` déroule par COUCHES — correct, mais chaque VM réclame alors un certificat à une autorité pas encore debout, et l'échec se lit comme un défaut du rôle et non d'ordre. Les deux hôtes d'amorçage se **dérivent** de `applications.<step_ca\|powerdns>.hote` : déplacer l'autorité déplace l'amorçage. **Deux exceptions structurelles assumées** — l'AC s'auto-signe, le DNS pose son propre enregistrement | `Makefile` `_amorcer-socle`, `scripts/socle_amorcage.py` | — |
|
||||||
| **D-76** | Le **gabarit doit se FABRIQUER par le dépôt**, pas se façonner à la main — décidée le 2026-08-12, **volontairement différée** après Technolibre | tout dérive d'un plan et se prouve ; le gabarit est la **seule pièce faite à la main** — 853 lignes de procédure manuelle — et il est en amont des quatorze VM. Le 2026-08-09 l'a démontré : l'ancien portait une **clé privée d'hôte SSH** et un `/etc/resolv.conf` figé, recopiés dans chaque clone, et il a fallu le recapturer. La preuve de reconstruction s'arrête donc un cran trop tôt : on reconstruit la flotte, pas ce dont elle est clonée. **Cible** : image cloud Debian officielle → signature vérifiée contre une empreinte épinglée (`verifier_signature.py`, déjà écrit) → import, réglages, conversion. **Coût honnête** : la recette doit être COMPARÉE au gabarit courant avant bascule — un réglage oublié serait hérité par les quatorze VM, et découvert loin de sa cause. **En attendant**, un gabarit se transporte d'un cluster à l'autre par `vzdump` / `qmrestore` | `docs/procedure-template-debian13-proxmox.md`, `scripts/verifier_signature.py` | — *(à construire)* |
|
| **D-76** | Le **gabarit doit se FABRIQUER par le dépôt**, pas se façonner à la main — décidée le 2026-08-12, **volontairement différée** après Technolibre | tout dérive d'un plan et se prouve ; le gabarit est la **seule pièce faite à la main** — 853 lignes de procédure manuelle — et il est en amont des quatorze VM. Le 2026-08-09 l'a démontré : l'ancien portait une **clé privée d'hôte SSH** et un `/etc/resolv.conf` figé, recopiés dans chaque clone, et il a fallu le recapturer. La preuve de reconstruction s'arrête donc un cran trop tôt : on reconstruit la flotte, pas ce dont elle est clonée. **Cible** : image cloud Debian officielle → signature vérifiée contre une empreinte épinglée (`verifier_signature.py`, déjà écrit) → import, réglages, conversion. **Coût honnête** : la recette doit être COMPARÉE au gabarit courant avant bascule — un réglage oublié serait hérité par les quatorze VM, et découvert loin de sa cause. **En attendant**, un gabarit se transporte d'un cluster à l'autre par `vzdump` / `qmrestore` | `docs/procedure-template-debian13-proxmox.md`, `scripts/verifier_signature.py` | — *(à construire)* |
|
||||||
|
|
||||||
| **D-77** | **L'underlay d'un site dérive du même `index` que son tenant**, dans la **bande basse** `10.(10+index).0–15.x` ; les réseaux de **stockage** en sortent et sont **identiques partout**, en `192.168.<vlan>.0/24` | tant qu'il n'existait qu'un site, `10.0.x.x` suffisait. Deux sites qui doivent se joindre — reprise mutuelle, sauvegardes croisées, exploitation à distance — **ne peuvent pas** porter les mêmes plages : chaque routeur croit que le réseau est chez lui. Un « numéro de site » a d'abord été proposé : **rejeté**, c'était un SECOND SEED à tenir et à synchroniser, alors que tout dérive déjà d'`index` (D-17). La bande basse est sûre **par la règle, pas par chance** : les zones valent `10.(10+index).(15+categorie).0/24`, donc troisième octet ≥ 16 — les octets 0 à 15 ne sont jamais alloués. Les troisièmes et derniers octets de l'underlay actuel sont ainsi **préservés** : seul le deuxième change, et l'invariant `.1` (D-04) survit intact. Le **stockage** en est sorti parce qu'il est jumbo, non routé, et ne quitte jamais son site : il n'a aucun besoin d'être unique, et l'aligner sur le VLAN (`192.168.20.x` ↔ VLAN 20) fait dire son VLAN à l'adresse. Contrepartie assumée : ces réseaux ne pourront jamais traverser un lien inter-sites — sans conséquence, puisque ce qui voyage entre deux sites est l'**état**, par le dépôt de sauvegarde, pas le stockage bloc | `underlay.yml` (`index`), `scripts/underlay.py`, `docs/preparer-un-site-hebergeur.md` | **P23** |
|
| **D-77** | **L'underlay d'un site dérive du même `index` que son tenant**, dans la **bande basse** `10.<index>.0–15.x` ; les réseaux de **stockage** en sortent et sont **identiques partout**, en `192.168.<vlan>.0/24` | tant qu'il n'existait qu'un site, `10.0.x.x` suffisait. Deux sites qui doivent se joindre — reprise mutuelle, sauvegardes croisées, exploitation à distance — **ne peuvent pas** porter les mêmes plages : chaque routeur croit que le réseau est chez lui. Un « numéro de site » a d'abord été proposé : **rejeté**, c'était un SECOND SEED à tenir et à synchroniser, alors que tout dérive déjà d'`index` (D-17). La bande basse est sûre **par la règle, pas par chance** : les zones valent `10.<index>.(15+categorie).0/24`, donc troisième octet ≥ 16 — les octets 0 à 15 ne sont jamais alloués. Les troisièmes et derniers octets de l'underlay actuel sont ainsi **préservés** : seul le deuxième change, et l'invariant `.1` (D-04) survit intact. Le **stockage** en est sorti parce qu'il est jumbo, non routé, et ne quitte jamais son site : il n'a aucun besoin d'être unique, et l'aligner sur le VLAN (`192.168.20.x` ↔ VLAN 20) fait dire son VLAN à l'adresse. Contrepartie assumée : ces réseaux ne pourront jamais traverser un lien inter-sites — sans conséquence, puisque ce qui voyage entre deux sites est l'**état**, par le dépôt de sauvegarde, pas le stockage bloc | `underlay.yml` (`index`), `scripts/underlay.py`, `docs/preparer-un-site-hebergeur.md` | **P23** |
|
||||||
|
|
||||||
> **Ce que D-77 rend possible, et ce qu'elle coûte.** Elle est la condition de la reprise
|
> **Ce que D-77 rend possible, et ce qu'elle coûte.** Elle est la condition de la reprise
|
||||||
> mutuelle : sans plages distinctes, aucun lien entre deux sites ne peut router. Elle est
|
> mutuelle : sans plages distinctes, aucun lien entre deux sites ne peut router. Elle est
|
||||||
|
|
|
||||||
|
|
@ -152,9 +152,9 @@ Ce que `index` dérive (modèle à 6 zones) :
|
||||||
|
|
||||||
| Élément | Formule | Exemple (index 13) |
|
| Élément | Formule | Exemple (index 13) |
|
||||||
| --- | --- | --- |
|
| --- | --- | --- |
|
||||||
| Supernet | `10.(10+index).0.0/16` | `10.23.0.0/16` |
|
| Supernet | `10.<index>.0.0/16` | `10.13.0.0/16` |
|
||||||
| Sous-réseau de zone | `10.(10+index).(15+zone).0/24` | `10.23.16.0/24` (Frontière) |
|
| Sous-réseau de zone | `10.<index>.(15+zone).0/24` | `10.13.16.0/24` (Frontière) |
|
||||||
| Passerelle | `…(15+zone).1` | `10.23.16.1` |
|
| Passerelle | `…(15+zone).1` | `10.13.16.1` |
|
||||||
| VLAN sur le trunk | `1000 + index×10 + zone` | `1131`-`1136` |
|
| VLAN sur le trunk | `1000 + index×10 + zone` | `1131`-`1136` |
|
||||||
| VMID (ip-miroir) | `VLAN · octet-hôte · séq` (9 chiffres) | `113102101` |
|
| VMID (ip-miroir) | `VLAN · octet-hôte · séq` (9 chiffres) | `113102101` |
|
||||||
|
|
||||||
|
|
@ -166,8 +166,9 @@ mêmes VLAN/VMID : c'est la collision que `make instances` et **P21** attrapent.
|
||||||
`federe: false` : il est alors **exclu du réseau convergé** (devis, `make instances` le
|
`federe: false` : il est alors **exclu du réseau convergé** (devis, `make instances` le
|
||||||
montre « local »). Il garde son adressage dérivé et reste déployable sur *son* infra.
|
montre « local »). Il garde son adressage dérivé et reste déployable sur *son* infra.
|
||||||
|
|
||||||
**Plafond théorique : 245 écosystèmes fédérés** (index 1 à 245), borné par l'IPv4
|
**Plafond théorique : 255 écosystèmes fédérés** (index 1 à 255), borné par l'IPv4
|
||||||
`10.(10+index)` (2ᵉ octet 11→255). Le VLAN (≤ 4094) autorise jusqu'à 308, le VMID bien
|
`10.<index>` (2ᵉ octet 1→255). Le décalage de +10, retiré le 2026-08-12, en confisquait
|
||||||
|
dix — et surtout, il empêchait de lire l'index directement dans l'adresse. Le VLAN (≤ 4094) autorise jusqu'à 308, le VMID bien
|
||||||
plus — c'est donc l'adressage IP qui plafonne. Au-delà d'une poignée d'instances
|
plus — c'est donc l'adressage IP qui plafonne. Au-delà d'une poignée d'instances
|
||||||
co-localisées, confier l'allocation à un **IPAM** (NetBox) plutôt qu'au moteur — cf.
|
co-localisées, confier l'allocation à un **IPAM** (NetBox) plutôt qu'au moteur — cf.
|
||||||
[`positionnement.md`](positionnement.md).
|
[`positionnement.md`](positionnement.md).
|
||||||
|
|
|
||||||
|
|
@ -31,14 +31,14 @@ basse** du supernet — celle que la dérivation des tenants n'alloue jamais.
|
||||||
|
|
||||||
| Rôle | VLAN | Sous-réseau | MTU | Qui y vit |
|
| Rôle | VLAN | Sous-réseau | MTU | Qui y vit |
|
||||||
|---|---|---|---|---|
|
|---|---|---|---|---|
|
||||||
| Gestion | 10 | `10.(10+index).0.0/24` | 1500 | frontière `.1`, commutateurs, OOB/IPMI, admin hyperviseur |
|
| Gestion | 10 | `10.<index>.0.0/24` | 1500 | frontière `.1`, commutateurs, OOB/IPMI, admin hyperviseur |
|
||||||
| Sortie des tenants | 40 | `10.(10+index).4.0/24` | 1500 | frontière `.1`, nœuds de sortie |
|
| Sortie des tenants | 40 | `10.<index>.4.0/24` | 1500 | frontière `.1`, nœuds de sortie |
|
||||||
| Transport VXLAN | 11 | `10.(10+index).5.0/24` | 1500 | hyperviseurs seulement |
|
| Transport VXLAN | 11 | `10.<index>.5.0/24` | 1500 | hyperviseurs seulement |
|
||||||
| Stockage iSCSI | 20 | `192.168.20.0/24` | 9000 | baie ↔ hyperviseurs |
|
| Stockage iSCSI | 20 | `192.168.20.0/24` | 9000 | baie ↔ hyperviseurs |
|
||||||
| Ceph public | 30 | `192.168.30.0/24` | 9000 | clients ↔ MON/OSD |
|
| Ceph public | 30 | `192.168.30.0/24` | 9000 | clients ↔ MON/OSD |
|
||||||
| Ceph cluster | 31 | `192.168.31.0/24` | 9000 | OSD ↔ OSD |
|
| Ceph cluster | 31 | `192.168.31.0/24` | 9000 | OSD ↔ OSD |
|
||||||
|
|
||||||
Index 17 → gestion en `10.27.0.0/24` ; index 11 → `10.21.0.0/24`. Deux sites ne peuvent
|
Index 17 → gestion en `10.17.0.0/24` ; index 11 → `10.11.0.0/24`. Deux sites ne peuvent
|
||||||
donc **pas** se chevaucher, sans qu'on ait rien de plus à décider.
|
donc **pas** se chevaucher, sans qu'on ait rien de plus à décider.
|
||||||
|
|
||||||
**Les VLAN ne changent jamais** d'un site à l'autre : ils sont locaux, ils ne traversent
|
**Les VLAN ne changent jamais** d'un site à l'autre : ils sont locaux, ils ne traversent
|
||||||
|
|
@ -46,7 +46,7 @@ aucun lien inter-sites. Un seul modèle mental, et l'adresse de stockage porte s
|
||||||
numéro de VLAN — `192.168.20.x` est sur le VLAN 20.
|
numéro de VLAN — `192.168.20.x` est sur le VLAN 20.
|
||||||
|
|
||||||
> **Pourquoi la bande basse est sûre, et non pas seulement libre aujourd'hui.** Les zones
|
> **Pourquoi la bande basse est sûre, et non pas seulement libre aujourd'hui.** Les zones
|
||||||
> d'un tenant sont dérivées en `10.(10+index).(15+categorie).0/24` : leur troisième octet
|
> d'un tenant sont dérivées en `10.<index>.(15+categorie).0/24` : leur troisième octet
|
||||||
> vaut donc **16 au minimum**, et croît avec le nombre de zones. Les octets `0` à `15`
|
> vaut donc **16 au minimum**, et croît avec le nombre de zones. Les octets `0` à `15`
|
||||||
> ne sont **jamais** alloués — c'est une propriété de la règle, pas une place restée
|
> ne sont **jamais** alloués — c'est une propriété de la règle, pas une place restée
|
||||||
> vide. L'underlay y tient largement.
|
> vide. L'underlay y tient largement.
|
||||||
|
|
@ -76,8 +76,8 @@ C'est le seul équipement qui route, et l'unique point de passage entre l'extér
|
||||||
l'intérieur. Set-OPS **pilote ses règles par API** : le boîtier reste à l'hébergeur, rien
|
l'intérieur. Set-OPS **pilote ses règles par API** : le boîtier reste à l'hébergeur, rien
|
||||||
n'y est installé.
|
n'y est installé.
|
||||||
|
|
||||||
**Interfaces :** le WAN (noter l'IP publique) ; la gestion en `10.(10+index).0.1/24` ; le
|
**Interfaces :** le WAN (noter l'IP publique) ; la gestion en `10.<index>.0.1/24` ; le
|
||||||
transit en `10.(10+index).4.1/24`, par où sortent les machines du tenant.
|
transit en `10.<index>.4.1/24`, par où sortent les machines du tenant.
|
||||||
|
|
||||||
> **Un point de routage porte le même dernier octet partout** : `.1`, quel que soit
|
> **Un point de routage porte le même dernier octet partout** : `.1`, quel que soit
|
||||||
> l'équipement qui l'assure. Invariant porté par la preuve `P23`.
|
> l'équipement qui l'assure. Invariant porté par la preuve `P23`.
|
||||||
|
|
|
||||||
|
|
@ -34,8 +34,8 @@ Vérifiée sur les deux tenants fédérés, elle ne demande **aucun changement d
|
||||||
| **zone** (un VRF) | le tenant | `CHEZ17` |
|
| **zone** (un VRF) | le tenant | `CHEZ17` |
|
||||||
| **VNet** | la zone de sécurité | `chez174` |
|
| **VNet** | la zone de sécurité | `chez174` |
|
||||||
| **tag** (VNI) | `vlan_de(index, zone)` | `1174` |
|
| **tag** (VNI) | `vlan_de(index, zone)` | `1174` |
|
||||||
| **subnet** | `sous_reseau_de(index, zone)` | `10.27.19.0/24` |
|
| **subnet** | `sous_reseau_de(index, zone)` | `10.17.19.0/24` |
|
||||||
| **gateway** | `passerelle_de(index, zone)` | `10.27.19.1` |
|
| **gateway** | `passerelle_de(index, zone)` | `10.17.19.1` |
|
||||||
|
|
||||||
> **Rectification du 2026-08-03.** Ce tableau annonçait `chez17-services-infra`, qui
|
> **Rectification du 2026-08-03.** Ce tableau annonçait `chez17-services-infra`, qui
|
||||||
> aurait été **refusé à l'application** : zones et VNets sont limités à **8 caractères**
|
> aurait été **refusé à l'application** : zones et VNets sont limités à **8 caractères**
|
||||||
|
|
|
||||||
|
|
@ -1,55 +0,0 @@
|
||||||
---
|
|
||||||
serveur_powerdns_packages:
|
|
||||||
- pdns-server
|
|
||||||
- pdns-backend-bind
|
|
||||||
- bind9-utils
|
|
||||||
- dnsutils
|
|
||||||
|
|
||||||
serveur_powerdns_service_name: "pdns"
|
|
||||||
serveur_powerdns_zone_directory: "/etc/powerdns/zones"
|
|
||||||
serveur_powerdns_bind_config: "/etc/powerdns/bindbackend.conf"
|
|
||||||
serveur_powerdns_zone: "{{ domaine_interne }}"
|
|
||||||
serveur_powerdns_nameserver: "ns1"
|
|
||||||
serveur_powerdns_contact: "hostmaster.{{ domaine_interne }}"
|
|
||||||
serveur_powerdns_ttl: 3600
|
|
||||||
serveur_powerdns_serial: 2026062201
|
|
||||||
serveur_powerdns_soa_refresh: 3600
|
|
||||||
serveur_powerdns_soa_retry: 900
|
|
||||||
serveur_powerdns_soa_expire: 1209600
|
|
||||||
serveur_powerdns_soa_minimum: 3600
|
|
||||||
# L'adresse du tenant SEULEMENT, pas `0.0.0.0` : lier toutes les interfaces occupe aussi
|
|
||||||
# `127.0.0.1:53`, ou un resolveur recursif local voudrait s'installer. Ce n'est pas un
|
|
||||||
# probleme theorique — c'est la raison pour laquelle `client_unbound` exempte cet hote.
|
|
||||||
# PowerDNS reste autoritatif pur : il repond pour la zone souveraine et REFUSE le reste.
|
|
||||||
serveur_powerdns_listen_addresses:
|
|
||||||
- "{{ ansible_host | default('0.0.0.0') }}"
|
|
||||||
serveur_powerdns_allow_axfr_ips: []
|
|
||||||
|
|
||||||
# Enregistrements additionnels geres explicitement.
|
|
||||||
serveur_powerdns_records:
|
|
||||||
- name: "dns"
|
|
||||||
type: "CNAME"
|
|
||||||
value: "ns1.{{ serveur_powerdns_zone }}."
|
|
||||||
|
|
||||||
# Groupes dont les hotes actifs avec ansible_host seront ajoutes a la zone.
|
|
||||||
serveur_powerdns_inventory_groups:
|
|
||||||
- hotes_actifs
|
|
||||||
|
|
||||||
# Publier des A pour les FQDN d'exposition (champ 'expose' des applications) vers l'edge
|
|
||||||
# qui les sert (domaines.edge). Ferme la boucle : declarer 'expose' -> vhost + cert + DNS.
|
|
||||||
serveur_powerdns_publier_expositions: true
|
|
||||||
serveur_powerdns_expositions: []
|
|
||||||
|
|
||||||
# Zone INVERSE — DERIVEE du supernet, jamais ecrite. Un /16 `10.(10+index).0.0` donne
|
|
||||||
# `(10+index).10.in-addr.arpa`. Vide si le supernet n'est pas connu ou n'est pas un /16 :
|
|
||||||
# mieux vaut pas de zone inverse qu'une zone fausse.
|
|
||||||
#
|
|
||||||
# Pourquoi elle manquait. Rien dans le moteur ne touchait `in-addr.arpa` — mesure du
|
|
||||||
# 2026-08-08. Un hote pouvait donc etre resolu par son nom et rester anonyme a l'envers,
|
|
||||||
# ce que la plupart des services de courriel et de journalisation reprochent en silence.
|
|
||||||
serveur_powerdns_zone_inverse: >-
|
|
||||||
{{ (setops_supernet | default('') | ansible.utils.ipaddr('prefix') | int == 16)
|
|
||||||
| ternary(
|
|
||||||
(setops_supernet | default('0.0.0.0/0')).split('.')[1] ~ '.'
|
|
||||||
~ (setops_supernet | default('0.0.0.0/0')).split('.')[0] ~ '.in-addr.arpa',
|
|
||||||
'') }}
|
|
||||||
|
|
@ -156,7 +156,7 @@ CHEMINS_UNDERLAY = {
|
||||||
# (son domaine, son realm, son modele) et des valeurs de l'HEBERGEUR (son cluster, sa
|
# (son domaine, son realm, son modele) et des valeurs de l'HEBERGEUR (son cluster, sa
|
||||||
# frontiere, sa fabric). Ce sont deux proprietaires, deux depots, deux cycles de vie.
|
# frontiere, sa fabric). Ce sont deux proprietaires, deux depots, deux cycles de vie.
|
||||||
INTRANTS_SCHEMA = [
|
INTRANTS_SCHEMA = [
|
||||||
("index", "reseau", "constante", "Réseau", "Index d'instance dans la fédération (seed : dérive supernet 10.(10+index), VLAN 1000+index×10+zone, VMID)", "int", "tenant"),
|
("index", "reseau", "constante", "Réseau", "Index d'instance dans la fédération (seed : dérive supernet 10.<index>, VLAN 1000+index×10+zone, VMID)", "int", "tenant"),
|
||||||
("domaine_interne", "identite", "constante", "Identité", "Domaine DNS interne", "str", "tenant"),
|
("domaine_interne", "identite", "constante", "Identité", "Domaine DNS interne", "str", "tenant"),
|
||||||
("fuseau_horaire", "identite", "defaut", "Identité", "Fuseau horaire", "str", "tenant"),
|
("fuseau_horaire", "identite", "defaut", "Identité", "Fuseau horaire", "str", "tenant"),
|
||||||
("organisation", "identite", "defaut", "Identité", "Organisation (annuaire LDAP, certificats)", "str", "tenant"),
|
("organisation", "identite", "defaut", "Identité", "Organisation (annuaire LDAP, certificats)", "str", "tenant"),
|
||||||
|
|
|
||||||
|
|
@ -454,28 +454,39 @@ def fonction_seq(nom: str) -> tuple[str, int | None]:
|
||||||
# le devis reseau (scripts/devis_reseau.py).
|
# le devis reseau (scripts/devis_reseau.py).
|
||||||
#
|
#
|
||||||
# Conventions du modele a 6 zones (reference integral) :
|
# Conventions du modele a 6 zones (reference integral) :
|
||||||
# - 2e octet du supernet = OCTET_TENANT + index (index 1 -> 10.11.0.0/16)
|
# - 2e octet du supernet = index TEL QUEL (index 1 -> 10.1.0.0/16)
|
||||||
# - 3e octet de la zone = OCTET_ZONE + categorie (zone 1 -> .16, dans .16.0/20)
|
# - 3e octet de la zone = OCTET_ZONE + categorie (zone 1 -> .16, dans .16.0/20)
|
||||||
# - VLAN sur le trunk convergE = SOCLE_VLAN + index x 10 + zone (4 chiffres, unique)
|
# - VLAN sur le trunk convergE = SOCLE_VLAN + index x 10 + zone (4 chiffres, unique)
|
||||||
# - VMID ip-miroir = VLAN(4) . octet-hote(3) . sequence(2) = 9 chiffres mnemotechniques
|
# - VMID ip-miroir = VLAN(4) . octet-hote(3) . sequence(2) = 9 chiffres mnemotechniques
|
||||||
OCTET_TENANT = 10
|
#
|
||||||
|
# LE DECALAGE DE +10 A ETE RETIRE le 2026-08-12. Il produisait `10.(10+index)`, et
|
||||||
|
# personne ne savait plus pourquoi : ni le commentaire de la constante, ni le wiki, ni
|
||||||
|
# le commit fondateur (36a882b) ne le justifiaient. Ses deux effets constates :
|
||||||
|
# - il reservait 10.0-10.9 sous la plage tenant — utile tant que l'underlay vivait
|
||||||
|
# LA ; D-77 l'a fait entrer dans la bande basse de son propre /16, ce qui a vide
|
||||||
|
# cette reserve de son role ;
|
||||||
|
# - il eloignait le premier tenant de 10.0.0.0/16, la plage la plus repandue en
|
||||||
|
# reseau domestique. Ce risque revient donc aux INDEX BAS, et c'est assume :
|
||||||
|
# choisir un index, c'est choisir sa plage — autant que ce soit lisible.
|
||||||
|
# En echange, l'index se lit DIRECTEMENT dans l'adresse (index 17 -> 10.17.x.x) et la
|
||||||
|
# plage utile passe de 0-245 a 0-255.
|
||||||
OCTET_ZONE = 15
|
OCTET_ZONE = 15
|
||||||
SOCLE_VLAN = 1000
|
SOCLE_VLAN = 1000
|
||||||
INDEX_BAC_A_SABLE = 9 # index par defaut d'une nomenclature sans seed (jetable)
|
INDEX_BAC_A_SABLE = 9 # index par defaut d'une nomenclature sans seed (jetable)
|
||||||
|
|
||||||
|
|
||||||
def supernet_de(index: int) -> str:
|
def supernet_de(index: int) -> str:
|
||||||
"""/16 du tenant : 10.(10+index).0.0/16."""
|
"""/16 du tenant : 10.<index>.0.0/16 — l'index se lit dans l'adresse."""
|
||||||
return f"10.{OCTET_TENANT + int(index)}.0.0/16"
|
return f"10.{int(index)}.0.0/16"
|
||||||
|
|
||||||
|
|
||||||
def base3_de(index: int, categorie: int) -> str:
|
def base3_de(index: int, categorie: int) -> str:
|
||||||
"""Trois premiers octets d'une zone : 10.(10+index).(15+categorie)."""
|
"""Trois premiers octets d'une zone : 10.<index>.(15+categorie)."""
|
||||||
return f"10.{OCTET_TENANT + int(index)}.{OCTET_ZONE + int(categorie)}"
|
return f"10.{int(index)}.{OCTET_ZONE + int(categorie)}"
|
||||||
|
|
||||||
|
|
||||||
def sous_reseau_de(index: int, categorie: int, cidr: int = 24) -> str:
|
def sous_reseau_de(index: int, categorie: int, cidr: int = 24) -> str:
|
||||||
"""/24 d'une zone : 10.(10+index).(15+categorie).0/24."""
|
"""/24 d'une zone : 10.<index>.(15+categorie).0/24."""
|
||||||
return f"{base3_de(index, categorie)}.0/{int(cidr)}"
|
return f"{base3_de(index, categorie)}.0/{int(cidr)}"
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ sys.path.insert(0, str(RACINE / "scripts"))
|
||||||
import underlay as u # noqa: E402
|
import underlay as u # noqa: E402
|
||||||
from inventory_rules import OCTET_ZONE # noqa: E402
|
from inventory_rules import OCTET_ZONE # noqa: E402
|
||||||
|
|
||||||
SUPERNETS = ["10.21.0.0/16", "10.27.0.0/16"] # deux sites : index 11 et 17
|
SUPERNETS = ["10.11.0.0/16", "10.17.0.0/16"] # deux sites : index 11 et 17
|
||||||
MIEN = 11
|
MIEN = 11
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -39,25 +39,25 @@ def test_la_borne_derive_de_la_regle_des_zones():
|
||||||
|
|
||||||
|
|
||||||
def test_bande_basse_de_son_propre_supernet_acceptee():
|
def test_bande_basse_de_son_propre_supernet_acceptee():
|
||||||
for sous in ("10.21.0.0/24", "10.21.4.0/24", "10.21.5.0/24", "10.21.15.0/24"):
|
for sous in ("10.11.0.0/24", "10.11.4.0/24", "10.11.5.0/24", "10.11.15.0/24"):
|
||||||
assert _erreurs(sous) == [], f"{sous} devrait etre conforme (bande basse)"
|
assert _erreurs(sous) == [], f"{sous} devrait etre conforme (bande basse)"
|
||||||
|
|
||||||
|
|
||||||
def test_bande_des_zones_refusee():
|
def test_bande_des_zones_refusee():
|
||||||
for sous in (f"10.21.{OCTET_ZONE + 1}.0/24", "10.21.18.0/24", "10.21.16.0/20"):
|
for sous in (f"10.11.{OCTET_ZONE + 1}.0/24", "10.11.18.0/24", "10.11.16.0/20"):
|
||||||
assert _erreurs(sous), f"{sous} devrait etre REFUSE (bande des zones)"
|
assert _erreurs(sous), f"{sous} devrait etre REFUSE (bande des zones)"
|
||||||
|
|
||||||
|
|
||||||
def test_un_prefixe_qui_franchit_la_frontiere_est_refuse():
|
def test_un_prefixe_qui_franchit_la_frontiere_est_refuse():
|
||||||
"""Le piege : il COMMENCE dans la bande basse et deborde. Un test qui ne
|
"""Le piege : il COMMENCE dans la bande basse et deborde. Un test qui ne
|
||||||
regarderait que le premier octet le laisserait passer."""
|
regarderait que le premier octet le laisserait passer."""
|
||||||
for sous in ("10.21.0.0/19", "10.21.0.0/16"):
|
for sous in ("10.11.0.0/19", "10.11.0.0/16"):
|
||||||
assert _erreurs(sous), f"{sous} couvre au-dela de {OCTET_ZONE} : a refuser"
|
assert _erreurs(sous), f"{sous} couvre au-dela de {OCTET_ZONE} : a refuser"
|
||||||
|
|
||||||
|
|
||||||
def test_supernet_d_un_autre_site_refuse():
|
def test_supernet_d_un_autre_site_refuse():
|
||||||
"""C'est ce qui empeche deux sites d'etre relies — l'erreur la plus couteuse."""
|
"""C'est ce qui empeche deux sites d'etre relies — l'erreur la plus couteuse."""
|
||||||
assert _erreurs("10.27.0.0/24"), "le supernet d'un autre site doit etre refuse"
|
assert _erreurs("10.17.0.0/24"), "le supernet d'un autre site doit etre refuse"
|
||||||
|
|
||||||
|
|
||||||
def test_hors_de_tout_supernet_accepte():
|
def test_hors_de_tout_supernet_accepte():
|
||||||
|
|
@ -69,7 +69,7 @@ def test_hors_de_tout_supernet_accepte():
|
||||||
def test_sans_index_on_retombe_sur_la_regle_stricte():
|
def test_sans_index_on_retombe_sur_la_regle_stricte():
|
||||||
"""Un underlay qui n'a pas encore migre ne declare pas d'index : aucun chevauchement
|
"""Un underlay qui n'a pas encore migre ne declare pas d'index : aucun chevauchement
|
||||||
n'est alors tolere, ce qui reste le comportement sur."""
|
n'est alors tolere, ce qui reste le comportement sur."""
|
||||||
assert _erreurs("10.21.0.0/24", index=None), \
|
assert _erreurs("10.11.0.0/24", index=None), \
|
||||||
"sans index, tout chevauchement doit etre refuse"
|
"sans index, tout chevauchement doit etre refuse"
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,9 +8,9 @@ flotte, ils n'appartiennent a aucun tenant.
|
||||||
Convention : VLAN < 1000, franchement SOUS la plage tenant (VLAN = 1000+index*10+zone).
|
Convention : VLAN < 1000, franchement SOUS la plage tenant (VLAN = 1000+index*10+zone).
|
||||||
|
|
||||||
ADRESSAGE (D-77, 2026-08-12). Un site derive du meme `index` que son tenant, et son
|
ADRESSAGE (D-77, 2026-08-12). Un site derive du meme `index` que son tenant, et son
|
||||||
underlay occupe la BANDE BASSE de ce supernet : `10.(10+index).0-15.x`. La bande est
|
underlay occupe la BANDE BASSE de ce supernet : `10.<index>.0-15.x`. La bande est
|
||||||
sure PAR LA REGLE et non par chance — les zones d'un tenant valent
|
sure PAR LA REGLE et non par chance — les zones d'un tenant valent
|
||||||
`10.(10+index).(15+categorie).0/24`, donc troisieme octet >= 16 ; les octets 0 a 15
|
`10.<index>.(15+categorie).0/24`, donc troisieme octet >= 16 ; les octets 0 a 15
|
||||||
ne sont jamais alloues. Deux sites ne peuvent alors pas se chevaucher, sans second
|
ne sont jamais alloues. Deux sites ne peuvent alors pas se chevaucher, sans second
|
||||||
registre a tenir.
|
registre a tenir.
|
||||||
|
|
||||||
|
|
@ -57,7 +57,7 @@ from inventory_rules import supernet_de, vlan_de # noqa: E402
|
||||||
SEUIL_VLAN_TENANT = 1000
|
SEUIL_VLAN_TENANT = 1000
|
||||||
|
|
||||||
# Premier troisieme-octet alloue aux ZONES d'un tenant. DERIVE de la regle
|
# Premier troisieme-octet alloue aux ZONES d'un tenant. DERIVE de la regle
|
||||||
# (`base3_de` = 10.(10+index).(15+categorie)) et jamais ecrit en dur : deplacer
|
# (`base3_de` = 10.<index>.(15+categorie)) et jamais ecrit en dur : deplacer
|
||||||
# OCTET_ZONE deplacerait la frontiere de la bande basse avec lui.
|
# OCTET_ZONE deplacerait la frontiere de la bande basse avec lui.
|
||||||
from inventory_rules import OCTET_ZONE # noqa: E402
|
from inventory_rules import OCTET_ZONE # noqa: E402
|
||||||
PREMIER_OCTET_ZONE = OCTET_ZONE + 1
|
PREMIER_OCTET_ZONE = OCTET_ZONE + 1
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@ serveurs. Refusé par la preuve **P06** et par la création de modèle.
|
||||||
1ʳᵉ fois). Cf. [Infra as Code & idempotence](Infra-as-Code-et-idempotence).
|
1ʳᵉ fois). Cf. [Infra as Code & idempotence](Infra-as-Code-et-idempotence).
|
||||||
|
|
||||||
**Index (seed)** — Le **seul** intrant d'adressage d'une instance. Détermine supernet
|
**Index (seed)** — Le **seul** intrant d'adressage d'une instance. Détermine supernet
|
||||||
(`10.(10+index)`), VLAN (`1000+index×10+zone`), VMID. Unique par instance fédérée.
|
(`10.<index>`), VLAN (`1000+index×10+zone`), VMID. Unique par instance fédérée.
|
||||||
|
|
||||||
**Instance** — Un écosystème réel (un *tenant*) : `../OPS-<nom>`, avec ses valeurs concrètes
|
**Instance** — Un écosystème réel (un *tenant*) : `../OPS-<nom>`, avec ses valeurs concrètes
|
||||||
(domaine, *voûte*, index). L'active est celle que pointe le symlink `instance/`.
|
(domaine, *voûte*, index). L'active est celle que pointe le symlink `instance/`.
|
||||||
|
|
|
||||||
|
|
@ -37,8 +37,8 @@ Le **plan** (`instance/plan/`) est la source unique. Cinq registres :
|
||||||
|
|
||||||
| Élément | Formule (modèle 6 zones) |
|
| Élément | Formule (modèle 6 zones) |
|
||||||
|---|---|
|
|---|---|
|
||||||
| Supernet | `10.(10+index).0.0/16` |
|
| Supernet | `10.<index>.0.0/16` |
|
||||||
| Sous-réseau de zone | `10.(10+index).(15+zone).0/24` |
|
| Sous-réseau de zone | `10.<index>.(15+zone).0/24` |
|
||||||
| Passerelle | `…(15+zone).1` |
|
| Passerelle | `…(15+zone).1` |
|
||||||
| VLAN sur le trunk | `1000 + index×10 + zone` |
|
| VLAN sur le trunk | `1000 + index×10 + zone` |
|
||||||
| VMID | `VLAN·octet-hôte·séquence` (9 chiffres) |
|
| VMID | `VLAN·octet-hôte·séquence` (9 chiffres) |
|
||||||
|
|
|
||||||
|
|
@ -120,7 +120,7 @@ En mode `sdn`, ces réseaux transportent du VXLAN : leur **MTU doit atteindre 15
|
||||||
sinon le ping passe et les transferts échouent. `make underlay` le refuse.
|
sinon le ping passe et les transferts échouent. `make underlay` le refuse.
|
||||||
|
|
||||||
`make underlay` l'affiche et le **valide** : VLAN < 1000 et sous-réseaux hors des supernets
|
`make underlay` l'affiche et le **valide** : VLAN < 1000 et sous-réseaux hors des supernets
|
||||||
tenant (`10.(10+index).0.0/16`) — **aucune collision possible** avec les overlays. `make
|
tenant (`10.<index>.0.0/16`) — **aucune collision possible** avec les overlays. `make
|
||||||
devis-reseau` en émet la config (section 0) et l'ajoute au trunk. La **preuve P23** garde la
|
devis-reseau` en émet la config (section 0) et l'ajoute au trunk. La **preuve P23** garde la
|
||||||
règle ; elle est *sautée* si aucun `underlay.yml` n'est défini.
|
règle ; elle est *sautée* si aucun `underlay.yml` n'est défini.
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue