Set-OPS-Public/docs/courriel-conception.md
Daniel Allaire ac85278366 preuve : P34 — chaque document declare son lecteur (D-74)
La refonte de ce matin posait une convention. Une convention qu'on n'outille
pas tient tant que quelqu'un y pense : c'est le raisonnement de D-70, applique
au corpus documentaire.

Etat de depart mesure : 2 documents sur 34 declaraient leur lecteur. Les 32
autres disaient leur SUJET — ce qui avait enfoui le runbook de reprise le plus
utile du depot au §6 de autorisation.md.

Les 38 le declarent desormais, lecteur determine document par document et non
colle au gabarit : l'exploitant (devis, migration de tenant, cycle de vie,
gabarit d'or), le mainteneur (conceptions, registres, carte), le lecteur
externe (ecosysteme-chezlepro), l'agent IA (MISE-A-JOUR-CODEX-CLAUDE).

Deux exemptions DERIVEES, pas listees — un chemin en dur aurait vieilli a la
premiere page ajoutee : un document qui s'annonce genere, et un fragment sans
titre. Les 13 exemptes verifies un par un ; aucun document ecrit a la main
n'est exempte par accident. La preuve ne lit que l'EN-TETE, ce qui empeche
frontiere-opnsense.md et plan-et-generation.md — qui parlent de generation
dans leur corps — d'etre exemptes a tort.

Eprouvee dans les deux sens. Elle a echoue seule des sa premiere execution en
nommant deux documents que mon inventaire avait manques (docs/audit/). Puis
test negatif delibere : declaration retiree de meta-classe.md -> ECHEC la
nommant ; restauree -> OK.

Ce qu'elle ne teste pas : que le lecteur declare soit le BON. Ca se juge en
revue ; elle garantit qu'on a du y penser.

P01–P34. Comptes perimes corriges au passage (AGENTS.md et devis-services.md
annoncaient encore 30 preuves).

Verifie : prouver.py 0 (34 OK), plan-recette inchange.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-10 07:53:04 -04:00

12 KiB

Conception — Service de courriel souverain (Chezlepro)

Pour qui : le mainteneur du service de courriel.

Statut : CONCEPTION (cadrage). Aucun rôle n'est encore écrit. Ce document fixe les décisions, les prérequis et la topologie avant toute implémentation.

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 :587signature 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é en bac à sable.
  2. serveur_postfix + serveur_dovecot + serveur_rspamd sur mail-01 : TLS step_ca, annuaire/auth LDAP, DKIM interne, nftables mail.
  3. Prouver : réception → boîte → accès IMAP → envoi intra-écosystème, le tout en TLS interne, auth LDAP.

(Étape actuelle : identité OK ; on démarre serveur_postfix.)

É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. Il ne décrit pas encore de code livré.