Set-OPS-Public/docs/courriel-conception.md
Daniel Allaire 5bc3bceac1
Some checks failed
verifier / verifier (push) Has been cancelled
documentation : la tournee des 74 documents, parce qu un balayage ne lit pas
La revision a commence par un balayage par motifs — chemins morts, cibles make
absentes, comptes derives. Il a trouve une trentaine d ecarts et rate presque
tout le reste : un motif ne voit que ce qui s exprime en motif.

make hote-planifier en est l exemple. La cible EXISTE, donc le controle passait
au vert. C est une cible depreciee qui refuse et sort en 2, recommandee par
AGENTS.md, et qui contredit la REGLE D OR du meme fichier trois ecrans plus
haut. Il fallait lire pour la voir.

74 documents lus un par un. 66 corriges, 8 exacts.

CE QUI ETAIT FRANCHEMENT FAUX

AGENTS.md, la source d autorite, annoncait la flotte pas encore executee contre
des VM reelles. Elle a ete rasee et remontee depuis zero trois fois.
ecosysteme-chezlepro.md, le document montre a un client, portait la meme
phrase : il se sous-vendait gravement.

courriel-conception.md s ouvrait sur aucun role n est encore ecrit, au-dessus de
son propre paragraphe 1 qui les nomme. autorisation.md se terminait sur rien n
est construit alors qu il rapporte des mesures datees du role en fonctionnement.
hebergeur-exploitation.md disait rien n est fait d un depot qui existe.
filiation-emancipation.md se contredisait a deux ecrans de distance.

DES MODELES DECRITS D APRES UN MONDE ANTERIEUR

Le resolveur : cinq documents decrivaient un Unbound par VM en opt-in, trois le
donnaient en exemple d integration FACULTATIVE — il est universel depuis le
2026-08-24. L adressage de nomenclature-vm.md : reseau unique, VLAN 11-15, VMID
a cinq chiffres. Le nommage SDN de sdn-evpn.md contre le code : c est le wiki
qui avait raison.

CE QUI CASSE AU PREMIER ESSAI

Le nom du gabarit dore etait faux a quatre endroits, dont la procedure qui le
FABRIQUE et le critere R2 de l epreuve d operateur independant.
preparer-un-site-hebergeur.md avertissait qu une VM faite a la main serait
detruite : raser derive du plan, il ne la detruira jamais — le risque est l
inverse. Un mot de passe d essai en clair dans un depot public.

DEUX PREUVES ETENDUES, ET UNE QUI SE TROMPAIT ELLE-MEME

P57 couvre les groupes : elle a signale aussitot 29 groupes annonces au-dessus d
un tableau qui en cite 40. P29 confronte le tableau de authentification.md aux
declarations reelles : 12 annonces, 21 reels.

Et P57 imposait un chiffre faux — 56 preuves alors que le depot en porte 57, la
conditionnelle vivant hors de tout comptage. Un garde-fou qui fait respecter une
erreur ajoute l assurance a l erreur.

CE QUI RESTE, ET QU AUCUNE PREUVE NE TIENT

Deux comptes trouves a la main. Et une lacune reelle : rien ne garde les
meta/acces.yml — ni qu un service web-sso en porte un, ni que le groupe qu il
nomme existe. P29 tient les positions d authentification, personne ne tient les
habilitations.

make prouver : CONFORME, 56 OK, 0 echec, 1 saute. 0 lien mort.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Crgis8CxCWkAGFA1ecBz3q
2026-09-06 16:18:23 -04:00

13 KiB

Conception — Service de courriel souverain (Chezlepro)

Pour qui : le mainteneur du service de courriel.

Statut, revu le 2026-09-06 — l'Étape A est LIVRÉE, l'Étape B reste du cadrage. Ce document annonçait « aucun rôle n'est encore écrit » : les trois rôles (serveur_postfix, serveur_dovecot, serveur_rspamd) existent, sont déployés, et le flux interne est prouvé de bout en bout — SMTP → validation LDAP → LMTP chiffré → boîte → lecture IMAP, avec antispam et signature DKIM. Ce qui n'est pas livré, c'est l'Étape B (§11) : la face publique — Let's Encrypt, reprise du MX .53, enregistrements chez Namespro, tests de délivrabilité. Lire ce document ainsi : les décisions du §1 sont arrêtées et appliquées ; la feuille de route du §11 est ouverte.

1. Décisions arrêtées

