- IP/PTR VÉRIFIÉ : mx.chezlepro.ca=69.70.26.53, FCrDNS OK, bloc Videotron contrôlé → make-or-break levé pour le primaire. - DNS public chez Namespro (pas PowerDNS) ; MX/SPF/DMARC existants à reprendre ; DKIM à (re)poser ; MX secours .55 à re-PTR s'il émet. - Phasage restructuré en deux étapes : (A) interne d'abord, (B) externe. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
185 lines
10 KiB
Markdown
185 lines
10 KiB
Markdown
# 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. |
|
|
| 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 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 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)│
|
|
│ 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`)
|
|
|
|
> **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** :
|
|
- `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
|
|
|
|
- ✅ **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 Stalwart, 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**) validé sur un nœud du bac à sable.
|
|
2. **`serveur_stalwart`** sur `mail-01` : TLS **step_ca** (mode `fichiers`), annuaire **LDAP**,
|
|
DKIM interne, nftables mail.
|
|
3. **Prouver** : réception → boîte → accès **IMAP/JMAP** → envoi **intra-écosystème**, le tout
|
|
en TLS interne, auth LDAP.
|
|
|
|
*(Étape actuelle : `serveur_openldap` écrit — reste à déployer/éprouver en bac à sable.)*
|
|
|
|
### É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é.*
|