README reduit au role du projet et au demarrage rapide. docs/architecture.md (schemas Mermaid), docs/setup.md, docs/usage.md (154 cibles en 13 familles), docs/README.md (index). Documents ranges en conception/, exploitation/, hebergement/, projet/ ; 598 chemins suivis. QUICKSTART.md, SOLUTION.md, architecture-set-ops.md et la carte fondus puis retires. Preuves : P48 lit l'index et conception/mecanismes.md ; les gardes parcourent docs/ sous- dossiers compris (_documents) ; usage.md suit le Makefile dans les deux sens. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
9.8 KiB
9.8 KiB
Architecture
Pour qui : quiconque doit comprendre comment Set-OPS est construit — avant de l'installer, de l'exploiter ou de le modifier. Le détail de chaque mécanisme est dans
docs/conception/; l'index complet dansREADME.md.
Set-OPS est un moteur Ansible et Python. Il lit un plan déclaratif, en dérive un inventaire et des politiques, et les applique à des VM Debian 13 clonées sur une grappe Proxmox. Le moteur est générique ; chaque écosystème réel vit dans son propre dépôt.
Composants
flowchart LR
subgraph POSTE["Poste de l'exploitant (ou runner)"]
MOT["Set-OPS<br/>moteur : roles/, playbooks/, scripts/"]
INST["instance/ → ../OPS-X<br/>le locataire actif"]
UND["underlay.yml → ../SITE-Y/underlay.yml<br/>le site actif"]
CLE["~/.config/setops-vault-*<br/>une clé par voûte"]
end
subgraph SITE["Site d'hébergement"]
PVE["Grappe Proxmox<br/>SDN EVPN, pare-feu est-ouest"]
OPN["Frontière OPNsense<br/>nord/sud"]
RUN["site-ops-01<br/>runner du site"]
FORGE["Forge du site<br/>le génome"]
VMS["VM des locataires<br/>et du site"]
end
MOT -- "lit" --> INST & UND
MOT -- "API Proxmox : clone, SDN, pare-feu" --> PVE
MOT -- "API OPNsense : règles, routes" --> OPN
MOT -- "SSH + Ansible" --> VMS
POSTE -- "make publier / genome-pousser" --> FORGE
RUN -- "tire" --> FORGE
RUN -- "SSH + Ansible" --> VMS
PVE --- VMS
| Composant | Ce que c'est | Où |
|---|---|---|
| Moteur | rôles, playbooks, scripts de dérivation, preuves | ce dépôt |
| Locataire (tenant) | un écosystème : son plan, son inventaire généré, sa voûte | dépôt OPS-<nom>, monté par instance/ |
| Site | l'hébergeur : matériel, underlay, frontière, services prêtés aux locataires | dépôt SITE-<nom>, désigné par underlay.yml |
| Voûtes | secrets chiffrés ansible-vault, une par dépôt, une clé par voûte |
group_vars/all/vault.yml ; clés hors dépôt |
| Runner du site | machine du site qui déploie à la place du poste | site-ops-01, compte setops, /opt/setops |
| Forge du site | Forgejo qui porte le génome (moteur + plans) que les runners tirent | VM du site |
Moteur, site, locataire
flowchart TB
M["Set-OPS (moteur)"]
S["SITE-Y<br/>underlay.yml · plan/ · opnsense.yml"]
T1["OPS-A<br/>plan/ · inventories/"]
T2["OPS-B<br/>plan/ · inventories/"]
M -. "monte un site" .-> S
M -. "monte un locataire" .-> T1 & T2
S -- "contrat du site → fiche-site.yml" --> T1 & T2
T1 & T2 -- "face réseau publiée" --> S
- Deux classes d'écosystème, un tronc commun :
scripts/contexte.pyest le seul endroit qui lit les indices (instance/,underlay.yml,SETOPS_*, dossiers frères) et rend unSiteou unLocataire. Conception :docs/conception/conception-contextes.md. - Le site lit la face réseau des locataires, le locataire lit la fiche du site. Le
contrat (
make site-intrants) dérive ce que le site expose : résolveur, cache de paquets, forge, adresses publiques, serveurs DNS publics.make fiches-site-deposerle dépose chez chaque locataire (fiche-site.yml) ;make site-intrants-verifierjuge l'écart. - Multi-instance par convention : un dépôt par écosystème, découverts comme dossiers
frères. Tout l'adressage dérive d'un seed
indexpar écosystème ; P21 refuse une collision. Détail :docs/conception/multi-instances.md. - Le site prête trois services à un locataire jeune — paquets (
serveur_cache_site), génome (serveur_forge_site), noms (serveur_resolveur_site) — jusqu'à ce qu'il ait les siens. Filiation et émancipation :docs/conception/filiation-emancipation.md.
Du plan au déploiement
flowchart LR
PLAN["plan/<br/>serveurs · applications · bases-donnees<br/>domaines · nomenclature"] --> INS["make instancier<br/>scripts/instancier.py<br/>inventory_rules.py"]
INS -- "diff sémantique" --> APP["make instancier-appliquer"]
APP --> HOSTS["inventories/INVENTAIRE/hosts.yml<br/>GÉNÉRÉ"]
COUCHES["docs/couches-deploiement.yml<br/>docs/dependances-groupes.yml"] --> ORCH["make site<br/>scripts/orchestrer.py"]
ORCH --> SITEYML["playbooks/site.yml<br/>GÉNÉRÉ"]
HOSTS & SITEYML --> ANS["make deployer · deployer-tout<br/>ansible-playbook"]
VAULT["vault.yml<br/>ANSIBLE_VAULT_IDENTITY_LIST"] --> ANS
ANS --> VM["VM : groupes → playbooks/groupes/GROUPE.yml → rôles"]
- On édite le plan, jamais l'inventaire. VMID, IP, VLAN, FQDN et appartenances aux
groupes sont dérivés de la
fonctiond'une VM et des applications qui y tournent. - L'inventaire est généré et comparé à l'existant avant d'être écrit.
- L'ordre de déploiement est généré depuis les couches et le graphe des dépendances entre groupes.
- Un groupe = un playbook homonyme (
playbooks/groupes/<groupe>.yml) qui applique ses rôles. Le socle (serveur_debian) et le durcissement (serveur_durci) passent en premier.
Les registres du plan :
| Registre | Entité | Champs clés |
|---|---|---|
plan/serveurs.yml |
VM | fonction, etat (planifie → actif), placement |
plan/applications.yml |
service (entité pivot) | groupe (rôle), hote, port, liens, expose |
plan/bases-donnees.yml |
base | serveur, propriétaire, secret en voûte, consommateur, portee |
plan/domaines.yml |
zone DNS | autorite, edge, dnssec, enregistrements, resolution_interne |
plan/nomenclature.yml |
dérivation | index (seed), fonctions → VMID / VLAN / IP |
Détail : docs/conception/plan-et-generation.md, docs/conception/meta-classe.md.
Ce qu'un rôle déclare, ce que le moteur dérive
Chaque rôle porte ses déclarations dans roles/<rôle>/meta/. Le moteur les agrège ; aucune
liste n'est tenue à la main ailleurs.
| Déclaration | Ce que le moteur en dérive | Doc |
|---|---|---|
meta/flux.yml |
nftables de l'hôte, pare-feu Proxmox, frontière OPNsense, registre des flux | conception/flux-conception.md |
meta/liens.yml |
variables de connexion service → service | conception/bindings-conception.md |
meta/empreinte.yml |
RAM, CPU, disque de la VM | conception/dimensionnement-ressources.md |
meta/supervision.yml, meta/metriques.yml |
services Icinga, cibles Prometheus, tableaux | conception/supervision-conception.md |
meta/authentification.yml |
portée et mécanisme d'authentification du rôle, gardés par P29 | conception/authentification.md |
meta/acces.yml |
rôles d'accès projetés dans Keycloak | exploitation/autorisation.md |
meta/integration.yml |
intégrations universelles (client_*) posées sur chaque VM |
conception/integrations-vm.md |
Réseau
flowchart TB
NET(("Internet")) --> OPN["Frontière OPNsense<br/>nord/sud · seul équipement L3 de bordure"]
OPN --> SDN["SDN EVPN sur les hyperviseurs<br/>une zone (VRF) par écosystème · passerelles anycast"]
SDN --> PFW["Pare-feu Proxmox<br/>est-ouest, par VM"]
PFW --> NFT["nftables de l'hôte"]
NFT --> SVC["service"]
FLUX["roles/*/meta/flux.yml"] -. "dérive" .-> OPN & PFW & NFT
- Underlay (
underlay.ymldu site) : la fabric physique — gestion, iSCSI, Ceph, ponts.make underlay-planle confronte au réel. - Overlay : un écosystème = une zone EVPN et ses VNets, nommés depuis le seed
(
make sdn-plan). Détail :docs/conception/sdn-evpn.md. - Quatre couches de filtrage, une seule source : les flux déclarés par les rôles.
pair: externedevient la politique de bordure. Détail :docs/conception/frontiere-opnsense.md,docs/conception/registre-flux.md. - Deux sites reliés par un tunnel WireGuard (
opnsense_liens_sites) : réplication du DNS public, administration du site pair. DNS :docs/conception/dns-interne.md.
Déclaré, dérivé, mesuré
flowchart LR
D["Déclaré<br/>plan · meta/ · cartes"] --> V["Dérivé<br/>devis : scripts/devis_*.py"]
V --> P["make SUJET-plan<br/>écart, aucune écriture"]
P --> A["make SUJET-appliquer CONFIRMER=true<br/>réconcilie"]
R["Réel<br/>API Proxmox · OPNsense · VM"] --> P
D --> PR["make prouver / verifier<br/>preuves statiques : lisent le dépôt"]
- Les preuves (
make verifier,make prouver) lisent le dépôt seulement : cohérence du plan, des rôles, de la doc. Registre :docs/audit/affirmations.md. - Les devis lisent le système en marche et le comparent à ce que le plan dérive. Ils
n'écrivent rien ; la cible
-appliquercorrespondante réconcilie, sousCONFIRMER=true. Détail :docs/exploitation/devis-services.md.
Sécurité
| Sujet | Mécanisme | Doc |
|---|---|---|
| Secrets | une voûte par dépôt, une clé par voûte, scripts/voutes.py construit ANSIBLE_VAULT_IDENTITY_LIST |
exploitation/sortir-les-cles-du-poste.md |
| Confiance machine | AC interne step-ca (ACME), certificats par client_pki |
conception/integrations-vm.md |
| Identité | OpenLDAP source unique, Keycloak fédéré, oauth2-proxy devant les services sans OIDC |
conception/identite-sso.md, conception/authentification.md |
| Habilitations | amorcées par amorcage_acces, jamais réconciliées |
exploitation/autorisation.md |
| Administration | tunnel WireGuard nominatif admins, rebond par la frontière |
exploitation/acces-administration.md |
| Transit | chaque flux déclare son chiffrement ; le registre en fait la synthèse |
conception/flux-conception.md, conception/registre-flux.md |
Invariants
- Logiciel libre exclusivement ; ni Docker, ni Podman.
- L'inventaire et
playbooks/site.ymlsont générés : ne pas les éditer. - Aucun nom d'inventaire codé en dur :
<inventaire>est résolu parORDRE_INVENTAIRE. - Le moteur s'exploite sans IA : la doc,
makeet le GUI suffisent. - L'autorité est
AGENTS.md.