Commit graph

33 commits

Author SHA1 Message Date
b60c5dc963 serveur_oauth2_proxy : passerelle SSO OIDC générique + Icinga Web 2 au SSO
oauth2-proxy (v7.15.3) place Keycloak devant toute app sans OIDC natif
(auth external, utilisateur via en-tête). Rôle paramétrable, réutilisable.
Éprouvé devant icingaweb2 (backend=external, X-Forwarded-Preferred-Username).

Prouvé : testmail → oauth2-proxy → Keycloak → icingaweb2 /dashboard,
connecté. Ferme le gap LDAP-direct d'icingaweb2.

Réglages appris : insecure_oidc_allow_unverified_email (IdP interne) ;
reverse-proxy passe X-Forwarded-* pas X-Auth-Request-* ; handler nginx en
restart (pas reload) — un changement d'adresse d'écoute n'est pas pris par
un reload gracieux.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-03 19:05:04 -04:00
2ed919e914 Module BPM éprouvé + codifié — pile Icinga complète
serveur_icingaweb2 installe + active businessprocess, crée le répertoire
des processus (éditable UI) et sème des processus BPM en IaC
(serveur_icingaweb2_bpm_processes). Format host;service éprouvé via les
fixtures du module.

Prouvé : processus « Supervision Chezlepro » (roll-up load/procs/swap/
ping4/ssh en ET) rend un état dans l'UI, backend IcingaDB (pas d'IDO).
Rôle re-prouvé (reset → recrée le processus). Pile Icinga = moteur +
Web 2 + BPM.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-03 17:04:34 -04:00
b3b972fb5e serveur_icingaweb2 : Icinga Web 2 (UI + module IcingaDB) — éprouvé
App PHP (php8.4-fpm) + nginx local, exposée par l'edge (auto-dérivé).
Config par fichiers .ini (config/resources/authentication/roles + module
icingadb), pas d'assistant. Base IcingaDB via resoudre_base. Auth LDAP
direct (client_pki sur sup-01) — pas d'OIDC natif (SSO-proxy = raffinement).

Prouvé : testmail (LDAP) se connecte (/dashboard), module IcingaDB affiche
la supervision (hôte icinga). Déploiement failed=0 (frictions dans le
simulateur curl, pas le rôle). Reste : module BPM.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-03 16:57:04 -04:00
889e9af97a DRY : rôle utilitaire partagé resoudre_base (résolution BD depuis le registre)
Le bloc copié-collé dans keycloak/forgejo/icinga (charger le registre,
filtrer par consommateur, déréférencer le secret via lookup('vars'),
résoudre hôte/port) extrait dans roles/resoudre_base (facts génériques,
no_log). Les 3 rôles l'incluent + adoptent les facts. Le secret ne quitte
toujours pas le rôle.

Fait « sur la preuve » : re-déploiement keycloak + forgejo failed=0,
idempotent, testmail token Keycloak HTTP 200. Ferme le reste de la Phase 2
des bindings.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-03 15:57:06 -04:00
e214dcf4ed Forgejo au SSO OIDC (2e app SSO) — éprouvé sur forge-01
serveur_forgejo (10.0.0) : PostgreSQL via registre, exposé par l'edge
(auto-dérivé), source OAuth2 vers Keycloak (add-oauth idempotent), client
OIDC forgejo via serveur_keycloak_clients, auto-enregistrement OIDC
(identités depuis l'annuaire seulement).

Prouvé : testmail (LDAP) → « Se connecter avec Chezlepro » → compte
auto-créé, connecté au tableau de bord.

5 bugs de 1er déploiement corrigés : dépendance sendmail→postfix ;
app.ini propriété git (persiste secrets) ; ordre admin/migrations
(flush_handlers + wait_for) ; HTTP_ADDR 0.0.0.0 (edge distant) ;
auto-enregistrement OIDC.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-03 15:52:38 -04:00
fa945de5a7 client_unbound : résolveur local (DNS dynamique) — éprouvé sur un nœud
Unbound par nœud (127.0.0.1) : stub-zone vers PowerDNS (interne) + récursion
Internet (ou forward). Alternative dynamique au plancher /etc/hosts. Bascule
resolv.conf protégée (apply+confirm) ET validée avant (Unbound doit résoudre
interne + Internet, sinon pas de bascule → nœud jamais coupé). Sûr par défaut
(apply=false).

Prouvé sur data-sql-01 : dig @127.0.0.1 keycloak/id-sso-01 → PowerDNS,
deb.debian.org → récursion, apt OK. Rollout flotte = opt-in par nœud.

Note : OPNsense embarque Unbound → l'Unbound réseau pourra vivre sur
l'appliance de bordure (nœud public, Étape B) ; ce rôle reste complémentaire.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-03 14:35:00 -04:00
a870c9befe hosts_statiques : alias d'exposition dans le plancher /etc/hosts (résolution sûre)
Le plancher pose <IP edge> <FQDN exposé> sur chaque nœud, dérivé de expose +
domaines.edge (même source que nginx/PowerDNS). DNS-indépendant, aucun risque.
Chargement du plan best-effort (stat delegate_to localhost + become false).

Prouvé : /etc/hosts d'obs-01 régénéré avec keycloak/grafana → edge (ligne
manuelle éliminée), SSO Grafana fonctionne via le plancher (login: testmail).
Boucle Phase 3 fermée : expose → vhost + SAN cert + A PowerDNS + alias plancher.

