Set-OPS-Public/docs/conception/mecanismes.md
Daniel Allaire aab1bcc83a doc : rangee par lecteur, trois portes d'entree (architecture, setup, usage) et un index
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>
2026-10-15 01:01:54 -04:00

10 KiB

Les mécanismes transverses

Pour qui : le mainteneur — celui qui va modifier le moteur. À lire avant d'ajouter quoi que ce soit : ces mécanismes vivent dans le code et les README de rôles, et on les re-découvre sinon. Le survol est dans docs/architecture.md ; l'index des documents dans docs/README.md.

Les mécanismes transverses, et où ils vivent

Ce que je re-découvre sinon. Consulter avant de concevoir un nouveau mécanisme.

Mécanisme Ce que c'est Où, dans le code Doc
Plan → inventaire plan/*.yml → hosts.yml généré scripts/instancier.py, scripts/inventory_rules.py plan-et-generation.md
Schéma des registres la forme des six registres — champs, types, énumérations, requis — dérivée des validateurs, jamais écrite à la main. Sert à générer les formulaires plutôt qu'à les écrire. La cohérence reste aux valider_* : un schéma ne sait pas dire qu'un consommateur désigne une application inexistante scripts/schema_plan.py (make schema) → docs/audit/schema-plan.json ; garde P61 plan-et-generation.md
Nomenclature dérivée VMID / IP / VLAN / FQDN dérivés inventory_rules.deriver_nomenclature + plan/nomenclature.yml nomenclature-vm.md
Dimensionnement RAM/CPU/disque sommés par logiciel roles/*/meta/empreinte.yml → deriver_ressources dimensionnement-ressources.md
Bindings app→app lien côté app (liens) résolu en host_vars plan/applications.yml liens: + roles/*/meta/liens.yml + instancier.resoudre_liens bindings-conception.md
Bindings app→base lien côté base (consommateur/portee) résolu dans le rôle plan/bases-donnees.yml + rôle utilitaire resoudre_base (lookup('vars', secret), no_log) inclus par le consommateur bindings-conception.md §5
Résolution d'annuaire connexion LDAP (uri/base DN/bind) dérivée, jamais recopiée rôle utilitaire resoudre_annuaire (inclus par dovecot/postfix/keycloak/icingaweb2 et amorcage_acces) identite-sso.md
Plancher de résolution /etc/hosts généré depuis l'inventaire + alias d'expose → l'écosystème se résout DNS éteint rôle hosts_statiques (appliqué dans la couche socle) dns-interne.md
Pont de certificat cert step_ca → service, resync au renouvellement script *-cert-sync + unité .path, dans chaque rôle serveur ; cert déposé par client_pki —
Ordonnancement socle-first socle/durci avant les client_* serveur_debian/serveur_durci d'abord (posent /etc/hosts via hosts_statiques) —
Sûreté check-mode dry-run fiable when: not ansible_check_mode sur les tâches de service + handlers —
Voûte au déploiement secret jamais en clair ; une voûte, une clé depuis le 2026-08-28 ANSIBLE_VAULT_IDENTITY_LIST construit par scripts/voutes.py (clé nommée ~/.config/setops-vault-<dépôt>) ; déréférencé par lookup('vars', <nom>) autorisation.md §6.1
Multi-instance un dépôt par écosystème ; l'active = symlink instance/, les autres découvertes par convention (dossiers frères, aucun registre) active : symlink instance/ ; découverte : scripts/instances.py / devis_reseau.py (glob ../*/plan/nomenclature.yml avec index) ; garde-fou collision : preuve P21 multi-instances.md
Exposition → edge app expose un FQDN public servi par un edge plan/domaines.yml + expose (applications) bindings-conception.md §4
Exploitation de l'hébergeur ses opérations n'appartiennent à aucun tenant et restent hors overlay à moitié construit : les VM du site ont leur inventaire (scripts/site_inventaire.py), leur socle, leur durcissement, leurs sauvegardes et leur supervision (site-mon-01, 2026-09-02). Les équipements : hyperviseurs et frontière supervisés depuis le 2026-09-17 — températures, ventilateurs, SMART, usure NVMe, un catalogue (scripts/materiel.py) lu par le tableau Grafana « Matériel » et le service Icinga materiel (supervision-conception.md). Les commutateurs restent sans supervision ; aucun équipement n'a de sauvegarde de configuration hebergeur-exploitation.md
Authentification web → Keycloak ; LDAP source unique ; secours par sudo, formulaire local non annoncé <rôle>_connexion_locale: false (grafana, forgejo, nextcloud) ; garde de version Forgejo ≥ 10 authentification.md
Accès & habilitations Set-OPS amorce un accès sysadmin puis se retire ; les appartenances aux groupes ne sont jamais réconciliées — c'est une personne qui gouverne construit et éprouvé (2026-08-08) : rôle amorcage_acces (idempotence par existence, D-67), groupes projetés en rôles par serveur_keycloak, meta/acces.yml dans les 5 rôles web ; chaîne LDAP → Keycloak → groupe → service exercée de bout en bout sur Icinga Web 2 autorisation.md (§6 = runbook de reprise)
DNS public le locataire écrit ses zones autorite: primaire-cache, le site les sert en secondaire, un site pair les réplique. Transfert ouvert à la clé TSIG seule (allow-axfr-ips et TSIG sont alternatifs dans PowerDNS) ; instance pdns@public à part pour que le site ne puisse jamais interroger la zone .internal roles/serveur_dns_public/, roles/serveur_powerdns/tasks/zones-publiques.yml ; relations dérivées dans scripts/site_inventaire.py ; mots de flux dns_public_site / primaires_dns_locataires ; garde P82 dns-interne.md §Zones publiques
Remise au client remettre un écosystème se fait en deux temps : l'identité le jour de la livraison (sa clé de voûte, sa voûte, sa racine d'AC), la machine à l'échéance (sa clé SSH entre, la nôtre sort, la voûte est re-clétée). Le registre déclare enfin le responsable désigné (D-18) scripts/remise.py (make remise-paquet, remise-inscrire, remise-recleer) ; registre remise.yml chez le locataire ; garde P80 remise-au-client.md
SDN EVPN ajouter un tenant implique 1 zone + 6 VNets + 6 sous-réseaux, tous dérivés du seed scripts/devis_sdn.py (make devis-sdn) ; nommage dérivé du seed (t17, t17serv), ≤ 8 caractères ; garde P30 sdn-evpn.md §2
Pools Proxmox un pool par tenant : les noms courts de VM sont volontairement identiques d'un tenant à l'autre (même fonction, même nom), et seule la console Proxmox en souffrait scripts/devis_proxmox_pools.py (make devis-proxmox-pools) ; nom dérivé de l'index ; garde de collision = preuve P28 decisions-architecture.md D-37
Routage aucun commutateur ne route : la frontière est le seul équipement L3 ; les switches commutent passerelle dit qui porte la passerelle, le SVI se dérive du rôle du porteur decisions-architecture.md D-49/50
Devis de service LIT le système en marche et le compare à ce que le plan dérive ; n'écrit rien (D-23/D-24 portés du réseau aux services). Le playbook relève, Python compare playbooks/maintenance/devis-*.yml + scripts/devis_*.py ; cible make <sujet>-plan devis-services.md
Accès d'administration un tunnel WireGuard nominatif (instance admins) : un pair par personne et par appareil, le réseau du tunnel devient un réseau d'administration dont les pare-feux d'hôte, le contrat vers les locataires et les règles de bordure dérivent. Le runner n'est pas le rebond, et le document dit pourquoi scripts/vpn_admin.py (make vpn-admin-plan) ; déclaré dans acces_admin_vpn (plan du site) acces-administration.md
Frontière nord/sud les flux pair: externe — sautés par le pare-feu d'hôte — sont la politique de bordure scripts/devis_opnsense.py (make devis-opnsense) ; garde d'accès admin = preuve P24 frontiere-opnsense.md

