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>
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 applyannoncé 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ôleserveur_stalwart) est retirée ; git en garde la trace. Stalwart à réévaluer dans ~2 ans, une fois mûri et sonconfig applylivré.
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…), paslaposte-01.chezlepro.ca— à corriger s'il doit émettre.- DKIM : le sélecteur
default._domainkeyest 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 versmail-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,
:25seulement ; file puis transfert quandedge-mtaest 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._domainkeyvide) 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_postfixen 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 parresoudre_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É :
.53FCrDNS OK, bloc Videotron contrôlé (§2). - ⬜ Emplacement du MX de secours (
.55existe ; lien/PTR à cadrer) (§3). - ⬜ Stockage : embarqué v1 vs PostgreSQL dès le départ (§4).
- ⬜ Domaine(s) desservi(s) :
chezlepro.caseul, ou multi-domaines (tenants) ? - ⬜ Reprise du MX existant : bascule directe de
.53vers 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.
- Pilier identité :
serveur_openldap(TLS step_ca) — ✅ déployé et prouvé en bac à sable. serveur_postfix+serveur_dovecot+serveur_rspamdsurmail-01: TLS step_ca, annuaire/auth LDAP, DKIM interne, nftables mail.- 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).
- Basculer le TLS des faces publiques sur Let's Encrypt (ACME).
- Reprendre
mx.chezlepro.ca(.53) — préserve PTR/réputation déjà acquis. - Mettre à jour les enregistrements chez Namespro : MX, DKIM (nouveau sélecteur), vérifier SPF/DMARC.
- MX secours
.55: PTR custom Videotron s'il doit émettre ; sinon réception/queue seulement. - 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é.