Commit graph

22 commits

Author SHA1 Message Date
60a60b6fb1 pools Proxmox : un par tenant, dérivé de l'index (D-37, P28)
Onze des quatorze serveurs portent le même nom court chez Chezlepro et chez
Technolibre. Vérifié un par un, ce n'est pas un problème technique : tout le
reste dérive du seed et diverge (10.27.19.21 contre 10.21.19.21, VMID 117402101
contre 111402101, VLAN 1174 contre 1114, deux domaines internes), et rien n'est
indexé sur le nom court — les opérations Proxmox portent toutes un vmid, les
certificats un FQDN, et client_backup_repo vise backup-01.{{ domaine_interne }}.

Le coût est humain : la console Proxmox affiche le nom, et deux infra-pki-01 y
sont indiscernables à l'œil. Le VMID porte le tenant, encore faut-il connaître le
codage.

Un pool par tenant, dérivé du dossier d'instance et de l'index — déjà unique par
P21, donc aucun registre de plus : Chezlepro-17, Technolibre-11.

make devis-proxmox-pools rattrape la flotte existante (création du pool, puis
affectation des VM actives). Les VM créées ensuite entrent d'elles-mêmes :
make creer-vm dérive le pool par la même fonction et le passe à la création. Le
playbook crée le pool au préalable — proxmox_kvm échoue sur un pool inconnu, et
l'API ne sait pas changer le pool d'une VM existante ; c'est aussi pourquoi le
rattrapage passe par les membres.

P28 garde deux collisions : même nom de pool entre tenants, et surtout même VMID
— une machine appartenant à deux tenants serait pire qu'une homonymie.

Rien n'est renommé : les homonymes sont la preuve que la nomenclature est un vrai
gabarit. Le devis ne lit pas le cluster, il dit l'état cible et non l'écart.

27 preuves OK, 0 échec. --syntax-check du playbook de clonage.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-03 15:15:14 -04:00
fd62b59989 pare-feu Proxmox : le filtrage est-ouest intra-tenant, dérivé (P25)
`make devis-proxmox-fw` : 34 groupes de sécurité, 40 règles, 2 tenants —
depuis les 57 flux intra-tenant que le registre connaissait déjà.

Défense en profondeur, pas remplacement : l'hyperviseur filtre puis l'hôte
destinataire filtre à nouveau. Coût de maintenance nul, les deux barrières
lisent le registre par les MÊMES fonctions — la duplication est dans
l'application, jamais dans la décision.

Un IPSet par rôle porte les membres, les groupes y renvoient : ajouter un
hôte à un rôle met à jour toutes les règles qui l'autorisent, en un endroit.

Garde ajoutée après coup : Proxmox limite un nom de groupe à 18 caractères.
Ma première version tronquait sans vérifier — deux rôles tronqués au même nom
auraient fusionné leurs règles, donnant à une VM les autorisations d'un rôle
qu'elle ne porte pas, silencieusement. Le préfixe porte maintenant l'index
plutôt que l'étiquette, et une garde échoue sur toute collision. Exercée.

Conséquence consignée : tout ce qui entre dans un tenant passant par la
frontière, le contrôleur Ansible aussi — l'OPNsense devient un prérequis de
déploiement, pas une étape parmi d'autres.

