Set-OPS-Public/docs/courriel-conception.md
Daniel Allaire 1e2c323156 docs: cadrage du service de courriel souverain (Stalwart, full self-host)
Décisions : vrai service (boîtes/IMAP), full self-host, suite Stalwart
enveloppée par un rôle mince, identité via LDAP, PKI Let's Encrypt
(public) + step_ca (interne). Topologie MX primaire + MX secours,
enregistrements DNS publics, prérequis bloquant IP/PTR, décisions
ouvertes et phasage. Conception seulement.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-02 06:50:46 -04:00

7.8 KiB

Conception — Service de courriel souverain (Chezlepro)

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.
Suite Stalwart Mail Server (binaire unique Rust, AGPL ; SMTP/IMAP/JMAP/POP3 + anti-spam + DKIM intégrés). Adoptée et enveloppée par un rôle Set-OPS mince — pas de réimplémentation.
Identité Boîtes/utilisateurs dans l'OpenLDAP existant (annuaire Stalwart → 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.

Le rôle existant serveur_sendmail (relais sortant Postfix, sans boîtes) reste pour le courrier de notification système (via client_smtp/msmtp). Il ne fait pas partie de ce service et ne le remplace pas.

2. Prérequis BLOQUANT — l'IP publique

Le full self-host sortant est viable seulement si :

  • IP publique fixe avec un PTR (reverse DNS) contrôlé pointant vers mail1.chezlepro.ca ;
  • IP absente des listes noires (Spamhaus, etc.) ;
  • ports 25 / 465 / 587 / 993 / 443 / 80 routables vers les nœuds mail ;
  • SPF/DKIM/DMARC en place + réchauffement de réputation.

⚠️ Si l'IP de sortie ne peut pas avoir un PTR propre ou est sur une blocklist grand public, l'envoi vers Gmail/Outlook échouera — quelle que soit la suite. À vérifier AVANT toute implémentation.

Décision ouverte : quelle IP / quel hébergement portera le mail de prod ? (non tranché)

3. Topologie (2-3 nœuds)

                          INTERNET
                             │
        DNS public chezlepro.ca :  MX 10 → mail1 ,  MX 20 → mail2
                             │
             ┌───────────────┴───────────────┐
             ▼                                ▼
   ┌───────────────────┐            ┌───────────────────┐
   │ mail-01 (PRIMAIRE) │            │ mail-02 (MX secours)│
   │ Stalwart complet   │◄──relais──│ Stalwart mode relais│
   │ SMTP 25 / 587 / 465│  quand    │ SMTP 25 seulement   │
   │ IMAP 993 / JMAP 443│  mail-01  │ file d'attente puis │
   │ antispam + DKIM     │  est down │ transfert à mail-01 │
   │ BOÎTES stockées     │           └───────────────────┘
   └─────────┬──────────┘
             │ (réseau interne, mTLS step_ca)
     ┌───────┼─────────────┬──────────────┐
     ▼       ▼             ▼              ▼
  OpenLDAP  step_ca     PowerDNS      PostgreSQL
 (identité)(certs int.)(DNS interne)(métadonnées, option HA)
  • mail-01 (primaire) — Stalwart complet : réception :25, soumission authentifiée :587/:465, accès client IMAP :993 + JMAP/web :443, anti-spam, signature DKIM, hébergement des boîtes.
  • mail-02 (MX de secours) — Stalwart en mode relais, écoute seulement :25. Quand mail-01 est indisponible, accepte + met en file l'entrant, puis retransmet au rétablissement → zéro perte à l'entrée. À placer idéalement sur un lien/IP indépendant (autre site ou VPS), sinon la résilience est illusoire.

Décision ouverte : emplacement du MX secours (même cluster ? VPS ? autre site ?).

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)

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 :
    • serveur_stalwart — mince : installe le binaire Stalwart, dépose la config (annuaire LDAP, ACME public, DKIM, certs internes step_ca), unité systemd, règles nftables mail.
    • variante « relais » (ou paramètre du même rôle) pour le MX de secours.
  • Intégrations des nœuds mail : client_ldap (auth), client_pki (certs internes), client_dns.
  • Secrets (voûte) : clé/mots de passe d'admin Stalwart, éventuel secret ACME, clé privée DKIM — via vault_*, câblés au rôle (comme les autres secrets).

10. Décisions ouvertes (à trancher avant l'implémentation)

  1. IP publique + PTR de prod — le make-or-break (§2).
  2. Emplacement du MX de secours (§3).
  3. Stockage : embarqué v1 vs PostgreSQL dès le départ (§4).
  4. Domaine(s) desservi(s) : chezlepro.ca seul, ou multi-domaines (tenants) ?

11. Phasage proposé

  1. Vérifier l'IP/PTR (prérequis bloquant). Sans ça, rien.
  2. Écrire serveur_stalwart + le déployer sur mail-01 dans le bac à sable (interne d'abord, ACME en mode staging/interne).
  3. Brancher LDAP (auth), step_ca (interne), DKIM.
  4. Ajouter mail-02 (MX secours).
  5. Poser les enregistrements DNS publics + basculer l'ACME en production.
  6. Tests de bout en bout : réception, 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é.