Commit graph

90 commits

Author SHA1 Message Date
69536a2b1a openldap : charge ppolicy — le jeton d'amorcage devient a usage unique
Le module etait sur disque mais jamais charge (seul back_mdb l'etait). Depuis
OpenLDAP 2.5 son schema est INTEGRE au module : aucun .ldif a charger.

La contrainte mord, mesuree sur un compte fraichement amorce :

  Insufficient access (50)
  Operations are restricted to bind/unbind/abandon/StartTLS/modify password

Le sysadmin peut se connecter et RIEN d'autre que changer son mot de passe. Ce
que la doctrine promettait est garanti techniquement, plus seulement demande.

`pwdMustChange` est ce qui donne son effet a `pwdReset` : sans lui, marquer une
entree n'oblige a rien. La politique apporte aussi longueur minimale 12,
verrouillage apres 5 echecs, historique. `olcPPolicyUseLockout` reste FALSE :
annoncer « compte verrouille » renseignerait un attaquant sur son existence.

Le DN de la base est LU, pas suppose : olcDatabase={1}mdb est l'usage mais
l'index n'est pas garanti.

La detection du role d'amorcage s'est verifiee d'elle-meme : rejoue apres le
chargement, il annonce « Changement FORCE » la ou il disait l'inverse une heure
plus tot.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-07 13:52:00 -04:00
ba70b80197 amorcage_acces : le role qui cree UN acces puis se retire
Cree uid=sysadmin et cn=sysadmin dans LDAP. Prouve sur idm-01 : le compte
s'authentifie, et le second passage ne touche a rien (changed=0, 7 taches
sautees) — idempotence par EXISTENCE, pas par conformite (D-67).

Il suit l'annuaire au lieu de se declarer au plan : il ecrit par `ldapi:///` et
doit tourner sur cet hote. Le declarer comme groupe obligerait chaque instance a
le poser sur le bon hote, et elles ne le nomment pas pareil (idm-01 ici,
id-ldap-01 chez Technolibre) — je l'ai d'abord pose sur infra-pki-01 par erreur.

Trois defauts trouves en le construisant :

1. `pwdReset` n'existe pas dans ce schema (overlay ppolicy non charge) :
   l'entree entiere etait rejetee et `no_log` masquait la cause. J'avais suppose
   un mecanisme sans verifier. Le role le DETECTE maintenant, et la doctrine ne
   promet plus un changement force qui n'a pas lieu.

2. Le mot de passe aurait ete stocke EN CLAIR : `ldap_entry` ecrit userPassword
   litteralement. Hache par `slappasswd -h {SSHA}` desormais.

3. `voute.py` ne scannait que roles/<groupe> : un role applique par un playbook
   sans etre un groupe echappait au recensement, ce que D-20 interdit. Il suit
   maintenant les listes `roles:` des playbooks.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-07 13:42:27 -04:00
8260f2f914 annuaire : l'hote se derive du plan, il ne s'ecrit plus
`resoudre_annuaire` fixait `id-ldap-01` en dur — une machine qui n'existe dans
aucun plan. Postfix ne pouvait pas se lier : « Can't contact LDAP server ».

L'intention etait juste et son commentaire le disait : un seul point ou le nom
est fixe, au lieu d'etre repete dans chaque role. Mais ECRIT au lieu d'etre
derive. Une valeur unique et fausse vaut mieux qu'une valeur repetee et fausse ;
elle reste fausse.

Le plan le declare (`applications.openldap.hote`) : c'est de la qu'elle vient.

infra-mail-01 et edge-mta-01 deployees, 19 playbooks sans un echec. LMTP en TLS
verifie, mynetworks sur le supernet derive, liaison LDAP etablie vers idm-01.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-07 12:46:48 -04:00
249fba702a sso : l'issuer et le nom d'hote se derivent de l'exposition declaree
oauth2-proxy fonctionne devant Icinga Web 2 : 302 vers Keycloak, qui federe
LDAP. Quatre defauts leves, dont trois du meme motif — un nom construit par
convention d'un cote, declare de l'autre.

1. Le secret de cookie etait en base64 STANDARD. oauth2-proxy decode en
   url-safe : le decodage echoue, il retombe sur la chaine brute et se plaint de
   sa LONGUEUR, jamais de l'encodage. Garde ajoutee qui refuse + et /.

2. L'issuer etait fabrique (`keycloak.<domaine>`), un nom que rien ne publie.
   Le plan expose `auth.<domaine>` — c'est ce nom que le DNS resout et que nginx
   sert. Derive desormais du champ `expose`.

3. Keycloak s'annoncait sous ce meme nom invente : « issuer did not match ».
   Meme correctif a la source.

4. Le pare-feu est-ouest bloquait l'edge : nginx ne declarait son 443 qu'avec
   `pair: externe`, que le devis est-ouest saute (il releve de la frontiere).
   Le flux existait d'un seul cote et la matrice etait satisfaite. nginx declare
   maintenant aussi son 443 depuis la flotte.

obs-01 et mon-01 deployees. 7 cibles Prometheus up, scrutees en TLS a travers
cinq zones du VRF.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-07 11:47:34 -04:00
41413c7f04 deploiement : deux attentes de premier demarrage, et trois defauts leves
`idm-01` a prouve le routage inter-zone dans le VRF (10.27.19.21 -> 10.27.17.11,
deux passerelles anycast) et leve trois defauts qu'aucun devis ne pouvait
montrer :

1. Le handler de `client_pki` rechargeait `slapd` avant son installation —
   consequence directe de l'ordre retabli. Un consommateur absent n'est pas une
   erreur ; un vrai echec de rechargement reste fatal.

2. `resoudre_base` ne trouvait aucune base de portee `application` : Keycloak
   declare `consommateur: keycloak`, le role cherchait `serveur_keycloak`. Le
   lien est declare dans applications.yml — on le suit au lieu de retirer un
   prefixe a la main.

3. Keycloak attend PostgreSQL, pas encore deploye. Pas un defaut : `deployer`
   ne connait que l'ordre intra-hote, l'ordre inter-hotes est celui de `site`.