Preuves : 25 OK, 0 échec.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-03 11:43:32 -04:00
3698152b6a 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
8c401f95cf wiki : intègre les 8 vues annotées à « Le GUI (console d'exploitation) »
La série d'illustrations (commit précédent) rejoint sa page. En fin de section
② de l'unité, une galerie « Les vues, annotées » présente les 8 figures — vues
éditables (Serveurs, Applications, Bases × 2, Domaines) puis dérivées (Flux,
Couches, Réseau) — chacune un SVG auto-contenu avec ses repères + légende.

Mécanique, sans duplication dans l'arbre source :
- symlink wiki/img -> ../docs/img : foyer unique dans docs/img/, refs relatives
  (img/*.svg) qui résolvent en local et sur le navigateur de dépôt ;
- make wiki-publier embarque désormais les docs/img/*-annote.svg (déréférencés)
  dans le wiki Forgejo publié — jusqu'ici seules les .md voyageaient, donc aucune
  image n'aurait rendu une fois publiée.

Preuves : 22 OK / 0 échec / 1 sauté (dont P22 « plan de recette à jour »).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-28 13:57:39 -04:00
272f6369d8 Underlay : fabric physique cluster-global (mgmt/iSCSI/Ceph) + preuve P23
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>
2026-07-24 14:56:38 -04:00
412448ba55 Devis switch : dialecte cisco|binardat (masque ACL + remark)
Le switch Binardat differe de Cisco sur deux points que le devis ignorait :
- masque d'ACL normal (255.255.0.0) au lieu du wildcard inverse (0.0.255.255) ;
- pas de commande 'remark' (commentaires d'ACL).

devis_reseau.py gagne un dialecte (defaut cisco, option binardat) : masque_acl()
et remarque() adaptent la sortie. Reglable par --dialecte, SETOPS_DIALECTE, ou
make devis-reseau DIALECTE=binardat. Le GUI suit l'env. Public reste generique.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-23 17:15:27 -04:00
58015f56e0 Plan de recette (P22) : le pendant manuel de make prouver
Les 78 exercices « À toi de jouer » du wiki forment un plan de tests d'acceptation.
Formalisé sans dupliquer :

- scripts/plan_recette.py + make plan-recette : GÉNÈRE docs/audit/plan-de-recette.md
  depuis les exercices du wiki. Grille auto-contenue par unité, colonnes : ce qu'on
  éprouve · le geste · type (observe/casse-répare) · Preuve auto (le Pxx extrait du
  texte -> quels gestes manuels sont AUSSI gardés par la machine). Générée -> ne peut
  pas dériver du wiki.
- Preuve P22 : plan_recette.py --verifier échoue si le fichier committé est périmé.
  Le plan de recette devient auto-gardé.
- Honnêteté de couverture assumée : « — » = manuel seul ; pas d'exhaustivité au-delà
  des exercices du wiki.

Pendant humain de make prouver (le harnais prouve le moteur P01-P21, la recette valide
l'exploitation) ; checklist du protocole-operateur-independant (« exploitable sans IA »).

Validé : 78 gestes / 19 unités, 5 doublés d'un Pxx ; P22 détecte une dérive (testé) ;
make verifier -> CONFORME 22/22 (instance cohérente).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-23 15:49:16 -04:00
4180913c25 Créer un modèle (make model-creer) — base + promotion d'instance
Symétrique d'instance-creer, produit un modèle dans le dépôt PRIVÉ
(Set-OPS-Modeles/, jamais exemples/modeles/). scripts/model_creer.py, 2 modes :
- MODE=base : copie un modèle générique.
- MODE=instance : PROMEUT une instance en modèle (généralise identité ->
  exemple.*, index -> 1, production -> false, nftables_admin_ssh -> [], cle de
  sauvegarde videe, proxmox.yml generique [D1], inventaire principal [D2]).

Surete : aucun secret ne sort (vault.yml/proxmox.vault.yml jamais copies ; refus
si l'un subsiste ; .example conserve). Copie CIBLEE (plan/ + inventories/ seulement,
symlinks resolus) -> robuste aux depots imbriques et boucles de symlinks. Le modele
produit doit valider (modeles.py verifier), sinon annule.

Teste en isolement (depot prive jamais touche) : promotion du labo reussie +
validee (aucun chezlepro residuel, aucun secret, proxmox generique) ; copie socle
OK ; refus d'une instance INVALIDE (garde-fou : hote fantome detecte).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-23 14:43:06 -04:00
d8474d1c9f Créer une instance depuis un modèle (CLI + GUI)
Le moteur reste independant des instances ET des modeles assembles (prives) :
il ne contient que le modele public socle ; les modeles assembles sont
DECOUVERTS au runtime via SETOPS_MODELES (depot prive de l'operateur), jamais
embarques dans le code public.

- scripts/instance_creer.py : copie un modele (exemples/modeles/* + SETOPS_MODELES)
  vers un depot frere ../<nom>, y fixe l'index, et refuse un nom existant, un
  modele inconnu, ou un index en collision avec une instance federee (verifie
  AVANT toute copie). .git et hosts.genere.yml non copies.
- make instance-creer NOM=.. MODELE=.. [INDEX=N] ; make instance-modeles.
- GUI (vue Reseau) : formulaire « Creer une instance depuis un modele » sous la
  flotte. POST /api/instance-creer ; /api/instances renvoie aussi modeles +
  index_pris. Ne bascule pas l'active.

Corrige : gabarit de voute du labo complete (P18 a echoue en passant l'active
sur le labo, dont le vault.yml.example etait reste a 17 cles ; aligne sur 23).

Valide : garde-fous de creation testes en isolement (collision refusee avant
copie, ecrasement refuse, modele inconnu refuse, aucune pollution) ; node --check ;
make verifier rc=0 CONFORME 21/21 (active = labo).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-23 14:13:36 -04:00
b1460a6dde Multi-instances : make instances (vue + collision) + preuve P21
La bascule d'instance existait deja (make instance-utiliser / instance-courante,
repointage du symlink). Manquaient la vue d'ensemble et le filet de securite.

- make instances (scripts/instances.py) : liste les instances de la federation
  (depots freres avec plan/nomenclature.yml), marque l'active (*), montre index,
  plage VLAN derivee, statut federe/local et production. Lecture seule.
- Detection de collision d'index entre instances FEDEREES (memes VLAN/VMID sur le
  trunk) : le piege exact vecu (prod + labo tous deux a l'index 1) est desormais
  crie. Mode --verifier -> rc=2 sur collision.
- Preuve P21 : cable ce garde-fou dans make prouver / make verifier. No-op quand
  moins de deux instances federees sont presentes (comme P17 sans SETOPS_MODELES).

Valide : make instances liste les 3 instances (labo LOCAL, Technolibre + Chezlepro
federees, index 2 et 13) ; detection testee en synthetique (deux federees meme
index -> collision ; labo federe:false -> coherent) ; make verifier rc=0
CONFORME 21/21.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-23 11:26:01 -04:00
5a53332f96 make verifier inclut les preuves (make prouver --verifier)
- prouver.py : nouveau mode --verifier — exécute toutes les preuves du registre
  (verdict + code de sortie) sans écrire de rapport, pour ne pas écraser la pièce
  justificative committée docs/audit/preuve-<date>.md.
- Makefile : make verifier se termine par `python3 scripts/prouver.py --verifier`
  → verifier échoue si une preuve échoue. make prouver seul écrit toujours le rapport.
- docs/audit/README.md : section « Rapport avec make verifier » mise à jour.

Vérifié : make verifier → CONFORME 16/16 (voûte), aucun churn du rapport ; make
prouver écrit toujours ; ansible-lint 0 failure.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-20 21:03:20 -04:00
835f8ab6d0 Mise en conformité prouvable : registre d'affirmations + make prouver
Le dépôt fait / explique / prouve ce qu'il affirme, vérifiable en une commande.

- Phase 1 : docs/audit/affirmations.md — 54 affirmations publiques tracées vers
  une commande de preuve et un statut (/🟡//).
- Phase 2 : CLAUDE.md réduit à un pointeur mince ; contradiction SSH levée (le
  code applique déjà PasswordAuthentication no + AuthenticationMethods publickey,
  conforme à AGENTS.md) ; section AGENTS « Codex » → « agents IA ».
- Phase 3 : parcours démarrage réparé (QUICKSTART renvoyait à un modèle absent,
  chemins de voûte faux, commandes make périmées) ; make verifier vert
  (ansible-lint 33 → 0 : site.yml généré nommé, pipefail, name[template]) ;
  voûte Proxmox unifiée lue par le clonage (all/vault.yml).
- Phase 4 : make prouver → docs/audit/preuve-<date>.md, harnais rejouable qui
  rappelle l'outillage existant (aucune validation réimplémentée).
- Phase 5 : parcours QUICKSTART prouvé hors-ligne sur le socle ; modèle socle
  rendu valide (autorite interne → auto-heberge) ; split-brain d'inventaire
  corrigé (repli sur le répertoire existant, pas principal/).

make prouver : 15 OK, 0 échec, 1 sautée (voûte). ansible-lint : 0 failure.
Écarts découverts en cours de traitement (AFF-097..100) : tous résolus.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-20 19:53:18 -04:00
97670dd27c make devis-reseau : config switch derivee du plan
scripts/devis_reseau.py decouvre les instances federees (ip-miroir) et emet
VLANs + SVIs + ACLs d'isolation inter-tenant, derives des nomenclatures.
Plus jamais saisi a la main. Eprouve sur Chezlepro + Technolibre.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-07 15:50:18 -04:00
77dcc72aa6 Recette d'acceptation : make valider (phase 4, v1)
Vérifie que les services FONCTIONNENT, pas juste qu'ils sont déployés — complète
les *-verifier (statiques, sur le plan) par une recette fonctionnelle vivante.

playbooks/valider.yml (lecture seule) :
- Prometheus : toutes les cibles de supervision UP (API /targets)
- Edge : les vhosts HTTPS exposés répondent (server_name réels filtrés sur
  domaine_interne, statut sain 200/301/302/401/403)

Éprouvé sur la flotte : 7 cibles UP, 8 vhosts OK (sous pare-feu actif).
À venir : courriel bout-en-bout (envoi->IMAP), restauration de sauvegarde.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-07 03:19:51 -04:00
f05f505b88 Reconstruction propre : orchestrateur ordonné, registre des flux + pare-feu
Rend l'écosystème reconstructible en une commande (create+deploy idempotent) et
ajoute la couche « accès » (nftables least-privilege) au zéro-confiance.

Orchestrateur (phase 2) :
- docs/couches-deploiement.yml : registre des couches (socle → pki → services → apps → agents)
- scripts/orchestrer.py : tri par couche + topo intra-couche (graphe) → playbooks/site.yml ordonné
- Makefile : site / deployer-tout / flotte-creer / reconstruire / myDay (+ gardes CONFIRMER)
- docs/dependances-groupes.yml : graphe complété (keycloak→openldap, dovecot, postfix, icingaweb2, nextcloud)

Audit codé-en-dur (phase 1b) : labels/slug OIDC dérivés de l'intrant `organisation`
(serveur_forgejo/grafana/nextcloud) — le moteur ne porte plus de nom de tenant.

Registre des flux réseau (phase 0) :
- meta/flux.yml pour tous les rôles (29 rôles, 63 flux ; schéma + matrice validés)
- scripts/resoudre_flux.py : matrice d'audit (docs/registre-flux.md) + rulesets nftables résolus par hôte
- roles/nftables_baseline : déploie le ruleset résolu (moindre-privilège) quand activé, sinon repli

Correctifs : détection du coffre Vault (chemin production → inventaire réellement résolu).
Outillage : make wiki-publier (publication du wiki pédagogique dans Forgejo).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-07 03:08:09 -04:00
da85af2a62 Corriger 3 bugs trouvés au premier déploiement réel (asgard)
- clonage/Makefile : chemin proxmox codé en dur `inventories/lab` →
  détection lab>principal>production (débloque les instances principal)
- resize disque grow-only : tolère le cas disque dérivé < template
  (shrinking not supported), la VM garde le disque du template
- PowerDNS : ne plus redéclarer launch+=bind (déjà posé par le paquet
  pdns-backend-bind) → « multiple backends 'bind' » résolu

Trouvés en déployant réellement infra-dns-01 (clone + socle durci +
PowerDNS qui résout) sur le cluster Proxmox.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-01 15:38:42 -04:00
e57d2c265a Bascule d'instance (make instance-utiliser) + identité relative à l'inventaire
make instance-utiliser NOM=… repointe le symlink 'instance' (prod ↔ bac à
sable) ; make instance-courante affiche le montage. Le panneau Intrants lit
l'identité dans group_vars/all/10-intrants.yml de l'inventaire monté (réel
ou symlink partagé), donc compatible avec la séparation par instance comme
avec l'ancien partage lab/production.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-30 16:31:42 -04:00
e2b924cedc Inventaire d'instance neutre et configurable (principal / SETOPS_INVENTAIRE)
Le moteur ne code plus en dur inventories/lab|production : un inventaire
par instance, détecté de façon rétro-compatible (principal > production >
lab) et surchargeable par SETOPS_INVENTAIRE. Makefile (définitions seules,
pas les 47 usages), inventory_gui, instancier, config_proxmox, serveurs,
applications. Les instances lab/production existantes marchent à
l'identique ; les nouvelles adoptent inventories/principal/.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-30 16:08:25 -04:00
441dd284bb Documenter les paramètres de make config
Ajoute docs/config-proxmox.md : référence champ par champ des 16 paramètres
Proxmox non sensibles + les secrets API demandés par l'assistant (sens,
défaut, quoi saisir, constante vs défaut surchargeable), plus l'annexe de
création du token API. Renvois ajoutés depuis make help et QUICKSTART.md.
Ces invites n'étaient expliquées nulle part de façon pérenne.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-30 12:19:14 -04:00
5d30a3a608 Dimensionner les ressources VM depuis les logiciels hébergés
Les cœurs/RAM/disque d'une VM sont estimés depuis l'empreinte des rôles
hébergés (roles/<rôle>/meta/empreinte.yml) sommée au socle SE, au lieu
d'hériter des specs du golden template. Le générateur écrit
proxmox_coeurs/memoire/disque_taille ; le clonage les passe à Proxmox
(omit si absent → aucune régression). Override par hôte dans le plan.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-30 10:07:04 -04:00
c77ec20e4a Corriger instancier-appliquer FORCE=1 (ne relayait pas --force)
Trouve en dogfooding pendant la recreation d'une instance depuis un modele.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-25 09:29:08 -04:00
Alliance Boreale
3dd3f43ad8 Set-OPS — moteur d'ecosystemes numeriques souverains (Alliance Boreale) 2026-06-24 20:17:46 -04:00