⚠️ Deux directions de binding, assumées : app→app côté app (instancier), app→base côté base (registre, résolu en rôle pour que le secret ne quitte jamais le rôle). Ne pas unifier l'un dans l'autre sans raison. Cf. bindings-conception.md.

Maturité et dette

  • Maturité des rôles, échafaudages, rôles-catégories inertes : voir docs/projet/catalogue-services.md « État d'implémentation » (source de vérité, tenue à jour).
  • Dette (audit 2026-07-03, revu le 2026-07-29) :
    • ✅ soldé — README de rôles : tous les rôles en ont un (les 12 manquants écrits le 2026-07-29 : serveur_debian, hosts_statiques, resoudre_base, resoudre_annuaire, serveur_dovecot, serveur_postfix, serveur_rspamd, client_backup, serveur_backup, client_resolveur, serveur_oauth2_proxy, serveur_icingaweb2).
    • ✅ soldé — expose est consommé au déploiement : plan/applications.yml → filtre expositions_des_applications → vhosts nginx dérivés (roles/serveur_nginx/tasks/main.yml, template expositions.conf.j2, drapeau serveur_nginx_publier_expositions), + alias /etc/hosts posés par hosts_statiques,
      • SANs des certificats d'edge dérivés par scripts/instancier.py.
    • ⏳ ouvert — meta/liens.yml seulement sur serveur_postfix (mailstore, milter) : les autres liens app→app viendront.
    • ⏳ ouvert — requiert : câblé côté GUI (édition + validation valider_applications) mais pas consommé au déploiement ; c'est un indice de dépendance applicative. Les dépendances de groupes (celles qui pilotent l'ordre) vivent dans docs/dependances-groupes.yml + docs/couches-deploiement.yml, et sont bel et bien consommées par l'orchestrateur (scripts/orchestrer.py → playbooks/site.yml).

Discipline

Avant de concevoir ou d'ajouter un mécanisme :

  1. lire cette page, l'index (docs/README.md) et le document du sujet ;
  2. arpenter le code (grep) et lire les README des rôles concernés ;
  3. éprouver l'outil AVANT d'écrire le rôle qui l'enveloppe — une machine jetable hors plan se fabrique en deux minutes (make cloner-vm, cf. vm-lifecycle.md §4bis). C'est ce qui a évité les bugs de premier déploiement de rspamd, et ce qui a tranché le pivot Stalwart → Postfix/Dovecot. Elle est invisible au moteur : à détruire à la main ;
  4. étendre / factoriser l'existant plutôt qu'ajouter un chemin parallèle.

Un seul agent IA travaille dans le dépôt à la fois (Codex ou Claude) — cf. AGENTS.md.