Set-OPS-Public/docs/implanter-un-tenant-sur-un-site.md
Daniel Allaire 5bc3bceac1
Some checks failed
verifier / verifier (push) Has been cancelled
documentation : la tournee des 74 documents, parce qu un balayage ne lit pas
La revision a commence par un balayage par motifs — chemins morts, cibles make
absentes, comptes derives. Il a trouve une trentaine d ecarts et rate presque
tout le reste : un motif ne voit que ce qui s exprime en motif.

make hote-planifier en est l exemple. La cible EXISTE, donc le controle passait
au vert. C est une cible depreciee qui refuse et sort en 2, recommandee par
AGENTS.md, et qui contredit la REGLE D OR du meme fichier trois ecrans plus
haut. Il fallait lire pour la voir.

74 documents lus un par un. 66 corriges, 8 exacts.

CE QUI ETAIT FRANCHEMENT FAUX

AGENTS.md, la source d autorite, annoncait la flotte pas encore executee contre
des VM reelles. Elle a ete rasee et remontee depuis zero trois fois.
ecosysteme-chezlepro.md, le document montre a un client, portait la meme
phrase : il se sous-vendait gravement.

courriel-conception.md s ouvrait sur aucun role n est encore ecrit, au-dessus de
son propre paragraphe 1 qui les nomme. autorisation.md se terminait sur rien n
est construit alors qu il rapporte des mesures datees du role en fonctionnement.
hebergeur-exploitation.md disait rien n est fait d un depot qui existe.
filiation-emancipation.md se contredisait a deux ecrans de distance.

DES MODELES DECRITS D APRES UN MONDE ANTERIEUR

Le resolveur : cinq documents decrivaient un Unbound par VM en opt-in, trois le
donnaient en exemple d integration FACULTATIVE — il est universel depuis le
2026-08-24. L adressage de nomenclature-vm.md : reseau unique, VLAN 11-15, VMID
a cinq chiffres. Le nommage SDN de sdn-evpn.md contre le code : c est le wiki
qui avait raison.

CE QUI CASSE AU PREMIER ESSAI

Le nom du gabarit dore etait faux a quatre endroits, dont la procedure qui le
FABRIQUE et le critere R2 de l epreuve d operateur independant.
preparer-un-site-hebergeur.md avertissait qu une VM faite a la main serait
detruite : raser derive du plan, il ne la detruira jamais — le risque est l
inverse. Un mot de passe d essai en clair dans un depot public.

DEUX PREUVES ETENDUES, ET UNE QUI SE TROMPAIT ELLE-MEME

P57 couvre les groupes : elle a signale aussitot 29 groupes annonces au-dessus d
un tableau qui en cite 40. P29 confronte le tableau de authentification.md aux
declarations reelles : 12 annonces, 21 reels.

Et P57 imposait un chiffre faux — 56 preuves alors que le depot en porte 57, la
conditionnelle vivant hors de tout comptage. Un garde-fou qui fait respecter une
erreur ajoute l assurance a l erreur.

CE QUI RESTE, ET QU AUCUNE PREUVE NE TIENT

Deux comptes trouves a la main. Et une lacune reelle : rien ne garde les
meta/acces.yml — ni qu un service web-sso en porte un, ni que le groupe qu il
nomme existe. P29 tient les positions d authentification, personne ne tient les
habilitations.

make prouver : CONFORME, 56 OK, 0 echec, 1 saute. 0 lien mort.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Crgis8CxCWkAGFA1ecBz3q
2026-09-06 16:18:23 -04:00

272 lines
13 KiB
Markdown