Et deux attentes, sans lesquelles on ne peut pas enchainer creation et
deploiement — donc sans lesquelles `myDay` ne reconstruit pas seul : SSH, puis
cloud-init et les maj automatiques. `creer-vm` rend desormais une VM PRETE.
`lock_timeout: 300` sur chaque tache apt complete l'attente : le verrou peut
etre repris ENTRE deux taches, ce qu'une verification en amont ne previent pas.

Defaut dans l'attente elle-meme : `unattended-upgrades` est un demon, toujours
actif — l'inclure rendait la condition impossible a satisfaire.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-07 09:30:48 -04:00
f18715bc78 deployer : l'ordre des couches, et l'autorite qui se signe elle-meme
`make deployer` triait les groupes alphabetiquement apres le socle :
`client_metrique` passait avant `serveur_step_ca`, donc exigeait un certificat
que l'autorite, pas encore deployee, ne pouvait pas avoir emis — sur l'hote de
l'AC lui-meme. `docs/couches-deploiement.yml` existe pour definir cet ordre et
dit « integrations deployees en dernier » ; `make site` le lit, `deployer` ne
l'avait jamais lu. Meme registre desormais.

Deux politiques universelles se contredisaient : `client_pki` exemptait l'AC,
`client_metrique` refuse toute exemption. L'exemption confondait « ne pas
s'enroler » et « ne pas avoir de certificat ». `client_pki` distingue les deux
chemins : bootstrap pour les autres, EMISSION LOCALE sur l'AC. L'exemption
disparait, la doctrine reste.

Effet de bord instructif : `step ca bootstrap` ecrit aussi le defaults.json qui
porte l'URL de l'AC. En sautant le bootstrap on perdait l'information sans le
voir. `--ca-url` et `--root` sont explicites pour tous les hotes.

Mesure : infra-pki-01 et infra-dns-01 entierement deployees, aucun echec,
step-ca health=ok, powerdns resout la zone souveraine, et les deux hotes portent
un certificat de l'AC interne.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-06 23:57:01 -04:00
e276e76f32 dns : client_unbound universel, et un resolveur d'amorcage
Une VM ne peut pas s'installer sans resoudre des noms. PowerDNS repond
UNIQUEMENT pour la zone souveraine et ne recurse pour personne : il manquait un
resolveur recursif. `client_unbound` est l'outil ecrit pour ca — il rejoint
`client_journal` et `client_metrique` parmi les integrations universelles.

`infra-dns-01` est exempte (PowerDNS occupe son port 53), et
`serveur_powerdns_listen_addresses` passe de 0.0.0.0 a l'adresse de l'hote pour
laisser 127.0.0.1:53 libre. Mais l'appartenance au groupe est AUSSI ce qui ouvre
le port 53 a la frontiere : en exemptant la machine, je lui retirais le droit de
resoudre. `serveur_powerdns` declare donc son propre flux sortant — il ne
recurse pour personne, mais doit resoudre pour lui-meme.

Nouvel intrant `dns_amorcage`, derive jusqu'a `make creer-vm`. Cloud-init
l'ecrit bien mais sans effet : `dns-nameservers` exige `resolvconf`, absent du
gabarit, et installer resolvconf demande apt, qui demande la resolution.
`serveur_debian` pose donc le resolveur en pre_tasks, avant le premier apt, avec
une garde qui respecte la bascule ulterieure de client_unbound.

Defaut corrige en chemin : `_intrants_communs()` lisait `instance/` en dur ; le
chemin derive maintenant de l'inventaire recu, et un test le prouve.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-06 21:41:58 -04:00
22ef279464 authentification : chaque rôle déclare sa position, gardé par P29
Une règle qu'aucune garde ne vérifie finit par ne plus être vraie — c'est ce qui
était arrivé aux 28 lignes d'intégration recopiées. Chaque rôle serveur_* porte
un meta/authentification.yml, confronté à son code par P29.

