diff --git a/CHANGELOG.md b/CHANGELOG.md index 6a9b834..65dabc3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,14 @@ # CHANGELOG — Set-OPS +## 2026-07-02 + +### Ajouté +- **`docs/courriel-conception.md`** — cadrage du futur service de courriel souverain : + full self-host, suite **Stalwart** (adoptée, enveloppée par un rôle mince), topologie + MX primaire + MX secours, intégration identité (LDAP) / DNS / PKI (Let's Encrypt public + vs step_ca interne), enregistrements DNS publics, décisions ouvertes (IP/PTR, secours, + stockage) et phasage. **Conception seulement — aucun rôle livré.** + ## 2026-07-01 ### Ajouté diff --git a/docs/courriel-conception.md b/docs/courriel-conception.md new file mode 100644 index 0000000..3a5eb4d --- /dev/null +++ b/docs/courriel-conception.md @@ -0,0 +1,150 @@ +# 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 `: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`) + +``` +mail1 A +mail2 A +@ MX 10 mail1.chezlepro.ca. +@ MX 20 mail2.chezlepro.ca. +@ TXT "v=spf1 mx -all" +default._domainkey TXT "v=DKIM1; k=rsa; p=" +_dmarc TXT "v=DMARC1; p=quarantine; rua=mailto:dmarc@chezlepro.ca" +``` ++ **PTR** (reverse) : `` → `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é.*