# Implanter un tenant sur un site hébergeur neuf
> **Pour qui :** l'**exploitant**, sur place, le jour de l'intervention. Le tenant existe
> déjà (son plan est écrit, éprouvé) ; le site, lui, n'a jamais rien porté. Rien à
> migrer, rien à interrompre.
Trois documents voisins, à ne pas confondre :
| Situation | Document |
|---|---|
| L'hébergeur prépare son matériel, **avant** qu'on arrive | [`preparer-un-site-hebergeur.md`](preparer-un-site-hebergeur.md) |
| Un tenant **vivant** change d'hébergeur, sans coupure | [`migration-tenant.md`](migration-tenant.md) |
| **Ce document** — un tenant existant prend corps sur un site vierge | *(ici)* |
## La règle qui commande tout l'ordre
**Rien n'est fait tant que ce n'est pas mesuré sur place.** Une valeur transmise par
courriel, une liste relevée dans l'interface web, un `vmbr` cité de mémoire : chacun de
ces trois a déjà produit une panne dans ce dépôt. Chaque phase ci-dessous se termine donc
par une **commande qui interroge le système**, jamais par une conviction.
> **Le piège qui revient le plus souvent : le chèque vert sur un périmètre vide.** Une
> sauvegarde qui réussit sur zéro fichier, un devis qui lit un intrant périmé, une preuve
> qui ne peut pas échouer. À chaque « ✅ », se demander **sur quoi** il a porté.
---
## Phase 0 — au bureau, avant de partir
- [ ] **Recevoir la fiche de l'hébergeur** — les dix lignes du §7 de
[`preparer-un-site-hebergeur.md`](preparer-un-site-hebergeur.md). Sans le nom exact
du nœud et des stockages, la journée s'arrête à la phase 1.
- [ ] **Fixer l'`index` du site = l'`index` de son tenant.** Il n'y a pas de second
registre : la gestion du site est `10.<index>.0.0/24`, dérivée du même seed que les
zones du tenant. *(Technolibre → index 23 → gestion `10.23.0.0/24`.)*
- [ ] **Créer le dépôt de l'hébergeur** — un dossier frère, avec deux fichiers :
`underlay.yml` et `proxmox-hebergeur.yml` (squelettes en annexe).
- [ ] **Emporter le gabarit** `modeleSetOPS` sur disque (`vzdump`), *et* la procédure de
fabrication en repli : [`procedure-template-debian13-proxmox.md`](procedure-template-debian13-proxmox.md).
- [ ] **Préparer la voûte** de l'instance à recevoir les deux paires de secrets
(hyperviseur, frontière). Jamais dans un dépôt git, jamais dans une conversation.
- [ ] **Vérifier la version de Proxmox.** Tout ce dépôt a été éprouvé sur PVE 8. Sur PVE 9,
traiter chaque écart comme inconnu jusqu'à mesure — en particulier le SDN EVPN et le
moteur de pare-feu.
> **Un site neuf se construit d'emblée dans l'adressage cible** — gestion en
> `10.<index>.0.0/24`, chemins en `192.168.<vlan>.0/24` (D-77, D-78). Sur un site vierge, la
> cible ne coûte rien — et deux sites qui porteraient le **même** plan de gestion rendraient
> la **reprise mutuelle impossible** : deux réseaux identiques ne peuvent pas s'atteindre.
>
> *(État du site historique, mesuré le 2026-09-06 : sa gestion est **déjà** en `10.17.0.0/24`
> et son transport VXLAN en `192.168.50.0/24` ; le transit et le stockage restent dans
> l'ancien espace. Ce paragraphe le donnait entièrement « encore en `10.0.x` ».)*
---
## Phase 1 — reconnaissance du cluster (aucune écriture)
- [ ] **Relever le cluster par son API**, pas par son interface : nœuds, stockages qui
acceptent `images`, ponts présents.
- [ ] **Écrire `proxmox-hebergeur.yml` depuis ce relevé** — jamais depuis une union
devinée. C'est en recopiant des listes chez chaque tenant qu'elles ont divergé.
- [ ] **Décider le nom du contrôleur EVPN** : `EVPN00<index>` (site 23 → `EVPN0023`). Un
seul contrôleur par site sert **tous** ses tenants ; chaque tenant n'a que sa zone.
- [ ] **Sur un site à un seul nœud** : ce nœud est aussi le nœud de sortie et la sortie
primaire. Aucun pont ne peut être « partiel », et il n'y a pas de haute
disponibilité — le dire à l'hébergeur plutôt que le laisser supposer.
```bash
make underlay # affiche et valide la fabric — preuve P23
make placement-plan # nœud, stockage, pont, gabarit : existent-ils VRAIMENT ?
```
`placement-plan` est la commande qui sauve la journée : elle confronte les quatre objets
au cluster **avant** quarante minutes de déploiement. C'est elle qui a trouvé un pont
déclaré mais disparu depuis dix jours.
---
## Phase 2 — la frontière
- [ ] **Interfaces** : WAN (noter l'IP publique) ; gestion `10.<index>.0.1/24` ; transit
`192.168.40.1/24`. Un point de routage porte `.1` partout — invariant P23.
- [ ] **Compte `ansible`** avec clé publique. **Aucun `sudo`** : l'outil lit et appelle
l'API.
- [ ] **Clé d'API** (*System → Access → Users → API keys*). Le secret n'est affiché
**qu'une fois**.
- [ ] Poser la clé dans la voûte, puis :
```bash
make frontiere-plan # écart, sans rien écrire
make frontiere-appliquer CONFIRMER=true # écrit ET retire le périmé
```
---
## Phase 3 — le gabarit
- [ ] `qmrestore` de l'archive, puis **convertir en template**. Une VM ordinaire se
clonerait aussi — et produirait quatorze copies d'une machine vivante.
- [ ] **Noter son VMID sur ce cluster** et le porter dans le `group_vars/proxmox.yml` du
tenant (`proxmox_clone_vmid_modele`).
- [ ] **Ne pas le personnaliser.** Une clé d'hôte SSH, un `/etc/resolv.conf` figé ou un
compte nominatif se recopient dans **chaque** clone. C'est arrivé ; il a fallu
recapturer puis reconstruire.
> Transférer un binaire est le geste rapide, pas le geste juste : D-76 vise à
> **construire** le gabarit depuis le dépôt. À faire une fois, pas à ériger en méthode.
---
## Phase 4 — composer le moteur sur ce site
Les deux symlinks sont des axes **indépendants** (D-80) : le tenant ne sait rien de la
fabric qui le porte.
- [ ] `instance` → le dépôt du **tenant** (`make instance-utiliser NOM=<dossier>`)
- [ ] `underlay.yml` → le fichier du **site** :
`ln -sfn ../<depot-hebergeur>/underlay.yml underlay.yml`
*(`proxmox-hebergeur.yml` est trouvé par dérivation de ce symlink — rien d'autre à
déclarer.)*
- [ ] Les **quatre valeurs de placement** du tenant, dans son
`inventories/*/group_vars/proxmox.yml` : `proxmox_clone_noeud`,
`proxmox_clone_stockage`, `proxmox_clone_pont`, `proxmox_clone_vmid_modele`.
- [ ] Le **jeton d'API** de ce cluster dans la voûte de l'instance.
```bash
make instancier && make instancier-appliquer # FORCE=1 si le plan a changé exprès
make prouver && make test
make placement-plan # re-mesurer : les valeurs ont changé
```
---
## Phase 5 — matérialiser
- [ ] **Le SDN d'abord** :
```bash
make sdn-plan # écart
make sdn-appliquer CONFIRMER=true # crée ce qui manque, RETIRE ce qui est périmé
```
- [ ] **Puis la flotte, en une commande** :
```bash
make reconstruire CONFIRMER=true
```
Elle enchaîne, **dans cet ordre et pour de bonnes raisons** :
| | | Pourquoi cet ordre |
|---|---|---|
| 1 | `make flux` | Sans lui, `flux-genere/` est **vide** et le socle pose nftables en `policy drop` **sans aucune règle**. La flotte monte, SSH répond depuis l'administration, et tout le reste est mur. Trouvé le 2026-08-10 en montant un tenant depuis zéro : l'AC était debout, son port 8443 en écoute, et `step ca bootstrap` expirait depuis le même sous-réseau. |
| 2 | `flotte-creer` | clone les VM manquantes ; une VM déjà présente est sautée |
| 3 | `_amorcer-socle` | **PKI et DNS complètement debout d'abord** (D-71), hôte par hôte. Sinon chaque VM réclame un certificat à une autorité absente — et l'échec se lit comme un défaut du rôle, pas comme un défaut d'ordre. |
| 4 | `deployer-tout` | le reste, par couches |
- [ ] Si les clones expirent : `proxmox_clone_timeout` est **court sous clonage
parallèle**. Le relever, ou baisser `PARALLELE=n`.
---
## Phase 6 — la recette (rien n'est « prêt » avant)
- [ ] `make valider` — la recette sur la flotte
- [ ] Les devis, qui interrogent le **système en marche**, pas le dépôt :
```bash
make certificats-plan make identite-plan make courriel-plan
make expositions-plan make postgresql-plan make devis-reseau
make frontiere-plan make sdn-plan make placement-plan
```
- [ ] **La sauvegarde emporte-t-elle quelque chose ?** Compter les fichiers, pas les
succès. Une sauvegarde verte sur zéro fichier a tenu six semaines ici.
- [ ] **Éprouver une restauration** — [`runbooks-exploitation.md`](runbooks-exploitation.md) §5.
Une sauvegarde jamais restaurée n'est pas une sauvegarde.
- [ ] **La supervision voit-elle l'unité de sauvegarde ?** Sans
`vault_icinga_api_depot`, personne ne surveille les sauvegardes — et rien ne le dit.
- [ ] `make prouver` (toutes les preuves) et `make test`.
---
## Ce qui n'est PAS fait en repartant
À dire à l'hébergeur, explicitement, plutôt que de le laisser supposer :
- **Le resserrement du compte d'API.** `Administrator` le premier jour évite de courir
après des `403` ; le réduire est un rôle sur mesure, dix minutes — **un geste, pas une
intention**.
- **Le lien inter-sites**, si la reprise mutuelle est prévue : il doit tenir sans qu'aucun
poste soit allumé, et sa politique (`allowed-ips`) *est* l'isolation.
- **Le gabarit des deux côtés** — une reprise sans gabarit chez le survivant n'est pas une
reprise.
- **La voûte de l'instance conservée hors de son propre site.** Les sauvegardes sont
chiffrées côté client : le site d'accueil héberge du chiffré qu'il ne peut pas lire.
---
## Annexe — les deux fichiers du site
`underlay.yml` — squelette d'un site à un nœud, dans l'adressage cible :
```yaml
---
underlay:
# UN SITE N'A PAS D'INDEX (depuis le 2026-08-25). Il en portait un ; c'était un vestige.
# Un site ne dérive AUCUN adressage — ses machines vivent sur des réseaux de fabric.
# Cette valeur ne disait qu'une chose : quel supernet de tenant est le sien. Et elle le
# disait pour le site ENTIER alors qu'UN SEUL réseau est concerné.
#
# LES TENANTS QUE CE SITE PORTE — nom de dossier -> index. Les trois devis d'équipement
# (frontière, commutateur, SDN) découvrent TOUTE la fédération : sans cette clé, le
# second site se voit proposer les règles, les VLAN et les zones du premier. Le matériel
# les accepte, aucune ne correspond jamais à un paquet, et rien ne le signale.
tenants:
OPS-<tenant>: <index>
routeur: <nom-du-commutateur> # racine du spanning-tree, pas un routeur
# `stp` exige `routeur` : ne pas le déclarer tant qu'aucun commutateur ne l'est.
routage_tenants: sdn # le routage inter-zone vit sur l'hyperviseur
mtu_overlay: 1450 # 1450 + 50 de VXLAN = 1500 de transport
acl_inter_tenant: false # true seulement si le matériel sait lier une ACL à un SVI
dialecte: cisco # cisco | binardat — propriété du MATÉRIEL
stp: { mode: mstp, topologie: etoile }
reseaux:
# `bande_basse_de` DÉCLARE le chevauchement VOULU : ce /24 vit dans le /16 du tenant
# nommé, dans la bande 0-15 que ses zones (3e octet >= 16) n'allouent jamais. Sans
# cette clé, `make underlay` refuse le réseau — et il a raison : il ne peut pas
# distinguer un chevauchement voulu d'un accident. Le nom est vérifié contre `tenants:`,
# donc une faute de frappe est refusée.
- { nom: management, vlan: 10, bande_basse_de: OPS-<tenant>, sous_reseau: 10.<index>.0.0/24, passerelle: 10.<index>.0.1, mtu: 1500 }
- { nom: transit-frontiere, vlan: 40, sous_reseau: 192.168.40.0/24, passerelle_sortie: 192.168.40.1, mtu: 1500 }
- { nom: underlay-vxlan, vlan: 50, sous_reseau: 192.168.50.0/24, mtu: 1500 }
# Stockage : uniquement les réseaux réellement câblés (fabric: stockage, mtu 9000).
hotes:
- { nom: <frontiere>, reseau: management, ip: 10.<index>.0.1, role: frontiere }
- { nom: <frontiere>, reseau: transit-frontiere, ip: 192.168.40.1, role: frontiere }
- { nom: <noeud>, reseau: management, ip: 10.<index>.0.41, role: hyperviseur, via: vmbr0 }
- { nom: <noeud>, reseau: underlay-vxlan, ip: 192.168.50.41, role: hyperviseur, via: <bond> }
- { nom: <noeud>, reseau: transit-frontiere, ip: 192.168.40.41, role: hyperviseur, via: <bond> }
```
`proxmox-hebergeur.yml` — **rempli depuis la reconnaissance, jamais de mémoire** :
```yaml
---
proxmox_api_host: <noeud>
proxmox_api_port: '8006'
proxmox_api_user: ansible@pve
proxmox_validate_certs: false
proxmox_noeuds: [<noeud>]
proxmox_stockages: [<ceux qui portent `images`>]
proxmox_ponts: [<présents sur TOUS les nœuds>]
proxmox_sdn:
controleur: EVPN00<index>
asn: 65000
noeuds_de_sortie: [<noeud>]
sortie_primaire: <noeud>
```
Le MTU n'est pas un détail : **à moitié configuré, le jumbo ne fonctionne pas du tout.**
Un MTU rogné en chemin donne le pire des symptômes — les petites requêtes passent, les
grosses meurent, et rien n'est signalé. `make mtu-mesurer` tranche.
## Voir aussi
- [`preparer-un-site-hebergeur.md`](preparer-un-site-hebergeur.md) — ce que l'hébergeur prépare.
- [`migration-tenant.md`](migration-tenant.md) — déplacer un tenant **vivant**.
- [`multi-instances.md`](multi-instances.md) — un moteur, N écosystèmes.
- [`sdn-evpn.md`](sdn-evpn.md) — pourquoi une zone EVPN par tenant.
- [`decisions-architecture.md`](decisions-architecture.md) — D-71 (PKI/DNS d'abord), D-77, D-78, D-80.