Sujet Décision
Périmètre Vrai service de courriel (boîtes utilisateurs, réception publique, IMAP) — pas un simple relais sortant.
Modèle Full self-host : MX entrant et sortant chez Chezlepro, réputation d'IP propre.
Stack Postfix (MTA) + Dovecot (IMAP/LMTP) + rspamd (antispam/DKIM) — la stack libre mature, éprouvée depuis 20+ ans, entièrement configurable par fichiers. Trois rôles Set-OPS (serveur_postfix, serveur_dovecot, serveur_rspamd), comme on configure nginx/powerdns.
Identité Boîtes/utilisateurs dans l'OpenLDAP existant (Postfix + Dovecot → LDAP). Pas de comptes en double.
DNS Enregistrements publics dans la zone chezlepro.ca ; noms internes dans PowerDNS.
PKI Deux CA distinctes (voir §6) : Let's Encrypt pour les faces publiques, step_ca pour l'interne.
Démarche Deux étapes (voir §11) : (A) fonctionnement INTERNE d'abord (step_ca, LDAP, SMTP/IMAP internes, zéro dépendance publique) ; (B) fonctionnement EXTERNE ensuite (Namespro, Let's Encrypt, reprise du MX .53).

Le courrier de notification système des nœuds (cron, alertes) est relayé vers le MTA serveur_postfix (edge-mta) via client_smtp/msmtp. C'est distinct de ce service de boîtes et ne le remplace pas. (Note : l'ancien rôle serveur_sendmail a été retiré — supersédé par Postfix.)

Historique — pivot depuis Stalwart (2026-07-02). On avait d'abord choisi Stalwart (binaire unique, moderne). Le prototypage a révélé un projet jeune et volatil : modèle de config cassé entre 0.15 et 0.16, outil IaC stalwart config apply annoncé mais non livré dans le binaire, API REST supprimée au profit de JMAP, backlog d'issues/PR important. Pour un pilier critique souverain censé durer, c'est trop précaire. On pivote vers la stack mature Postfix/Dovecot/rspamd, qui a en prime l'avantage d'être 100 % déclarable par fichiers — donc parfaitement alignée avec le modèle Set-OPS (déclaratif, idempotent, exploitable sans IA). La Phase 1 Stalwart (rôle serveur_stalwart) est retirée ; git en garde la trace. Stalwart à réévaluer dans ~2 ans, une fois mûri et son config apply livré.

2. Prérequis IP publique — VÉRIFIÉ (recon DNS, 2026-07-02)

Le full self-host sortant exige un PTR propre, forward-confirmed, hors blocklist. C'est déjà en place pour le MX primaire de Chezlepro :

  • mx.chezlepro.ca = 69.70.26.53 ; PTR → mx.chezlepro.ca ; FCrDNS aller-retour OK.
  • Bloc 69.70.26.x (Videotron statique) contrôlé par Chezlepro ; PTR custom obtenable (déjà fait pour .53).

→ La condition dure de délivrabilité est levée pour le primaire. Le full self-host n'est pas un pari : c'est reprendre .53 en préservant sa réputation.

Réserves :

  • laposte-01 = 69.70.26.55 (MX secours) a encore le PTR Videotron par défaut (modemcable055…), pas laposte-01.chezlepro.ca — à corriger s'il doit émettre.
  • DKIM : le sélecteur default._domainkey est vide publiquement — à (re)poser.

État de la prod Chezlepro (recon)

Élément Réalité
DNS public Namespro (htns1/2/3.namespro.ca) — pas PowerDNS. PowerDNS = interne uniquement.
Bloc IP 69.70.26.x (Videotron statique) : .51 apex, .53 mx, .55 laposte-01, .59 git.
Mail existant MX mx → .53 déjà en service ; SPF -all correct ; DMARC quarantine correct.
Vue interne split-horizon (NS delaviorne.net, IP 10.10.x/192.168.14.x) — ne pas confondre avec le public.

Conséquence : le service mail n'est pas greenfield. Il reprend/modernise l'existant (MX .53), il ne le recrée pas.

