Set-OPS-Public/docs/intrants-communs.md

116 lines
6.3 KiB
Markdown
Raw Normal View History

# Intrants communs de l'écosystème
preuve : P34 — chaque document declare son lecteur (D-74) La refonte de ce matin posait une convention. Une convention qu'on n'outille pas tient tant que quelqu'un y pense : c'est le raisonnement de D-70, applique au corpus documentaire. Etat de depart mesure : 2 documents sur 34 declaraient leur lecteur. Les 32 autres disaient leur SUJET — ce qui avait enfoui le runbook de reprise le plus utile du depot au §6 de autorisation.md. Les 38 le declarent desormais, lecteur determine document par document et non colle au gabarit : l'exploitant (devis, migration de tenant, cycle de vie, gabarit d'or), le mainteneur (conceptions, registres, carte), le lecteur externe (ecosysteme-chezlepro), l'agent IA (MISE-A-JOUR-CODEX-CLAUDE). Deux exemptions DERIVEES, pas listees — un chemin en dur aurait vieilli a la premiere page ajoutee : un document qui s'annonce genere, et un fragment sans titre. Les 13 exemptes verifies un par un ; aucun document ecrit a la main n'est exempte par accident. La preuve ne lit que l'EN-TETE, ce qui empeche frontiere-opnsense.md et plan-et-generation.md — qui parlent de generation dans leur corps — d'etre exemptes a tort. Eprouvee dans les deux sens. Elle a echoue seule des sa premiere execution en nommant deux documents que mon inventaire avait manques (docs/audit/). Puis test negatif delibere : declaration retiree de meta-classe.md -> ECHEC la nommant ; restauree -> OK. Ce qu'elle ne teste pas : que le lecteur declare soit le BON. Ca se juge en revue ; elle garantit qu'on a du y penser. P01–P34. Comptes perimes corriges au passage (AGENTS.md et devis-services.md annoncaient encore 30 preuves). Verifie : prouver.py 0 (34 OK), plan-recette inchange. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-10 07:53:04 -04:00
> **Pour qui :** le **mainteneur** — les valeurs partagées par tout l'écosystème, et qui les possède.
Recensement des **intrants communs** : les valeurs partagées par tout l'écosystème
(par opposition aux valeurs propres à un seul hôte). Objectif : les saisir **une
fois**, depuis un endroit unique, puis les laisser se **dériver** ou se **propager**.
> Concept lié : [`meta-classe.md`](meta-classe.md) (une définition instancie la flotte)
> et [`dimensionnement-ressources.md`](dimensionnement-ressources.md).
## 1. Recensement par domaine
### A. Identité de l'instance — `group_vars/<env>/all.yml`
- **`domaine_interne`** — domaine DNS interne (ex. `chezlepro.internal`). **Keystone** :
zones DNS, FQDN, base DN LDAP, expéditeurs courriel, URL AC en dérivent.
- `fuseau_horaire` — fuseau (ex. `America/Toronto`).
- `setops_plan_dir` — chemin du plan.
### B. Réseau & nomenclature — `plan/nomenclature.yml`
- `supernet`, `cidr_hote`, `reservations`, `categories` (VLAN/sous-réseau/passerelle),
`fonctions` (catégorie + service).
frontière nord/sud : devis dérivé, lien de transit et les deux routes 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>
2026-08-01 19:32:04 -04:00
### C. Hyperviseur Proxmox — `group_vars/proxmox.yml`
- `proxmox_api_host`, `proxmox_api_user`, `proxmox_api_port`, `proxmox_validate_certs`.
frontière nord/sud : devis dérivé, lien de transit et les deux routes 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>
2026-08-01 19:32:04 -04:00
- 🔒 `proxmox_api_token_id`, `proxmox_api_token_secret` — dans la **voûte unique** de
l'instance, `group_vars/all/vault.yml`. (L'ancienne `proxmox.vault.yml` reste lue en
compatibilité si elle existe encore ; cf. `docs/config-proxmox.md`.)
- Golden template : `proxmox_clone_vmid_modele`, `proxmox_clone_source_nom`.
- Placement par défaut : `proxmox_clone_noeud`, `proxmox_clone_stockage`,
`proxmox_clone_pont`, format, complet, timeout, disque, interface, démarrer.
### D. Identité initiale des VM — `group_vars/modeles_vm.yml`, `creer-vm`
- **Clé publique SSH** (cloud-init) — accès admin de toute la flotte.
- Compte technique `ansible` (`sudo_ansible_admin_user`) + sudo NOPASSWD, `ciuser`.
- Politiques SSH communes (port, password auth off, root login off, grace/auth tries).
### E. Socle durci commun — `group_vars/modeles_vm.yml`
nftables baseline · fail2ban SSH · auditd · AppArmor · sysctl · unattended-upgrades ·
journald (rétention) · core_dumps · systemd_ssh_auto.
### F. Endpoints des services centraux (les rôles `client_*` en dérivent)
- DNS interne : plancher `/etc/hosts` (`hosts_statiques`) + PowerDNS + `client_unbound` (opt-in).
- AC/PKI (`client_pki_ca_url` → infra-pki, provisioner).
- IdM/LDAP : annuaire résolu par `resoudre_annuaire` (hôte + base DN dérivés du domaine).
- Relais courriel (`client_smtp_relais` → edge-mta, MTA Postfix, port 25).
- Métriques (node_exporter `:9100`).
- Journaux (`client_journal_loki_url` → obs).
- Temps (NTP) : **implicite** (pool Debian par défaut — aucun intrant configuré).
### G. Dépôts APT tiers communs
- Smallstep (step-cli) — `client_pki``serveur_step_ca`.
- Grafana (alloy/loki/grafana) — `client_journal``serveur_loki`/`serveur_grafana`.
### H. Secrets Vault communs 🔒 — **voûte unique** `group_vars/all/vault.yml`
> Tous les secrets de l'instance dans **un seul fichier chiffré par environnement**
> (`inventories/<env>/group_vars/all/vault.yml`), gabarit
> [`exemples/vault.exemple.yml`](../exemples/vault.exemple.yml). Un mot de passe, un
> endroit. Édité via `ansible-vault edit` (jamais par le GUI).
**La liste ne s'écrit pas ici.** Elle se *recense*, depuis le plan, les rôles des groupes
actifs et les `group_vars` :
```sh
python3 scripts/voute.py lister # chaque secret exigé + d'où vient l'exigence
make prouver # P18 : le gabarit les couvre-t-il tous ?
```
C'est la même source que le rappel « Secrets attendus » du panneau d'intrants. Trois copies
manuelles de cette liste ont existé et **toutes ont divergé** — elles annonçaient
`vault_ldap_sssd`, qu'aucun rôle ne consomme, et `vault_step_ca_fingerprint`, que
`client_pki` dérive à chaud depuis l'AC plutôt que de la lire.
Mot de passe du Vault lui-même : saisi au déploiement.
### I. Exposition publique — `plan/domaines.yml`
domaines publics, `edge`, autorité DNS, FQDN exposés.
## 2. Classification proposée : constante vs défaut surchargeable
> **Proposition à valider.** « Constante » = une seule valeur, pas de surcharge
> (diverger casserait le modèle). « Défaut surchargeable » = valeur globale qui
> ressurgit comme défaut là où l'intrant réapparaît (hôte / groupe / application).
| Intrant | Classe | Surcharge où ? |
| --- | --- | --- |
| `domaine_interne` | **Constante** | — |
| Nomenclature (supernet, CIDR, catégories, fonctions) | **Constante** | — (le plan réseau est la loi) |
| Accès Proxmox (API host/user/port/token) | **Constante** | — (un seul cluster) |
| Golden template (vmid_modele, source_nom) | **Constante** | — |
| Secrets Vault | **Constante** 🔒 | — (gérés à part, jamais en clair) |
| `fuseau_horaire` | Défaut | par hôte (rare) |
| `proxmox_clone_noeud` / `stockage` / `pont` | Défaut | par hôte (`serveurs.yml`) |
| DNS internes (plancher `/etc/hosts` + PowerDNS + `client_unbound`) | Défaut | par hôte / groupe |
| Politiques durcissement (SSH, nftables, fail2ban, journald…) | Défaut | par hôte / groupe |
| Relais SMTP, TLS internes | Défaut | par hôte / groupe |
| `ciuser`, compte `ansible` | Défaut | rarement surchargé |
## 3. Saisie unique dans le GUI (cible)
Un panneau « Intrants de base » dans le GUI :
- édite les **constantes** et les **défauts** au même endroit ;
- pour un **défaut**, la valeur globale apparaît pré-remplie (et signalée comme
« héritée ») là où l'intrant réapparaît dans le plan, surchargeable sur place ;
- les **secrets** ne sont **jamais** stockés en clair par le GUI (cf. §H) — il en
gère au plus les *références*, l'édition réelle restant côté Vault.
Persistance : les fichiers de l'instance (`group_vars/all/10-intrants.yml` — forme
dossier ; la forme plate `group_vars/all.yml` reste lue en compatibilité —, `proxmox.yml`,
`modeles_vm.yml`, `plan/nomenclature.yml`). À détailler dans la note de conception de la
fonctionnalité GUI.
## 4. Incohérences repérées (à corriger)
- `fuseau_horaire` défini en **lab** seulement, absent de **production**.
- `group_vars/serveur_debian.yml` **référencé** (commentaire de prod `all.yml`) mais
**absent** des deux environnements.