Bugs corrigés : serveur_loki (groupe loki manquant) déjà committé ; stat
sur cible→contrôle ; become inutile sur le contrôle.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-03 14:14:34 -04:00
00ba515aad serveur_powerdns : A d'exposition auto-dérivés (DNS de la Phase 3 bindings)
La zone interne inclut désormais un A pour chaque FQDN d'exposition
(expose des applications) vers l'edge qui le sert (domaines.edge), via
expositions_des_applications. Déclarer expose → vhost + SAN cert + DNS.

Prouvé : dig @infra-dns-01 grafana/keycloak.lab.chezlepro.internal → edge .21.

Limite : PowerDNS est autoritatif (pas récursif) — pour que les nœuds
l'utilisent sans casser Internet, il faut un récursif (pdns-recursor) ou
garder le plancher /etc/hosts. Ne pas repointer client_dns naïvement.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-03 13:47:29 -04:00
494dbb32dc serveur_keycloak : enregistrement des clients OIDC codifié (kcadm idempotent)
Liste déclarative serveur_keycloak_clients (clientId, redirect_uris,
web_origins, secret) → tasks/clients-oidc.yml enregistre chaque client
confidentiel via kcadm (create-si-absent, no_log). Décision côté Keycloak
(creds admin non répandus dans les rôles app) ; secret = même var de voûte
que l'app.