3. Topologie (2-3 nœuds)

                          INTERNET
                             │
        DNS public chezlepro.ca :  MX 10 → mail1 ,  MX 20 → mail2
                             │
             ┌───────────────┴───────────────┐
             ▼                                ▼
   ┌────────────────────┐           ┌───────────────────┐
   │ mail-01 (PRIMAIRE)  │           │ mail-02 (MX secours)│
   │ Postfix (MTA)       │◄──relais──│ Postfix (relais)    │
   │  SMTP 25 / 587 / 465│  quand    │ SMTP 25 seulement   │
   │ Dovecot (IMAP 993   │  mail-01  │ file d'attente puis │
   │  + LMTP + Sieve)    │  est down │ transfert à mail-01 │
   │ rspamd (spam + DKIM)│           └───────────────────┘
   │ BOÎTES stockées     │
   └─────────┬──────────┘
             │ (réseau interne, mTLS step_ca)
     ┌───────┼─────────────┬──────────────┐
     ▼       ▼             ▼              ▼
  OpenLDAP  step_ca     PowerDNS      PostgreSQL
 (identité)(certs int.)(DNS interne)(métadonnées, option)

Topologie révisée (2026-07-02) — MTA dédié en périphérie, boîtes à l'intérieur. Le schéma ci-dessus (tout-en-un) est remplacé par le modèle ci-dessous.

   Internet ─▶ edge-mta : Postfix + rspamd     (EXPOSÉ, aucune boîte)
                    │  LMTP (remise) + SASL (auth) — réseau, mTLS step_ca
                    ▼
              mail-store : Dovecot IMAP + boîtes (INTERNE, non exposé)
                    │
              OpenLDAP · step_ca · PowerDNS
  • edge-mta (primaire) — Postfix (:25, soumission :587/:465) + rspamd (anti-spam, DKIM, greylisting). Exposé à Internet ; ne stocke aucune boîte. Auth des soumissions déléguée à Dovecot (SASL réseau) ; remise via LMTP réseau vers mail-store.
  • mail-store (interne) — Dovecot : IMAP :993, boîtes (Maildir), Sieve, auth LDAP. Non exposé au public ; ne parle qu'à edge-mta (LMTP + SASL) et aux clients IMAP internes. Expose LMTP + auth sur le réseau, chiffré par step_ca.
  • mta2 (MX de secours) — Postfix relais, :25 seulement ; file puis transfert quand edge-mta est down ; idéalement sur un lien/IP indépendant.

Séparation clé : le MTA (surface la plus exposée) est isolé des boîtes (données sensibles) ; le lien Postfix→Dovecot passe en réseau chiffré par step_ca — réutilise le mTLS.

Décisions ouvertes : emplacement du MX secours ; edge-mta co-localisé avec l'edge web ou non.

4. Stockage

  • v1 : stockage embarqué (RocksDB) sur mail-01 + sauvegardes rigoureuses. Simple et souverain. Le MX secours protège l'entrée, pas les boîtes → la résilience des données repose sur les sauvegardes.
  • HA ultérieure : métadonnées dans PostgreSQL (pilier existant) + blobs sur stockage partagé, pour un primaire plus stateless.

5. Flux

  • Entrant : expéditeur → MX DNS → mail-01 :25 (ou mail-02 si down) → contrôles SPF/DKIM/DMARC + anti-spam → livraison à la boîte (utilisateur résolu via LDAP).
  • Sortant : client authentifié (LDAP) → soumission :587 → signature DKIM → remise directe MX vers le serveur destinataire :25 (← PTR + réputation décisifs).
  • Accès client : client mail → IMAP :993 / JMAP :443 → auth LDAP → boîte.

6. TLS — deux CA distinctes (à ne pas confondre)

Face CA Pourquoi
Publique (25/465/587/993/443 vers le monde) Let's Encrypt (ACME intégré à Stalwart) Les serveurs et clients distants valident contre les racines publiques ; ils ne connaissent pas l'AC interne.
Interne (mail ↔ LDAP, ↔ PostgreSQL, ↔ MX secours) step_ca Le mTLS souverain déjà en place pour les liaisons internes.

7. Pare-feu (nftables)

Le socle installe nftables désactivé. Les nœuds mail sont un des endroits où on l'active avec des règles adaptées au rôle :

  • Ouvert au monde : 25, 465, 587, 993, 443, 80 (ACME).
  • Interne seulement : LDAP, PostgreSQL, interface d'admin Stalwart.

8. Enregistrements DNS publics (chezlepro.ca)