web-sso 5, socle-identite 2 (keycloak/openldap : ils SONT la chaîne d'identité),
ldap-direct 2, interne-sans-auth 2, sans-auth-humaine 12.

La preuve refuse l'oubli ET le mensonge. Éprouvée par sabotage sur sept cas :
déclaration supprimée, portée inventée, secours retiré, posture de formulaire
retirée, raison retirée, ldap-direct mensonger, réglage retiré des defaults.

Les deux derniers passaient dans la première version :

- le mensonge passait à cause d'un commentaire. Je cherchais le mot « ldap » dans
  le rôle, et serveur_grafana/defaults/main.yml contient « désactiver quelqu'un
  dans LDAP » : de la prose validait une déclaration fausse. La preuve exige
  maintenant un indice nommé — variable <rôle>_oidc / <rôle>_ldap, ou URI ldap://
- le réglage retiré passait parce que le gabarit citait encore la variable alors
  que plus rien ne lui donnait de valeur. La preuve lit defaults/main.yml en YAML
  et exige que la clé y soit définie, pas mentionnée.

Elle a aussi forcé une valeur : oauth2-proxy était déclaré « formulaire local
fermé » alors qu'il n'a aucun compte local. D'où formulaire_local: aucun, qui
distingue « il n'y en a jamais eu » de « il y en a un, il est fermé ».

Correction d'une note de la veille : Prometheus et Loki ne sont PAS exposés
publiquement (aucun expose au plan). Seuls six groupes le sont. Le risque est
intra-tenant, pas frontalier. Les deux lacunes sont comptées à chaque exécution,
pas masquées.

AFF-111, D-42. 29 preuves OK, ansible-lint (production) sur 375 fichiers.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-03 17:05:43 -04:00
6a62f0a4c7 authentification : SSO Keycloak devant, secours par sudo, formulaire local fermé
Directive : toute authentification web passe par Keycloak, LDAP est la source
unique des comptes, chaque service garde un accès de secours par sudo sur
l'hôte. Les trois sont indissociables — la chaîne service → Keycloak → LDAP est
en série, donc sans secours une panne exclut tout le monde, y compris pour
réparer. Portée : le web seulement ; IMAP/SMTP se lient à LDAP directement et
SSH est en clé seule.

Posture <rôle>_connexion_locale, false par défaut. Le compte local existe — il
ne peut pas dépendre de Keycloak — mais son formulaire n'est plus proposé au
repos : ouvert en permanence, il contourne la politique de mot de passe, le MFA
et surtout la révocation centrale.

Vérifié auprès de l'amont, puis par rendu réel des gabarits dans les deux
postures :
- Grafana  GF_AUTH_DISABLE_LOGIN_FORM  → ferme ;
- Forgejo  ENABLE_INTERNAL_SIGNIN + ENABLE_BASIC_AUTHENTICATION → ferme, API
  Basic comprise. N'existe que depuis la v10 (ticket amont 7476) ; le rôle
  épingle 10.0.0 et un assert refuse la fermeture en deçà, car le réglage serait
  ignoré sans erreur ;
- Nextcloud hide_login_form → MASQUE seulement : ?direct=1 reste le chemin de
  secours documenté par l'amont. Écrit comme tel, sans prétendre à l'équivalence.

Défaut attrapé par le rendu : la condition Forgejo sans `| bool` n'émettait rien
dans aucune posture — une valeur en chaîne est vraie au sens Jinja, la connexion
locale serait restée ouverte en silence.

docs/authentification.md, décisions D-38 à D-41. ansible-lint (production) sans
échec, 28 preuves OK.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-03 16:50:36 -04:00
b0e56cbfc0 intégrations : le rôle déclare sa politique ; le cluster passe à l'hébergeur
Deux corrections de propriété, l'une dans le plan, l'autre dans les intrants.

1. Intégrations universelles (D-33/D-34, P26)

Le plan portait 57 lignes d'intégration écrites à la main, dont 28 disaient oui à
quelque chose de vrai pour tous les hôtes. Elles n'existaient que pour être
oubliées — et elles l'avaient été : dans Chezlepro, backup-01 et infra-pki-01
n'étaient ni supervisés, ni journalisés, ni certifiés.

Le rôle déclare désormais sa politique une fois, dans meta/integration.yml ; le
plan ne garde que les vrais choix et refuse la recopie. Les exemptions se
dérivent du service rendu (sauf_role), jamais d'un nom d'hôte : l'AC ne s'enrôle
pas auprès d'elle-même, et l'exemption suit step-ca si on le déplace.

Une seule fonction de résolution — integrations_de() — lue par l'inventaire, la
voûte et le panneau. Sans le passage par la voûte, les secrets des intégrations
universelles auraient cessé d'être exigés et P18 serait passé au vert sur une
voûte incomplète.

Vérifié : diff vide sur Technolibre (la politique reproduit exactement les 41
lignes retirées) ; sur Chezlepro, exactement les groupes manquants, et pas
client_pki sur infra-pki-01.

2. Vue Intégrations : la matrice

La fiche montrait les intégrations d'UN serveur ; le trou de Chezlepro n'a pas
été trouvé par le panneau mais par le devis de pare-feu. Matrice serveurs x
intégrations : colonnes de politique en lecture seule, facultatives cochables sur
place, ligne de couverture n/N qui rend le motif visible sans le juger.

3. Propriété des intrants (D-35/D-36, P27)

Le cluster Proxmox appartient à l'hébergeur, comme sa fabric et sa frontière.
Recopié chez chaque tenant, son inventaire avait déjà divergé : deux listes de
stockages contradictoires pour le même matériel. API/nœuds/stockages/ponts vont
dans proxmox-hebergeur.yml, à côté d'underlay.yml, dont le chemin se dérive —
l'hébergeur reste non déclaré (D-17). Restent au tenant son golden template et
ses défauts de placement.

Le panneau nomme désormais le propriétaire de chaque section : éditer une section
« hébergeur » vaut pour tous ses tenants, et l'écran ne le disait pas.

26 preuves OK, 0 échec. --syntax-check des deux playbooks Proxmox.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-03 14:09:22 -04:00
70fe6de557 flux : l'ICMP entre au registre — l'overlay à 1450 l'exige
Décision : l'overlay EVPN plafonne à 1450. Conséquence invisible : sous 1500,
tout ce qui traverse la frontière dépend de la découverte de MTU de chemin,
donc de l'ICMP « fragmentation nécessaire ».

Or le registre ne connaissait que TCP et UDP. Ce message ne pouvait pas être
déclaré et la bordure en `block in log all` l'aurait jeté : la connexion
s'établit, les petites requêtes passent, les grosses réponses restent
suspendues — la panne la plus coûteuse à diagnostiquer, et celle qu'on impute
d'abord à l'application.

`protocole: icmp` est admis ; le champ `port` y porte le type
(`frag-needed`). Le socle déclare les deux sens. Vérifié : nftables d'hôte
inchangés, le pair `externe` reste sauté.

Reconnaissance (lecture seule) : l'EVPN est à moitié construit — contrôleur
EVPN0017 (ASN 65000), zones VRF0011 et VRF0017, un VRF par tenant avec le VNI
égal à l'index. Aucun VNet, aucun nœud de sortie.

Signalé et non corrigé : les pairs BGP sont dans 10.27.19.0/24, le
sous-réseau Services-infra de Chezlepro. Le transport du cluster dérive de
l'index d'un tenant, et une VM de cette zone partage son sous-réseau avec les
VTEP — l'isolation est percée à l'endroit que l'EVPN devait fermer.

Preuves : 24 OK, 0 échec.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-03 10:07:30 -04:00
4d37570c0c frontière : la sortie générale est déclarée, pas subie
Le devis se terminait par `block out log all` avec une seule règle sortante
(le relais SMTP). Appliqué tel quel, il coupait la flotte d'Internet : plus
d'apt, plus de NTP, plus de récursion DNS. Rien ne le signalait — la ligne
la plus lourde de conséquences du devis, posée à la suite des autres.

La sortie est déclarée dans le registre, donc dérivée :
- `serveur_debian` (socle, 14 hôtes) : 443 et 80 pour les dépôts apt, 123/udp
  pour l'horloge — une dérive fait échouer step-ca et le SSO des semaines
  après la cause ;
- `client_unbound` : 53 udp et tcp, la récursion depuis la racine qu'implique
  `client_unbound_transitaires: []`. Le TCP est le repli obligatoire dès
  qu'une réponse DNSSEC dépasse la taille UDP.

Le devis passe de 6 à 11 règles, et sa section 5 énonce le default-deny
sortant, le nombre de règles qui l'accompagnent, et où déclarer un besoin
oublié — jamais à la main dans le pare-feu.

Vérifié : les nftables d'hôte sont inchangés, octet pour octet. Le pair
`externe` reste sauté par resoudre_flux.

Non déclaré volontairement : le rôle `chrony` n'est référencé par aucun
groupe ni playbook — un flux pour lui aurait été une règle morte.

Preuves : 24 OK, 0 échec.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-02 13:10:45 -04:00
7dc7720b4b client_pki : l'empreinte du root CA n'est pas un secret de voûte
Le rôle dérive l'empreinte à chaud depuis l'autorité, parce qu'un from-zero
régénère l'AC avec une empreinte neuve. Figée en voûte, elle serait périmée
dès la première reconstruction — et une empreinte périmée fait échouer le
bootstrap de chaque hôte.

Or `defaults/main.yml` portait encore un défaut lisant
`vault_step_ca_fingerprint`. Ce défaut était mort : la tâche suivante écrase
le fait sans condition, donc la valeur de la voûte n'avait aucun effet.

Le recensement de voute.py s'y laissait prendre — il cherche la chaîne
`vault_*` sans pouvoir savoir qu'un défaut n'est jamais lu. La « source
unique » avait hérité de l'erreur, et le panneau réclamait un secret
impossible à fournir avant que l'AC n'existe.

Défaut retiré : la clé disparaît du recensement (25 -> 24 exigés), du
gabarit et du panneau. `client_pki_ca_fingerprint_override` reste le moyen
d'épingler une empreinte.

`docs/intrants-communs.md` §H était une troisième copie manuelle de la liste
des secrets, avec les deux mêmes erreurs ; elle renvoie maintenant à
`voute.py lister` et à la preuve P18.

Preuves : 24 OK, 0 échec ; voute.py verifier --strict passe.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-01 22:37:27 -04:00
4a1d0836d0 docs : un README par rôle (12 manquants) + carte remise à l'état du code
Solde la dette documentaire repérée à l'audit du 2026-07-03. Tous les rôles ont
désormais un README, au format maison (intention → rôle → variables →
notes/limites → prérequis). Ils documentent ce qui ne se lit PAS dans les tâches :

- serveur_debian : rôle-catégorie sans tâches — il ne porte que le flux SSH du
  plan de gestion, sans quoi les nftables générés couperaient l'accès Ansible à
  toute la flotte ; le vrai travail est dans le playbook de groupe.
- hosts_statiques : le plancher /etc/hosts comme CONDITION de l'ordre de
  reconstruction (résolution par nom avant que PowerDNS existe) ; fichier
  entièrement géré, alias d'exposition best-effort.
- resoudre_base / resoudre_annuaire : entrées, sorties (facts), et pourquoi le
  FQDN plutôt que le nom court (fédération + nom canonique pour verify-full).
- serveur_dovecot : les 3 réglages Dovecot 2.4 qui conditionnent la remise
  (static_allow_all_users, mail_inbox_path vide, mail_path par utilisateur) et
  le local-part seul comme chemin commun LMTP/IMAP ; limite mono-domaine.
- serveur_postfix : liens mailstore/milter, recopie de /etc/hosts dans le chroot.
- serveur_rspamd : clé DKIM idempotente ; le domaine signé doit être PUBLIC en
  prod, sinon la signature ne vaut rien pour les MX distants.
- client_backup / serveur_backup : jobs déclaratifs, chiffrement côté client,
  deux pièges (jobs vides = silencieux ; dépôt neuf vide après un from-zero) ;
  hors-nœud n'est pas hors-site.
- serveur_oauth2_proxy : le patron réutilisable Keycloak-devant-n'importe-quoi,
  et pourquoi allow_unverified_email est nécessaire avec un annuaire LDAP.
- serveur_icingaweb2 : modes ldap vs external, écoute à restreindre en SSO.
- client_unbound : le garde-fou de bascule (apply ET confirm, validation réelle
  avant de toucher /etc/resolv.conf).

docs/carte-set-ops.md ne décrivait plus l'état du code :
- expose EST consommé au déploiement (annoncé comme « Phase 3 à venir ») :
  expositions_des_applications + expositions.conf.j2, alias /etc/hosts, SANs
  d'edge dérivés par instancier.py ;
- 3 mécanismes transverses ajoutés (résolution d'annuaire, plancher de
  résolution, resoudre_base nommé dans les bindings app→base) ;
- 5 entrées d'index ajoutées : réseau/pare-feu, ordre de déploiement,
  preuve/recette, exploitation courante, wiki — pans du corpus non indexés ;
- ce qui reste ouvert est marqué : meta/liens.yml sur le seul serveur_postfix,
  requiert non consommé au déploiement (l'ordre vient des couches + du graphe).

make verifier vert : ansible-lint 514 fichiers, tests, syntax-check,
23 preuves CONFORME / 0 échec / 0 sauté.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-29 11:32:06 -04:00
131a30075d Aurore : opacites reduites ; etat de forge-01 elucide
Palette (promo/, les 4 pages) — les teintes rose, verte et violette etaient
trop presentes une fois etalees au tour precedent. Reduction d'environ 40 % :
rose .075 -> .044, vert .058 -> .034, violet .062 -> .036, arrets
intermediaires abaisses dans la meme proportion, opacite de la nappe .aurora
.44 -> .32. Geometrie inchangee : meme largeur, meme position, seule
l'intensite baisse. 0 conflit CSS entre les quatre pages.

forge-01 — la note precedente presentait comme une contradiction a trancher
le fait que le plan dise `etat: planifie` et que le CHANGELOG du 2026-07-03
dise le branding « prouve sur forge-01 ». Ce n'en etait pas une : l'hote a ete
cree, puis supprime. Le plan decrit l'etat COURANT, le CHANGELOG un etat PASSE
— les deux disent vrai. La preuve reste valable, simplement non rejouable tant
que l'hote n'est pas recree. roles/serveur_forgejo/README.md corrige.

Valide : equilibre accolades/parentheses du CSS, 0 conflit CSS,
prouver.py --verifier -> CONFORME 16/16.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-22 11:57:50 -04:00
f8e754c0b0 Aurore rose-mauve et vert fluo ; thème Forgejo étendu au wiki
Palette (promo/, les 4 pages) — ajoute --rose:#ff6fc4 (frange magenta) et
--vert:#5cff9d (vert fluo), uniquement dans les DÉGRADÉS FONCÉS : fond fixe du
corps, nappe .aurora dérivante, filets .rule. Opacités de 5,5 % à 8,5 %, une
teinte et non un motif. Le vert entre par la gauche et le rose sort par la
droite, comme une vraie aurore. --aurora (texte et boutons) est inchangé :
l'identité de marque ne bouge pas. Appliqué identiquement aux quatre fichiers,
0 conflit CSS après coup.

Thème Forgejo (alliance.css, 29 → 118 lignes) — la feuille étant injectée par
templates/custom/header.tmpl sur toutes les pages, le wiki est couvert sans
feuille distincte. Réorganisée en deux sections de risque explicite :
  §1 Variables — couleurs officielles + ciel nocturne. Sûr, résiste aux
     mises à jour. ÉPROUVÉ sur forge-01 (CHANGELOG 2026-07-03).
  §2 Décor — fond aurore, filet sous les titres, citations, tableaux et code
     en ligne de .markup. Fragile (classes internes). JAMAIS RENDU.
Supprimer §2 ramène au thème sobre. Le ciel nocturne ne s'applique qu'aux
thèmes sombres, pour ne pas casser le thème clair.

docs/theme-forgejo-hors-flotte.md — pose manuelle sur une instance Forgejo non
gérée par Set-OPS (la forge historique qui héberge ce dépôt et son wiki).
Forgejo n'ayant aucun réglage web pour le CSS, il faut déposer la feuille sur
le serveur. La procédure ne duplique aucun fichier : elle pointe vers ceux du
rôle. Inclut la détection du répertoire custom, un garde-fou pour ne pas
écraser un header.tmpl existant (ajout de ligne), la vérification curl et la
marche arrière.

Corrige deux affirmations fausses de ma part :
- « thème jamais rendu par un Forgejo réel » était faux pour §1, éprouvée.
  Le statut est désormais donné section par section.
- Contradiction consignée sur forge-01 : le plan la dit `etat: planifie`, le
  CHANGELOG 2026-07-03 dit le branding « prouvé sur forge-01 ». Les deux ne
  peuvent pas être vrais ; l'écart est écrit dans le README du rôle, à trancher.

Validé : équilibre accolades/parenthèses du CSS, 0 conflit CSS entre les quatre
pages, lien de doc résolu, ansible-lint 0 échec sur 485 fichiers,
prouver.py --verifier → CONFORME 16/16.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-21 17:42:52 -04:00
72a5fdbbc4 Portabilité from-zero : 4 correctifs débusqués par la reconstruction
Reconstruction complète prouvée (14 VM + sauvegardes + AC supprimées, puis
`make myDay` rebâtit tout ; `make valider` entièrement vert). Bugs corrigés :

- client_pki : empreinte du root CA dérivée dynamiquement de l'autorité
  (au lieu d'une valeur figée en Vault) — une AC régénérée a une empreinte neuve.
- serveur_keycloak : assignation de rôle tolérante aux utilisateurs absents
  (annuaire vide sur un from-zero).
- serveur_prometheus : ne scrute que les hôtes ACTIFS (client_metrique ∩ hotes_actifs).
- nftables résolu : compatible Docker — remplace la seule table setops_flux (pas de
  flush ruleset, préserve les tables Docker) + forward autorise docker0/established.
  Sans ça, forward policy drop coupait Collabora (conteneur).

Ajoute playbooks/proxmox/supprimer_vm_debian.yml (suppression par VMID, garde-fous).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-07 06:45:12 -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
af13fc37c9 Rôles web : renommer web_frontal/dorsal -> serveur_web_frontal/dorsal (convention)
Aligne sur la convention serveur_* de tous les rôles de service (vars incluses).
Le modèle presence-web (pré-existant) utilisait déjà ces noms -> il colle enfin.
Aussi : serveur_web_dorsal ne chown plus le code (reste root, lecture seule pour
l'app = plus sûr + git idempotent, fini le 'propriété douteuse' au pull).
Idempotence prouvée (2e passage changed=0). lint production.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-05 18:49:31 -04:00
c8ccbb5e97 client_pki : ré-émettre le cert sur dérive de SAN (fin du rm manuel)
Le garde 'creates:' sautait la ré-émission même quand les SAN voulus changeaient
(ex: nouvelle exposition -> client_pki_sans mis à jour). Contourné 3× à la main ce
soir. Corrigé : on lit les SAN du cert existant (openssl) et on ré-émet si le cert
est absent OU si un SAN voulu manque, puis on recharge les consommateurs
(client_pki_reload_services). Idempotent (SAN à jour -> sauté) + dérive détectée,
prouvés. ansible-lint production : 0.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-05 18:43:23 -04:00
eee7dbd108 web_dorsal : rôle webapps dynamiques (2e brique plateforme, 100% natif)
Runtime (venv/paquets) + service systemd + nginx local, derrière l'edge, ZÉRO
conteneur. Chaque app : git clone (depth 1) → venv + pip → unité systemd durcie
(app en localhost, user webapp, NoNewPrivileges/PrivateTmp) → vhost nginx local
qui la fronte. data_dir persistant pour l'état local (SQLite) ; BD réseau via
resoudre_base sinon.

Éprouvé bout-en-bout sur web-frontal-01 par le rôle : monregistraire (FastAPI+
uvicorn+SQLite) cloné de Forgejo, servi via l'edge en HTTPS step-ca, API OK.
Avec web_frontal, la plateforme webapp native est complète. lint production: 0.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-05 18:37:47 -04:00
72b7579c6e web_frontal : git clone superficiel (depth 1) + git installé + fix nom de tâche
Chemin git prouvé de bout en bout : le rôle clone le site depuis le Forgejo
souverain (depth 1 — pas l'historique lourd) et le sert derrière l'edge.
Éprouvé sur web-frontal-01 (Alliance Boréale servi via edge depuis /srv/web,
cloné de Forgejo). ansible-lint production : 0.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-05 18:22:11 -04:00
f453f77268 web_frontal : rôle sites statiques (1re brique plateforme webapp, 100% natif)
nginx + sites statiques depuis un dépôt git souverain, derrière l'edge. Pas de
conteneur, pas de runtime, pas de BD — l'éthos libre/natif. Chaque site :
git clone → vhost (headers sécurité + CSP self-only, gzip, try_files). SAN edge
+ plancher auto-dérivés. meta/flux.yml (ingress 80 depuis edge).

Spike prouvé sur web-frontal-01 (site Alliance Boréale servi via edge, HTTPS
step-ca vérifié, CSP en place). NB : le chemin git-clone est codifié mais le
spike a servi via copie locale → à éprouver (pousser le site en Forgejo).
Les apps dynamiques (dorsal systemd) = rôle à venir. ansible-lint production: 0.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-05 18:12:19 -04:00
0d2bc2c2e9 Machinerie d'exposition : SAN auto-dérivés + vhost WebSocket-aware
Élimine 3 gotchas du spike Nextcloud/Collabora :
- instancier dérive sans_exposition par edge (FQDN exposés du plan) → le cert edge
  (client_pki_sans) se met à jour tout seul, plus de liste manuelle en group_vars ;
- champ 'websocket' sur une application → le vhost d'exposition ajoute la map
  $http_upgrade + en-têtes Upgrade/Connection + timeout long (Collabora, éditeurs live) ;
- (plancher /etc/hosts : le mécanisme d'alias existait déjà, publier_expositions=true).

Prouvé sur le lab : cert edge couvre les 6 expositions, bureau 200 en WebSocket.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-05 15:30:22 -04:00
da4976aa98 serveur_collabora : rôle codifié depuis le spike (Docker, WOPI)
Conteneur collabora/code (restart always), publié sur localhost + IP LAN
(gotcha : bind localhost seul → 502 depuis l'edge), aliasgroup = domaine
Nextcloud, ssl.termination à l'edge, attente santé /hosting/capabilities.
meta/flux.yml (ingress 9980 depuis edge) alimente le registre des flux.

Docker (prouvé au spike) ; CODE natif = option future à spiker. Tag à épingler.
ansible-lint profil production : 0 échec.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-05 15:03:07 -04:00
79d0529686 serveur_nextcloud : rôle codifié depuis le spike (13 gotchas encodés)
Maison numérique souveraine (offres maison-obnl + cabinet). Tâches découpées :
paquets → php (512M + TLS PG) → install (occ, PG verify-full) → exposition
(vhost .mjs) → configure (overwrite/redis/anti-SSRF/import CA) → OIDC user_oidc
→ Collabora richdocuments (WOPI split URL) → thème Alliance (ciel étoilé).

Chaque réglage encode un piège prouvé sur collab-01 : imagick Debian 13,
PGSSLMODE dans php-fpm, MIME .mjs, allow_local_remote_servers (SSRF), import
root step-ca, memory_limit 512M, public_wopi_url après activate-config…

Version épinglée (robustesse). ansible-lint profil production : 0 échec.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-05 15:00:39 -04:00
c98bc8393f Registre des flux : schéma meta/flux.yml + pilote (postgresql/metrique/nginx)
Couche accès du zéro-confiance (complète le chiffrement). Chaque rôle possède
ses flux (comme meta/empreinte) : sens/port/protocole/pair/chiffrement/raison.
Résolu par le plan (pair→IP) → génère les règles nftables (default deny) ET le
registre d'audit. Doc de conception + 3 pilotes validés (résolveur-démo).

Séquence : schéma+pilote (fait) → résolveur → remplir les rôles → générer +
registre → activer nftables prudemment (action destructive).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-05 09:41:42 -04:00
04d807c78d Module Collaboration : squelette serveur_nextcloud (defaults/meta/README)
Cœur de l'offre maison-obnl (OBNL/coops). Surface de config posée (BD via
resoudre_base, Redis, OIDC Keycloak, Collabora WOPI, exposé cloud.<domaine>,
sauvegarde Tier 1). tasks/main.yml VOLONTAIREMENT absent : attend le spike
empirique (éprouver l'outil avant le rôle) — déployer + prouver OIDC/WOPI/
fichiers sur un vrai nœud avant de codifier.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-05 01:39:11 -04:00
867e2f8cdc Découplage instance : realm centralisé + vars génériques
Fin des dernières poches de 'codé en dur' liées à l'instance d'origine :
- realm SSO centralisé sur l'intrant identite_realm (defaut chezlepro,
  retro-compatible) ; les 4 rôles (keycloak/forgejo/grafana/oauth2_proxy)
  en dérivent. Expose dans la GUI (panneau Intrants).
- vars brandees renommees generiques : chezlepro_timezone -> fuseau_horaire,
  chezlepro_organisation -> organisation (chrony, openldap, GUI, docs).

Aucune reference fonctionnelle aux anciens noms. Le moteur ne porte plus le
nom d'un tenant. Technolibre a son propre realm (technolibre).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-05 00:47:44 -04:00
5108a6c04d Références par FQDN partout : fin des IP codées en dur
Décision d'archi : FQDN pour toute référence inter-services (non ambigu en
fédération — data-sql-01 existe chez plusieurs tenants — + nom canonique TLS).

- resoudre_base : db_host renvoie le FQDN (hote.domaine_interne) → propagé à
  keycloak/forgejo/icinga (ils en dérivent tous). Résolu par le plancher.
- client_journal : loki_url dérivé du groupe serveur_loki en FQDN (fin du
  10.0.14.11 périmé).
- nettoyage des defaults db_host IP morts (10.0.13.11, écrasés par resoudre_base).

Aucune IP littérale ne subsiste dans les defaults des rôles. verify-full OK
(SAN FQDN). S'applique au prochain déploiement.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-05 00:40:57 -04:00
20329895f7 Zéro-confiance : flux Courriel chiffré (LMTP verify + client_smtp STARTTLS)
Deux sauts est-ouest en clair, corrigés :
- LMTP edge-mta -> infra-mail:24 : lmtp_tls_security_level=verify +
  lmtp_tls_CAfile=root_ca (le CONTENU des courriels). Dovecot LMTP offrait
  déjà STARTTLS (cert step-ca, SAN infra-mail-01) : aucun changement Dovecot.
- client_smtp -> edge-mta:25 : msmtp tls_starttls on + tls_trust_file root_ca.

Prouvé : livraison LMTP status=sent (verify ⇒ TLS obligatoire), msmtp tls=on
smtpstatus=250. Déjà chiffrés : submission :587, Postfix->LDAP ldaps, IMAP :993.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-04 21:47:29 -04:00
660aee91fa Zéro-confiance : flux Logs chiffré (Loki HTTPS + Alloy push https)
Loki sert son API en HTTPS via le cert step-ca (http_tls_config + cert-sync
owned loki, motif .path). Alloy pousse en https + tls_config (ca=root_ca).
Vars : serveur_loki_tls_actif, client_journal_loki_tls.

Prouvé : Loki HTTPS /ready 200 (vérif root_ca), HTTP rejeté (400), 4 hôtes
expédient des logs en https, 0 erreur loki.write après la transition.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-04 21:15:00 -04:00
e648009b87 Zéro-confiance : flux Métriques chiffré (node_exporter TLS + scrape https)
node_exporter sert en HTTPS via le cert step-ca (--web.config.file +
cert-sync owned prometheus, motif .path). Prometheus scrape en scheme https
+ tls_config (ca=root_ca), vérifie contre l'IP en SAN. Vars :
client_metrique_tls_actif, serveur_prometheus_metriques_tls.

Prouvé : node_exporter HTTPS 200 (vérif root_ca), HTTP rejeté (400),
4 cibles Prometheus UP en https sans erreur.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-04 21:04:40 -04:00
204910edbf Zéro-confiance PG : verrou hostssl + détection de version robuste
- pg_hba hostssl (serveur_postgresql_tls_force) : refuse les connexions
  non-TLS du réseau. Posé après validation des 3 clients en verify-full.
- Fix : tls_dir sous /etc/postgresql collisionnait avec la détection de
  version (find|sort|last prenait 'tls') → filtre numérique ^[0-9]+$ +
  tls_dir déplacé sous /var/lib/postgresql/tls.

Prouvé : non-TLS rejeté (« aucun chiffrement »), TLS accepté, 3 apps 200.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-04 20:46:53 -04:00
d26651a432 Zéro-confiance : IcingaDB→PG en TLS vérifié (cert step-ca)
config.yml database : tls: true + ca: root_ca step-ca. root_ca déjà 0644
(fix client_pki). Prouvé sur sup-01 : icingadb actif, log 'pgsql+tls://',
aucune erreur TLS. 3e et dernier client BD sur verify-full.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-04 20:32:05 -04:00
a51ddc6296 Zéro-confiance : Forgejo→PG en verify-full
SSL_MODE=verify-full dans app.ini [database] + PGSSLROOTCERT (root_ca step-ca)
dans l'unité systemd (lib/pq lit l'env). root_ca déjà 0644 (fix client_pki).

Prouvé sur forge-01 : accueil 200, SSL_MODE=verify-full, PGSSLROOTCERT ok,
aucune erreur TLS/DB. Déploiement propre du 1er coup (patron éprouvé).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-04 18:53:31 -04:00
fa6ef8b031 Zéro-confiance : Keycloak→PG en verify-full + root_ca lisible (0644)
- client_pki : root_ca.crt en 0644 (un cert racine est PUBLIC ; requis pour
  que les clients TLS non-root — keycloak, forgejo… — puissent vérifier).
- serveur_keycloak : db-url-properties sslmode=verify-full + sslrootcert.

Incident maîtrisé : 1er essai, keycloak (user keycloak) ne pouvait pas lire
root_ca 0600 → SSO down → restauré en <1 min → corrigé (0644) → verify-full OK.
Prouvé : realm 200, sslmode=verify-full, aucune erreur SSL/DB.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-04 18:45:16 -04:00
5aa7fcafdb PostgreSQL : servir le cert step-ca (TLS vérifiable), non-bloquant
Zéro-confiance flux PG, côté serveur : cert-sync (owned postgres, motif .path
comme Dovecot/Postfix) + ssl_cert/key/ca_file pointant sur le cert step-ca au
lieu du snakeoil. Garde-fou : ssl non activé si le cert n'est pas en place.
Reload robuste (instance postgresql@NN-main, pas le wrapper).

Prouvé sur data-sql-01 : cert servi = Set-OPS Internal CA (vérif root_ca ok),
keycloak/forgejo toujours 200 (TLS reste optionnel, rien de cassé).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-04 18:31:30 -04:00
94c9277c3d client_pki : recharger le vrai consommateur au renouvellement de cert
Bug latent de flotte : cert-renewer rechargeait un service nommé d'après le
cert (%i = FQDN, inexistant) au lieu du consommateur réel → nginx/postfix/
dovecot/slapd servaient l'ancien cert jusqu'à expiration. Symptôme : cert
edge périmé en mémoire → échec TLS OIDC → login SSO cassé.

Correctif : client_pki_reload_services (vrais consommateurs), par groupe.
Fix immédiat de l'incident : reload nginx sur l'edge.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-04 17:18:13 -04:00
c5df8fac4a RBAC via SSO : rôle de realm Keycloak → niveau Grafana (authZ)
Machinerie additive/idempotente dans serveur_keycloak (rbac-oidc.yml) :
rôles de realm + mapper 'roles' sur les clients choisis + assignations
rôle→utilisateur. kcadm à chaud (zéro coupure SSO). Grafana :
role_attribute_path (grafana-admin→Admin, grafana-editor→Editor, sinon
Viewer). Prouvé sur id-sso-01 (idempotence) : testmail = grafana-editor.

Complète le dashboard logs (Viewer-friendly) : les deux volets de la
question « testmail peut-il voir les logs ? ».

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-04 16:58:15 -04:00
4887d2aee8 Grafana : dashboard provisionné « Journaux de la flotte » (Loki, Viewer-friendly)
Provisioning de dashboards (provider + JSON) : un dashboard logs avec
sélecteur d'hôte + filtre regex + panneau logs + débit. Référence Loki par
une VARIABLE de datasource (ds_loki), pas un UID codé en dur.

Leçon : ajouter un uid explicite à une datasource déjà provisionnée casse
le démarrage de Grafana (« data source not found ») → variable de datasource.

Permet aux Viewers (dont testmail) de voir les logs sans accès Explore.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-04 16:10:59 -04:00
e9ca943425 Forgejo : identité visuelle Alliance (custom/ officiel, léger)
Branding via le dossier custom/ de Forgejo (mécanisme officiel, résistant
aux MAJ) : accent aurore par variables CSS, logo/favicon étoile, page
d'accueil brandée (home.tmpl), thème sombre, nom + méta. Codifié dans
serveur_forgejo (branding/app_name/theme). Prouvé sur forge-01.

+ CHANGELOG : entrées wiki pédagogique (14 unités) et GUI (boutons cohérents).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
EOF
2026-07-04 15:47:39 -04:00
e006dee693 Retirer 3 rôles legacy (serveur_sendmail, client_dns, client_ldap) + nettoyage
Supprimés (supersédés / hors-conception) : serveur_sendmail (→ Postfix),
client_dns (→ plancher + client_unbound), client_ldap (login LDAP OS, hors
design). Rôles + playbooks de groupe retirés.

Nettoyage des références :
- dependances-groupes.yml : entrées client_dns/client_ldap retirées + entrées
  mortes des scaffoldings (nextcloud/collabora/client_supervision) ; deps
  périmées corrigées (client_smtp → serveur_postfix ; serveur_keycloak →
  serveur_postgresql, la raison parlait à tort de Nextcloud).
- 6 modèles d'exemple : app mail serveur_sendmail → serveur_postfix.
- README, AGENTS : listes/glossaire nettoyés.
- catalogue-services : listes, tables, roadmap ; note « rôles retirés ».
- nomenclature-vm : infra-mail-01 → serveur_dovecot (était faux).
- courriel-conception, dns-interne (re-ciblé client_unbound), pouvoirs,
  intrants, READMEs (client_smtp/forgejo/openldap/unbound).

ansible-lint : 0 échec (366 fichiers). instancier OK.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-04 12:14:04 -04:00
ecc7b2767b docs(keycloak) : documenter le thème Alliance + la compatibilité MAJ
README du rôle : section Thème (vars login/account/theme_cache, fonctionnement,
piège cache 'immuable', mise en garde MAJ Keycloak — calque PatternFly/parents,
pas de réapparition de l'ancien thème mais retouche possible après MAJ majeure,
check-list). + README court dans le dossier du thème.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-04 10:05:58 -04:00
c785e41520 Thème account Keycloak : lisibilité (texte clair, contraste)
Remonte les variables de couleur PatternFly atténuées (v5/v6/générique :
Color--200, text--color--subtle...) + force titres/labels/aides en clair,
pour que le contenu de la console de compte soit lisible sur fond aurore.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-04 09:50:03 -04:00
0419114755 Thème Keycloak : faire apparaître la constellation (attendre le DOM)
Keycloak injecte le script dans <head> → il tournait avant que <body>
existe (insertBefore plantait) → pas de canvas. Corrigé : init différé à
DOMContentLoaded + repli taille sur window.innerWidth/Height. Dégradé aurore
posé aussi sur body (repli si le canvas échoue). Script copié côté account.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-04 09:44:42 -04:00
e12c40e00c Keycloak : option cache de thèmes (lab = désactivé, prod = activé)
serveur_keycloak_theme_cache (défaut true=prod). À false, ajoute
spi-theme-static-max-age=-1 + cache-themes/templates=false dans keycloak.conf
→ ressources servies en no-cache : les tweaks de thème sont visibles sans
lutter contre le cache 'immuable' du navigateur. Bac à sable = false.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-04 09:39:27 -04:00
a917bac386 Thème account Keycloak : couvrir PF4+PF5 + fond aurore + constellation
Le SPA account peut être en PatternFly 4 (.pf-c-*) ou 5 (.pf-v5-*) selon la
version ; on cible les deux. Même correctif que le login : fond par défaut
effacé (transparent), ciel aurore + constellation remontés (z-index), cartes
en verre, champs et bouton en !important.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-04 01:30:17 -04:00
c5434bb33c Thème login Keycloak : corriger fond, constellation et champs (vrais sélecteurs KC 26)
Le thème "keycloak" de KC 26 est PatternFly (body sans classe, .pf-c-*).
Corrections : fond gris par défaut sur .login-pf-page effacé (transparent),
ciel aurore remonté (z-index 0, sous le contenu z-index 1) → la constellation
s'affiche ; champs ciblés en .pf-c-form-control !important (le mot de passe
n'était plus blanc) ; carte/bouton/liens en !important.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-04 00:07:49 -04:00
987ba88644 Thème Keycloak : console de compte (account) à l'identité Alliance
Thème account (parent=keycloak.v3) : overlay CSS surchargeant les variables
PatternFly 5 (fond aurore, cartes en verre, accent aurore, bouton dégradé)
+ la même constellation animée. Appliqué via kcadm -s accountTheme.

Prouvé : console charge (200, keycloak.v3 intact), account.css servi (200),
constellation.js référencé.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-03 23:54:19 -04:00