Commit graph

11 commits

Author SHA1 Message Date
a90dff7ba7 courriel : routage local par identifiant, et la livraison interne remise en marche
Arbitrage rendu : le courrier local est route par uid, plus par l'attribut
mail. Dovecot le faisait DEJA (mail_home = /var/vmail/%{user | username}) ;
les deux moities ne s'accordaient que par coincidence, tant que mail valait
uid@<domaine_interne>. Cout assume : l'adresse interne est derivee et ne se
choisit plus ; en echange mail redevient libre de porter la vraie adresse de
la personne.

Puis la preuve de bout en bout a revele bien pire : toute livraison interne
etait DIFFEREE.

  SSL_connect error to infra-mail-01:24: Connection timed out
  status=deferred (Cannot start TLS: handshake failure)

Postfix etait durci (lmtp_tls_security_level = verify), le port LMTP de
Dovecot ecoutait en clair — son ssl = required global ne concerne que les
services de connexion. Les deux cotes d'un meme flux avaient ete traites
separement. Corrige et accorde : ssl = yes sur l'inet_listener (TLS implicite)
et lmtp_tls_wrappermode = yes cote client ; l'un sans l'autre ne marche pas.

Livraison prouvee : status=sent (250 ... Saved), message dans
/var/vmail/sysadmin/Maildir/.INBOX/new/.

Le devis disait CONFORME pendant ce temps : il verifiait la resolution et les
dialectes, jamais si le courrier BOUGE. Un devis qui ne regarde que les
reglages ne dit pas si le service rend son service. Il releve desormais la
file d'attente et ses raisons ; test negatif : la panne est nommee.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-08 09:42:45 -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
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
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
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
457b89927b Soumission courriel :587 interne (authentifiée) — boucle souveraine bouclée
Postfix (edge-mta) sert :587 (master.cf : STARTTLS + SMTP AUTH, seuls les
authentifiés relaient) ; SASL délégué à Dovecot (infra-mail, passdb LDAP)
via un auth-listener réseau (inet_listener sasl :12345). Interne seulement.

Prouvé (swaks) : testmail s'authentifie (235), Postfix accepte (250 queued),
courriel livré dans la boîte. Le courriel souverain fait recevoir ET envoyer.

Pièges : Dovecot 2.4 exige un nom de section inet_listener ; nouveau service
master.cf → restart (pas reload).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-03 23:17:36 -04:00
0a0563c226 Consolider : binding annuaire (resoudre_annuaire) — keycloak/dovecot/postfix
Rôle utilitaire partagé resoudre_annuaire (comme resoudre_base) : dérive la
connexion OpenLDAP du domaine_interne + un hôte surchargeable, au lieu de
répéter ldaps://id-ldap-01... dans chaque rôle. Facts uri/port/base_dn/
users_dn/bind_dn/bind_password (secret no_log).

Migrés + prouvés (config neutre, changed=0) : keycloak (fédération, testmail
token 200), dovecot + postfix (flux courriel livré de bout en bout).

Piège : les defaults d'un rôle inclus ne persistent pas hors de son
exécution — publier via set_fact.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-03 22:23:22 -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
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