Gérés chez Namespro (registrar/DNS public), PAS dans PowerDNS (qui ne sert que l'interne). Un MX (mx → .53), un SPF (-all, correct) et un DMARC (quarantine) existent déjà — à reprendre/ajuster, pas à recréer. Le DKIM (default._domainkey vide) est à (re)poser.

mail1                 A     <IP publique mail-01>
mail2                 A     <IP publique mail-02>
@                     MX 10 mail1.chezlepro.ca.
@                     MX 20 mail2.chezlepro.ca.
@                     TXT   "v=spf1 mx -all"
default._domainkey    TXT   "v=DKIM1; k=rsa; p=<clé publique DKIM Stalwart>"
_dmarc                TXT   "v=DMARC1; p=quarantine; rua=mailto:dmarc@chezlepro.ca"
  • PTR (reverse) : <IP mail-01> → mail1.chezlepro.ca (chez le propriétaire de l'IP).
  • MTA-STS / TLS-RPT : optionnels, recommandés.

9. Traduction Set-OPS

  • Nomenclature : 2 fonctions, p. ex. comm-mail (primaire) + comm-mx2 (secours) ; VMID / IP / VLAN dérivés comme le reste.
  • Rôles (config 100 % par fichiers, comme nginx/powerdns) :
    • serveur_postfix — MTA : main.cf/master.cf, TLS step_ca, cartes LDAP (domaines, boîtes, alias), remise LMTP vers Dovecot, soumission :587/:465, milter rspamd.
    • serveur_dovecot — IMAP :993 + LMTP + Sieve, stockage des boîtes, auth SASL (pour la soumission Postfix), backend LDAP, TLS step_ca.
    • serveur_rspamd — anti-spam, signature DKIM, greylisting ; branché à Postfix par milter.
    • serveur_postfix en mode relais (paramètre) pour le MX de secours.
  • Intégrations des nœuds mail : client_pki (certs internes), client_backup, client_metrique / client_journal (observabilité). L'annuaire est résolu par resoudre_annuaire (côté rôle), pas une intégration OS.
  • Secrets (voûte) : bind LDAP, clé privée DKIM, éventuel secret ACME (Étape B) — via vault_*, câblés aux rôles.

10. Décisions

  • ✅ IP publique + PTR — TRANCHÉ : .53 FCrDNS OK, bloc Videotron contrôlé (§2).
  • ⬜ Emplacement du MX de secours (.55 existe ; lien/PTR à cadrer) (§3).
  • ⬜ Stockage : embarqué v1 vs PostgreSQL dès le départ (§4).
  • ⬜ Domaine(s) desservi(s) : chezlepro.ca seul, ou multi-domaines (tenants) ?
  • ⬜ Reprise du MX existant : bascule directe de .53 vers la nouvelle stack, ou cohabitation transitoire ?

11. Démarche en deux étapes

Étape A — Fonctionnement INTERNE (d'abord, sans risque)

But : prouver toute la pile en interne, en code de prod, dans le bac à sable. Aucune dépendance au public.

  1. Pilier identité : serveur_openldap (TLS step_ca) — ✅ déployé et prouvé.
  2. serveur_postfix + serveur_rspamd sur edge-mta-01, serveur_dovecot sur infra-mail-01 : TLS step_ca, annuaire/auth LDAP, DKIM, nftables mail — ✅ déployés.
  3. Prouver : réception → boîte → accès IMAP → envoi intra-écosystème, le tout en TLS interne, auth LDAP — ✅ prouvé de bout en bout, et rejoué à la demande par make courriel-plan, file d'attente comprise.

(Ce paragraphe disait « Étape actuelle : identité OK ; on démarre serveur_postfix » et plaçait toute la pile sur un mail-01 unique. La topologie retenue est celle du §3 révisé — le MTA en périphérie, les boîtes à l'intérieur — et l'Étape A est close.)

Étape B — Fonctionnement EXTERNE (transition prod, plus tard)

But : brancher sur le monde en reprenant l'existant (voir §2).

  1. Basculer le TLS des faces publiques sur Let's Encrypt (ACME).
  2. Reprendre mx.chezlepro.ca (.53) — préserve PTR/réputation déjà acquis.
  3. Mettre à jour les enregistrements chez Namespro : MX, DKIM (nouveau sélecteur), vérifier SPF/DMARC.
  4. MX secours .55 : PTR custom Videotron s'il doit émettre ; sinon réception/queue seulement.
  5. Tests bout en bout : envoi vers Gmail/Outlook, SPF/DKIM/DMARC verts, bascule MX secours.

Ce document est un cadrage vivant : il évolue à mesure que les décisions ouvertes se tranchent. L'Étape A qu'il décrit est livrée et prouvée ; la séquence ci-dessus, qui est l'Étape B, ne l'est pas.