Prouvé : client grafana supprimé → rôle → recréé → testmail se connecte à
Grafana ; redéploiement idempotent (changed=0). Déploiement Grafana au SSO
désormais autonome.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-03 13:37:33 -04:00
67699e7841 Grafana branché au SSO OIDC (« Se connecter avec Chezlepro ») — prouvé
serveur_grafana : config OIDC via GF_AUTH_GENERIC_OAUTH_* (client grafana,
realm chezlepro, secret vault_grafana_oidc). serveur_loki/prometheus/grafana
déployés sur obs-01. Fix serveur_loki : créer le groupe loki (paquet crée
l'user en nogroup).

Prouvé (flux authorization code headless via l'edge) : testmail (LDAP) se
connecte à Grafana par le SSO ; /api/user renvoie login/email/name fédérés
depuis LDAP. Chaîne LDAP → Keycloak → Grafana.

Gaps notés : enregistrement du client OIDC dans Keycloak fait via kcadm à la
main (à codifier) ; résolution keycloak→edge sur obs-01 = /etc/hosts manuel
(PowerDNS devrait porter les A d'exposition) ; mapping de rôles Grafana.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-03 13:15:52 -04:00
5e3e4e0a46 serveur_keycloak : corriger le lint (risky-shell-pipe) de la fédération
set -euo pipefail + executable /bin/bash sur la tâche kcadm. Sûr ici (les
grep vides n'alimentent que des assignations, tolérées par set -e).
Vérifié : lint production 0 échec, redéploiement idempotent (changed=0),
testmail token HTTP 200.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-03 11:31:36 -04:00
c707b693c4 serveur_keycloak : fédération LDAP (modèle A) automatisée et prouvée
Le rôle configure via kcadm (idempotent) un realm applicatif + un provider
de stockage LDAP READ_ONLY vers OpenLDAP (LDAPS, uid/entryUUID/inetOrgPerson).
LDAPS validé par le truststore système (truststore-paths → bundle CA, racine
step_ca via client_pki, désormais requis sur le nœud). Secrets par environment
+ no_log. tasks/federation-ldap.yml.

Éprouvé avant codification, puis prouvé par le rôle : testmail (user LDAP)
obtient un token via le realm chezlepro (HTTP 200) ; redéploiement idempotent
(changed=0). Modèle d'identité A (OpenLDAP source → Keycloak fédéré) complet.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-03 11:29:23 -04:00
d95b26c243 bindings Phase 1 : résolveur de liens dans instancier (relations déclaratives)
Une application déclare ses liens ([{vers, role}]) dans applications.yml ;
chaque rôle décrit les liens acceptés dans meta/liens.yml. instancier
résout la cible (FQDN interne dérivé de la nomenclature) et injecte les
variables en host_vars du consommateur.

Migration prouvée : les liens mail Postfix→Dovecot (mailstore) et
Postfix→rspamd (milter) passent de group_vars codés en dur à des liens
déclaratifs — make instancier donne DIFF VIDE (mêmes vars générées).

Cf. docs/bindings-conception.md.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-03 08:33:30 -04:00
8df1db3b47 serveur_rspamd (rspamd 3.x) : antispam + DKIM en milter Postfix — prouvé
Rôle antispam sur edge-mta : Redis local, worker proxy en mode milter
auto-scan (:11332), signature DKIM sortante (clé générée idempotente,
enregistrement DNS affiché pour l'Étape B). Config par local.d/.
Postfix branché via smtpd_milters (option serveur_postfix_rspamd_milter,
milter_default_action=accept = tolérant si rspamd down).

Prouvé : courriel traversant le milter → scanné (rspamc stat: 1) +
signé DKIM (DKIM-Signature d=...), livré, lu en IMAP.
Étape A (courriel interne) complète : dovecot + postfix + rspamd.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-02 18:04:44 -04:00
5846a08667 serveur_dovecot : remise LMTP fonctionnelle — flux courriel interne prouvé
Réglages Dovecot 2.4 qui débloquent la remise LMTP (durement gagnés au
premier flux réel) :
- userdb static { static_allow_all_users = yes } : sinon le userdb exige
  un passdb et renvoie NOTFOUND (expéditeur/raw-mail-user externe absent
  de l'annuaire) → rejet 550.
- mail_inbox_path vidé : le défaut 2.4 (/var/mail/%{user}, mbox root)
  refusait l'autocréation de l'INBOX (Permission denied).
- Maildir explicite : mail_home + mail_path = %{home}/Maildir.
- Chemin par nom d'utilisateur : home identique côté LMTP (local-part) et
  IMAP (adresse complète). Mono-domaine ; multi-domaine = raffinement.

Prouvé de bout en bout : envoi → Postfix (validation LDAP) → LMTP →
Dovecot → boîte → LU EN IMAP (auth LDAP, TLS step_ca). status=sent.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-02 17:47:12 -04:00
e17ae54fda serveur_postfix : résolution du plancher /etc/hosts (native + chroot)
Trouvés au premier flux réel :
- lmtp_host_lookup = native (Postfix faisait du DNS-only, ignorant le
  plancher /etc/hosts → « Host not found » pour le mail-store) ;
- copie de /etc/hosts, resolv.conf, nsswitch.conf, services dans le
  chroot Postfix (/var/spool/postfix/etc) pour la résolution en chroot.

Résultat : Postfix atteint bien le mail-store en LMTP. Reste un nœud de
config Dovecot 2.4 (userdb LMTP renvoie NOTFOUND via auth-master) à
résoudre pour clore le flux interne.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-02 17:31:22 -04:00
9480e585a5 serveur_postfix (Postfix 3.x) : MTA edge-mta — cartes LDAP + LMTP + TLS step_ca
Réception :25, validation des boîtes par carte LDAP (attribut mail),
remise LMTP réseau vers le mail-store Dovecot (virtual_transport lmtp),
TLS via step_ca (pont de cert), aucune boîte locale. main.cf +
ldap-mailboxes.cf, validé par postfix check. Bind LDAP: vault_openldap_admin.

Validé statiquement (ansible-lint, syntax, rendu main.cf) ; déploiement à suivre.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-02 15:34:24 -04:00
a4b25018e6 serveur_dovecot : LMTP réseau pour un MTA distant (edge-mta)
Ajoute un inet_listener LMTP (port 24, variable) pour qu'un Postfix
distant (nœud edge-mta) livre par LMTP réseau. À restreindre au nœud MTA
par pare-feu en prod. Prérequis de la topologie MTA-dédié.
Validé : :24 écouté, doveconf OK.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-02 15:28:37 -04:00
7549c61e75 serveur_dovecot (Dovecot 2.4) : IMAP + auth LDAP + TLS step_ca — prouvé
Rôle mail : IMAP :993/:143 + LMTP, auth/annuaire LDAP (serveur_openldap),
stockage Maildir (user vmail), TLS via step_ca (pont de cert + resync au
renouvellement), auth système par défaut neutralisée. Config drop-in en
syntaxe Dovecot 2.4 (mail_driver, ssl_server_cert_file, passdb ldap),
validée par doveconf au déploiement. Sockets Postfix conditionnels à la
présence de l'utilisateur postfix (co-localisation).

Déployé et prouvé sur infra-mail-01 : doveadm auth test — bon mot de passe
accepté, mauvais refusé, cert IMAPS émis par step_ca. Format 2.4 validé
empiriquement avant l'écriture (leçon « éprouver l'outil »).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-02 15:09:37 -04:00
e01adac67b Courriel : pivot de Stalwart vers Postfix/Dovecot/rspamd
Stalwart trop jeune/volatil pour un pilier mail critique (config cassée
0.15→0.16, `config apply` annoncé non livré, API REST supprimée pour
JMAP, gros backlog). Pivot vers la stack mature Postfix/Dovecot/rspamd,
100 % configurable par fichiers (alignée au modèle déclaratif Set-OPS).

- Rôle serveur_stalwart retiré (Phase 1 prototypée ; git en garde la trace).
- docs/courriel-conception.md mis à jour ; vault_stalwart_admin retiré.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-02 12:52:49 -04:00
e3efbb5b1a serveur_stalwart : Phase 1 (install + démarrage), code prod
Stalwart Mail Server v0.16.11, binaire unique natif. Mécaniques réelles
validées empiriquement sur le binaire :
- config.json = objet typé {"@type":"RocksDb","path":…} (DataStore seul) ;
- démarrage IaC en mode récupération (STALWART_RECOVERY_MODE +
  STALWART_RECOVERY_ADMIN), admin depuis la voûte (vault_stalwart_admin).

Rôle : install version-épinglée, user système, unité systemd durcie
(CAP_NET_BIND_SERVICE, ProtectSystem), EnvironmentFile pour le secret.
Phase 2 (écouteurs/TLS step_ca/annuaire LDAP/DKIM via API d'admin) à venir.
Validé statiquement (ansible-lint, syntax, rendu config.json).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-02 10:24:50 -04:00
1a59af4d5b serveur_openldap : installer debconf-utils (module debconf) — validé en réel
Le module ansible debconf exige debconf-get-selections (paquet
debconf-utils), non installé -> échec au preconfigure du mot de passe
admin slapd. Ajout de l'install en tête de rôle.

Déploiement réel validé sur un nœud identité frais : slapd en LDAPS
(:636), certificat émis par step_ca (Verify OK), OU people/groups
créées, organisation depuis l'intrant. Avec le fix d'ordre (socle
d'abord), la chaîne socle → client_pki → serveur_openldap tient.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-02 09:45:34 -04:00
1edd205d13 serveur_openldap : TLS via step_ca + organisation en intrant (code prod)
- TLS LDAPS/STARTTLS : pont du cert step_ca (client_pki, root:root 600)
  vers /etc/ldap/tls lisible par openldap ; script + unité path systemd
  qui re-synchronise et recharge slapd au renouvellement ; olcTLS* dans
  cn=config ; SLAPD_SERVICES expose ldaps://. Dégrade proprement sans cert.
- Organisation : intrant chezlepro_organisation (remplace « Exemple Inc »).

Validé statiquement (ansible-lint, syntax) ; déploiement réel à suivre.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-02 07:27:43 -04:00
a5903f192b client_pki : SANs explicites sur le certificat d'hôte (mTLS)
step ca certificate ne recevait aucun --san explicite. Ajout d'une liste
client_pki_sans (FQDN + nom court + IP) et d'une boucle --san dans la
commande. Le cert porte désormais DNS:fqdn, DNS:court, IP:adresse — avec
EKU Server+Client Auth, prêt pour un mTLS bidirectionnel. Vérifié sur
infra-dns-01 (ré-émission).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-02 00:00:10 -04:00
a8319d4367 serveur_nginx : corriger server_tokens en double (Debian 13)
Debian 13 livre « server_tokens off; » actif dans nginx.conf ; notre
drop-in 99-setops.conf le redéclarait → nginx -t « directive is
duplicate » → déploiement planté au handler de validation. Le rôle
neutralise maintenant la ligne distro (replace idempotent) ; le drop-in
reste l'unique source. Trouvé en déployant nginx pour de vrai.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-01 23:26:43 -04:00
27b8f51f15 step_ca : dry-run check-safe (install + init du dépôt Smallstep)
Le rôle ajoute bien le dépôt Smallstep et installe step-cli/step-ca —
il n'était PAS cassé. Mais en --check, le dépôt/binaire ne sont pas
réellement présents → apt « No package step-cli » puis « step ca init »
échouaient (faux). Ajout de when: not ansible_check_mode sur l'install
et l'initialisation de l'AC (le service l'avait déjà).

Dry-run step_ca : failed=0 (prouvé avec vault_* de test). Config dépôt
vérifiée (clé officielle, stable/debian suite debs) — vrai déploiement
non exécuté (nécessite la voûte + action GUI).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-01 21:44:14 -04:00
bbcf087904 Câbler les secrets des rôles à leur variable de voûte (vault_*)
Les rôles à secrets déclaraient serveur_X_password: "" avec la variable
de voûte seulement en commentaire — aucun mapping réel. Remplir la voûte
ne branchait donc rien (secret vide → assertion échoue).

Les 12 secrets des 8 rôles pointent maintenant vers leur source :
  serveur_X_password: "{{ vault_X | default('') }}"
Comportement inchangé si la voûte est vide ; branché dès qu'elle a le
secret. Prouvé : assertion step_ca passe avec vault_step_ca_password.
Chaque instance remplit ses vault_* ; aucun mapping par instance.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-01 21:29:18 -04:00
f82630de6c Rendre le dry-run (--check) fiable sur les rôles applicatifs
« Vérifier » échouait faussement sur un hôte frais : les tâches
« démarrer service » et les handlers restart/reload/validate touchent
un paquet que --check n'installe pas vraiment → service/fichier absent
→ faux fatal, qui bloquait le déploiement (le dry-run doit passer pour
débloquer « Déployer »).

Ajout de « when: not ansible_check_mode » sur ces tâches + handlers des
13 rôles serveur_* (29 gardes). Sautées en dry-run, inchangées en réel.
Validé : powerdns dry-run failed=0 ; ansible-lint 0 échec ; 19 playbooks
syntax-OK.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-01 21:01:53 -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
a9a1493440 Plancher de résolution /etc/hosts (indépendant du DNS)
Nouveau rôle de socle hosts_statiques (dans serveur_debian) : génère
/etc/hosts sur chaque VM depuis l'inventaire. L'écosystème se résout par
nom même DNS éteint, et le bootstrap ne dépend plus du DNS. client_dns
rendu tolérant (inerte sans DNS interne) ; dépendance client_dns→powerdns
passée molle. PowerDNS devient une commodité (zone/externe).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-30 18:05:42 -04:00
3a3a80e0ac Appliquer chezlepro_timezone (rôle chrony) + nettoyer le CSS mort du GUI
L'intrant de base global chezlepro_timezone était défini mais jamais
appliqué : le rôle chrony règle désormais le fuseau horaire (chrony_timezone,
vide = ne pas toucher). Nettoyage du CSS/HTML devenu mort après la refonte
maître-détail (.message, .chip-f, .onglet*, .base-ligne, .ch-grp*, etc.).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-30 15:36:08 -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
Alliance Boreale
3dd3f43ad8 Set-OPS — moteur d'ecosystemes numeriques souverains (Alliance Boreale) 2026-06-24 20:17:46 -04:00