forge du genome : mutualisee par site, avec une confiance limitee a une url

Une forge sert a deux choses que le meme logiciel confondait : porter le GENOME
-- meme contenu pour tous les tenants d'un site -- et heberger le TRAVAIL de ses
gens, qui est un service du tenant. La premiere se mutualise, la seconde non.

Lire le genome chez un voisin suppose de faire confiance a SON autorite. On ne
pose PAS cette racine dans le magasin systeme : `git config
http.<url>.sslCAInfo` limite la confiance a cette seule forge. Une porte, pas un
trousseau.

L'adresse est une IP : `forge.genese.internal` ne resout pas depuis un autre
tenant, et le certificat de l'edge porte l'IP dans ses SAN.

Effet de bord recherche : le genome devient disponible AVANT que la forge du
tenant soit debout. Un ecosysteme neuf n'attend plus sa propre forge pour se
remplir.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Daniel Allaire 2026-08-24 18:55:44 -04:00
parent da211bd81b
commit 9c173f52ba
4 changed files with 60 additions and 5 deletions

View file

@ -21,7 +21,7 @@
| P06 | Validateurs de registres (serveurs/apps/bases/domaines) | AFF-003 | ✅ OK | Registre des domaines valide. |
| P07 | GUI (node --check) | AFF-033 | ✅ OK | JS du GUI : syntaxe valide (node --check). |
| P08 | Orchestration (couches + graphe) | AFF-070 | ✅ OK | Orchestration coherente : 35 groupes classes, aucun cycle, aucune arete en arriere. |
| P09 | Flux reseau (schema + matrice) | AFF-071 | ✅ OK | Flux coherents : 34 rôles, 86 flux, schéma + matrice OK. |
| P09 | Flux reseau (schema + matrice) | AFF-071 | ✅ OK | Flux coherents : 34 rôles, 87 flux, schéma + matrice OK. |
| P10 | Handlers <-> notify | AFF-034, AFF-035 | ✅ OK | Tout notify pointe vers un handler du meme role (49 roles). |
| P11 | Syntaxe des playbooks (--syntax-check) | AFF-083 | ✅ OK | playbook: playbooks/proxmox/cloner_vm_debian.yml |
| P12 | Existence des runbooks cites | AFF-010, AFF-011, AFF-012, AFF-083 | ✅ OK | 17/17 runbooks/registres cites presents. |
@ -36,7 +36,7 @@
| P21 | Federation : aucun index en collision | AFF-102 | ✅ OK | Federation coherente : 3 instance(s) federee(s), aucun index en collision. |
| P22 | Plan de recette a jour (genere du wiki) | AFF-002 | ✅ OK | Plan de recette à jour (22 sections). |
| P23 | Underlay sans collision avec la plage tenant | AFF-103 | ✅ OK | Underlay conforme : 7 reseau(x), aucune collision avec la plage tenant. |
| P24 | Frontiere nord/sud : acces d'administration declare | AFF-104 | ✅ OK | CONFORME : frontiere nord/sud, 62 regles, 15 routes, admin=10.0.0.0/24,10.17.0.0/24,10.29.19.41/32,192.168.254.2/32,192.168.255.2/32. |
| P24 | Frontiere nord/sud : acces d'administration declare | AFF-104 | ✅ OK | CONFORME : frontiere nord/sud, 68 regles, 15 routes, admin=10.0.0.0/24,10.17.0.0/24,10.29.19.41/32,192.168.254.2/32,192.168.255.2/32. |
| P25 | Pare-feu Proxmox : est-ouest intra-tenant derive | AFF-107 | ✅ OK | CONFORME : pare-feu Proxmox, 3 tenant(s), 51 groupe(s), 80 regle(s). |
| P26 | Integrations universelles : aucun hote laisse de cote | AFF-108 | ✅ OK | 15 hote(s) x 5 integration(s) universelle(s) : aucune lacune, aucune recopie (0 exemption(s) derivee(s) du service rendu). |
| P27 | Propriete des intrants : hebergeur et tenant separes | AFF-109 | ✅ OK | 8 cle(s) de cluster chez l'hebergeur, aucune recopiee dans les group_vars du tenant. |
@ -44,7 +44,7 @@
| P29 | Authentification : chaque role declare sa position | AFF-111 | ✅ OK | 28 role(s) serveur declares (interne-sans-auth 2, ldap-direct 2, sans-auth-humaine 17, socle-identite 2, web-sso 5) ; 2 lacune(s) nommee(s) : serveur_loki, serv |
| P30 | SDN EVPN : zones, VNets et sous-reseaux derives | AFF-112 | ✅ OK | CONFORME : SDN EVPN, 3 zone(s), 15 VNet(s), 15 sous-reseau(x), aucune collision. |
| P31 | Documentation : tout ce que le depot FAIT est nomme | — | ✅ OK | 47 scripts expliques et atteignables, 98 cibles make documentees, 60 roles avec README. |
| P32 | Intrants exiges par les roles : tous fournis | — | ✅ OK | CONFORME : 37 exigence(s) de role, toutes satisfaites (122 cle(s) declaree(s) par l'instance). |
| P32 | Intrants exiges par les roles : tous fournis | — | ✅ OK | CONFORME : 37 exigence(s) de role, toutes satisfaites (125 cle(s) declaree(s) par l'instance). |
| P33 | Aucune collision de port entre roles co-localises | — | ✅ OK | CONFORME : 33 revendication(s) de port, aucune collision entre roles co-localises (37 groupes). |
| P34 | Chaque document declare son lecteur | — | ✅ OK | 42 document(s) declarent leur lecteur (22 genere(s) exempte(s)). |
| P35 | Toute application exigeant une base en a une au plan | — | ✅ OK | 5 application(s) exigeant une base l'ont toutes (4 entree(s) au registre). |

View file

@ -68,6 +68,21 @@ serveur_ops_forge_organisation: "genome"
serveur_ops_forge_externe: false
serveur_ops_forge_amont: ""
# --- LA CONFIANCE ENVERS UNE FORGE D'UN AUTRE TENANT -------------------------
#
# Lire le genome chez un voisin suppose de faire confiance a SON autorite — or chaque
# ecosysteme a la sienne, et `client_pki` n'etablit la confiance que dans celle du tenant.
#
# ON NE POSE PAS CETTE RACINE DANS LE MAGASIN SYSTEME. L'y mettre ferait confiance a cette
# AC pour TOUT ce que la machine contacte, alors qu'on ne lui demande qu'une chose : servir
# un depot git. `git config http.<url>.sslCAInfo` limite la confiance a CETTE url — une
# porte, pas un trousseau.
#
# Chemin d'un certificat racine PUBLIC, sur le controleur. Vide = rien a poser (forge du
# meme ecosysteme, ou AC publiquement reconnue).
serveur_ops_forge_amont_ac: ""
serveur_ops_forge_amont_ac_depot: "{{ serveur_ops_racine }}/.ac-amont.crt"
# Les dépôts du génome, et où ils atterrissent. Les noms sont ceux que la forge porte
# (minuscules) ; les destinations reprennent la disposition du poste du mainteneur, où
# le moteur et les instances sont des dossiers frères — c'est cette fraternité que

View file

@ -25,3 +25,15 @@ flux:
pair: externe
chiffrement: tls-requis
raison: "API de l'hyperviseur : créer et cloner les VM d'un écosystème descendant."
# LIRE LE GENOME CHEZ UN VOISIN. La forge du genome se mutualise par SITE : le moteur,
# les modeles et la fabric sont le meme contenu pour tous les tenants. Seul le plan
# `OPS-xxx` differe.
#
# La forge DE TRAVAIL d'un ecosysteme -- celle qui sert ses gens -- reste un service du
# tenant, et n'a rien a voir avec ce flux.
- sens: egress
port: 443
protocole: tcp
pair: voisins_site
chiffrement: tls-requis
raison: "Cloner le genome depuis la forge du site, quand cet ecosysteme n'heberge pas la sienne."

View file

@ -68,14 +68,42 @@
delay: 6
until: serveur_ops_pip is succeeded
# LA CONFIANCE, AVANT LE CLONE — et limitee a une seule url.
#
# Voir defaults/main.yml : on ne pose pas cette racine dans le magasin systeme. `git
# config http.<url>.sslCAInfo` ne l'applique qu'aux echanges avec CETTE forge.
- name: Deposer la racine de la forge amont
ansible.builtin.copy:
src: "{{ serveur_ops_forge_amont_ac }}"
dest: "{{ serveur_ops_forge_amont_ac_depot }}"
owner: "{{ serveur_ops_utilisateur }}"
group: "{{ serveur_ops_utilisateur }}"
mode: "0644"
when:
- serveur_ops_forge_amont_ac | length > 0
- not ansible_check_mode
- name: Limiter la confiance a la forge amont, et a elle seule
community.general.git_config:
name: "http.{{ serveur_ops_forge_url }}/.sslCAInfo"
scope: global
value: "{{ serveur_ops_forge_amont_ac_depot }}"
become: true
become_user: "{{ serveur_ops_utilisateur }}"
when:
- serveur_ops_forge_amont_ac | length > 0
- not ansible_check_mode
# --- LE GÉNOME, DEPUIS SA PROPRE FORGE ---------------------------------------
#
# Cloné en anonyme : les dépôts du génome sont lisibles sur la forge de l'écosystème, et
# le poste n'a donc AUCUN justificatif à détenir pour se reconstruire. C'est délibéré —
# un secret de moins sur la machine qui en concentre déjà beaucoup.
#
# La confiance TLS vient de `client_pki` (racine step-ca dans le magasin système). Sans
# lui, `git clone` refuse le certificat de la forge — et c'est bien qu'il refuse.
# La confiance TLS vient de `client_pki` quand la forge est celle de CET écosystème
# (racine step-ca dans le magasin système). Quand elle est celle d'un voisin, elle vient
# de la tâche ci-dessus — limitée à cette seule url. Sans l'une ou l'autre, `git clone`
# refuse le certificat, et c'est bien qu'il refuse.
- name: Cloner le génome depuis la forge de l'écosystème
ansible.builtin.git:
repo: "{{ serveur_ops_forge_url }}/{{ serveur_ops_forge_organisation }}/{{ item.depot }}.git"