Merge branch 'orgmode_to_markdown' into 'master'
Orgmode to markdown See merge request nounous/documentation!21
commit
f03ab336b1
|
@ -0,0 +1,435 @@
|
|||
# Résumé
|
||||
|
||||
## Objectif du document
|
||||
|
||||
Description de plusieurs RFC intéressantes (ou non) autour des protocoles liés
|
||||
aux emails. Lorsque ces normes sont en application au Cr@ns (ou ont
|
||||
volontairement été repoussées à plus tard), les solutions techniques étudiées
|
||||
seront décrites.
|
||||
|
||||
*Remarques préalables :*
|
||||
|
||||
- SMTP est un protocole incontournable car largement utilisé. Malgré tous ses
|
||||
défauts, il restera important pendant un bon bout de temps. Pour cette raison,
|
||||
de nombreuses personnes ont cherché à augmenter la sécurité des emails tant
|
||||
bien que mal, en proposant de chiffrer les mails qui transitent d'un MTA à un
|
||||
autre, signant les mails émis par un serveur,... Toutes ces techniques sont
|
||||
mises en place autour du protocole mail, lequel ne change pas.
|
||||
- Aujourd'hui, certains organismes influents ont le bon goût de rejeter les
|
||||
mails issus de serveurs n'implémentant pas les protocoles les plus
|
||||
importants. Quoi que l'on pense du poids de l'influence des géants, cela
|
||||
permet d'élever les standards qualités des autres. Serons-nous un jour
|
||||
spam-free ? Les publicités mentionnant nos informations personnelles (nom,
|
||||
préférences, ...) seront-elles un jour toutes chiffrées ? Je ne sais pas,
|
||||
mais je l'espère haha.
|
||||
|
||||
## Au Cr@ns
|
||||
|
||||
| | Statut au Cr@ns ? | Adoption |
|
||||
|---------|-------------------|------------------------------------|
|
||||
| SPF | Implémenté | Large |
|
||||
| DKIM | Implémenté | Large |
|
||||
| SRS | Implémenté | ? |
|
||||
| DMARC | Non-implémenté | Large |
|
||||
| ARC | Non-implémenté | ? (Google l'utilise) |
|
||||
| MTA-STS | Non-implémenté | ? (MS, Méta et Google l'utilisent) |
|
||||
| DANE | Non-implémenté | Faible (requiert DNSSEC) |
|
||||
|
||||
Tous ce qui est discuté ci-dessous fonctionne de la manière suivante :
|
||||
|
||||
- l'infrastructure émettrice (le Cr@ns) publie des informations la concernant,
|
||||
- les serveurs réceptionnant les mails (les `MX` des destinataires
|
||||
des mails émis par
|
||||
le Cr@ns) peuvent vérifier les mails à l'aide de ces informations.
|
||||
|
||||
*NB :* je parle d'infrastructure ou d'organisation émettrice et non pas de serveur
|
||||
émetteur car plus d'un serveur est souvent requis (*e.g.* un serveur DNS
|
||||
autoritaire, un serveur Web,...).
|
||||
|
||||
## SPF
|
||||
|
||||
- [SPF](https://www.rfc-editor.org/rfc/rfc7208),
|
||||
- [Page Wikipédia](https://en.wikipedia.org/wiki/Sender_Policy_Framework).
|
||||
|
||||
Le SPF (*Sender Policy Framework*) permet d'indiquer quels serveurs ont le droit
|
||||
d'émettre des mails en `crans.org` (ou tout autre domaine, bien entendu).
|
||||
|
||||
### Implémentation (côté infrastructure émettrice)
|
||||
|
||||
Pour cela, nous publions un champ `TXT` pour `crans.org`. Voici le contenu que l'on
|
||||
obtient pour quelques associations avec `kdig -t TXT crans.org` (`dig`
|
||||
peut être utilisé à la place de `kdig`) :
|
||||
|
||||
Au Cr@ns :
|
||||
|
||||
```txt
|
||||
v=spf1 mx ip4:185.230.79.1 ip6:2a0c:700:2:0:ec4:7aff:fe59:a1ad ip4:185.230.79.38
|
||||
ip6:2a0c:700:2::ff:fe01:3502 ~all
|
||||
```
|
||||
|
||||
Cela signifie que les serveurs mail du Cr@ns (`mx`) et les adresses listées (et
|
||||
celles-ci uniquement) ont le droit d'envoyer des mails dont la source
|
||||
prétendue est *...@crans.org*.
|
||||
|
||||
Utiliser `~all` permet d'indiquer que si un mail provient d'une autre IP, il ne
|
||||
faut pas rejeter le mail, mais le mettre en *permerror*.
|
||||
|
||||
À l'April :
|
||||
|
||||
```txt
|
||||
v=spf1 include:spf.mailjet.com mx ip4:62.73.5.35 include:spf.protection.outlook.com include:_spf.april.com ip4:37.71.69.68 ip4:37.71.69.69 ip4:37.71.69.70 include:_spf.salesforce.com -all
|
||||
```
|
||||
|
||||
Idem, avec des champs `include:...` en plus. Ces derniers permettent d'inclure
|
||||
un autre enregistrement SPF (*e.g.* celui de `spf.mailjet.com`).
|
||||
|
||||
Utiliser `-all` permet de demander aux serveurs récepteurs de rejeter tout mail
|
||||
ne satisfaisant pas ce test.
|
||||
C'est une politique plus sévère que `~all`, qui a l'avantage de
|
||||
filtrer plus efficacement les mails douteux et l'inconvénient
|
||||
de risquer des pertes de mails plus ou moins importants,
|
||||
en tout cas légitimes, émis par des domaines configurés
|
||||
avec un respect des standards mail plus léger.
|
||||
|
||||
D'autres mécanismes et formats existent, mais nous ne les présentons pas
|
||||
ici. Se référer à la RFC ou la page Wikipédia pour leur description.
|
||||
|
||||
### Vérification (côté serveur récepteur)
|
||||
|
||||
Lorsque `redisdead` (le `MX` du Cr@ns) reçoit un mail, nous demandons à un service
|
||||
externe de vérifier le SPF (via la variable `smtpd_recipient_restrictions`). Le
|
||||
service externe tourne sur la même VM et est `postfix-policyd-spf-python`.
|
||||
|
||||
## SRS
|
||||
|
||||
- [Le papier d'origine](https://www.libsrs2.org/srs/srs.pdf),
|
||||
- [La page Wikipédia](https://en.wikipedia.org/wiki/Sender_Rewriting_Scheme).
|
||||
|
||||
Au Cr@ns comme ailleurs, on aime bien les mailing-lists
|
||||
et les transferts automatiques de mails par `.forward`.
|
||||
Le problème, c'est qu'intercaler un serveur entre l'expéditeur et
|
||||
le destinataire final est parfois peu distingable d'une usurpation.
|
||||
|
||||
Cas d'usage : un expéditeur envoie un mail à une mailing-list (du Cr@ns),
|
||||
qui retransmet aux adresses abonnées, qu'elles soient ou non au Cr@ns.
|
||||
Un problème survient, empêchant un abonné de recevoir le mail
|
||||
(à tout hasard, le quota de stockage est dépassé).
|
||||
Ce problème génère un *bounce*, un mail automatique d'erreur.
|
||||
|
||||
Question : qui doit recevoir ce *bounce* ?
|
||||
Logiquement, l'expéditeur d'origine, c'est lui qui a envie
|
||||
de savoir qu'un destinataire n'a pas lu son message.
|
||||
|
||||
Pour cela, le serveur intermédiaire va conserver le champ `Envelope-From`
|
||||
d'origine et passer le mail tel quel au serveur final.
|
||||
Or, ce choix bien intentionné se heurte, comme annoncé,
|
||||
aux politiques anti-usurpation à base de `SPF`.
|
||||
Si le serveur de l'expéditeur applique une politique `SPF`
|
||||
strice (`-all`) et que le serveur d'arrivée suit les instructions,
|
||||
le mail transféré sera refusé en raison de son champ `SPF` invalide.
|
||||
|
||||
Comment faire ? Réfléchissons à partir de nos contraintes :
|
||||
dans le pire des cas, on doit s'adapter à une politique `SPF`
|
||||
stricte pour ne perdre aucun mail d'adhérent.
|
||||
On doit donc montrer patte blanche en transférant le mail
|
||||
avec un champ `Envelope-From` dans notre domaine,
|
||||
de sorte que le mail soit accepté à l'arrivée.
|
||||
|
||||
Conséquence : c'est à nous que reviendront les
|
||||
éventuels *bounces* qui nous motivaient à l'origine.
|
||||
Sauf qu'ils ne nous intéressent pas directement,
|
||||
on doit trouver un moyen de les renvoyer à l'expéditeur.
|
||||
|
||||
C'est là que `SRS` entre en jeu : il fabrique,
|
||||
en suivant un schéma de nommage normalisé,
|
||||
une adresse temporaire qui va encoder l'adresse de
|
||||
l'expéditeur d'origine, plus quelques métadonnées,
|
||||
dans la partie "compte" (avant le `@`) de l'adresse fabriquée.
|
||||
|
||||
Prenons un exemple, éhontément pris de la page Wikipédia.
|
||||
Alice, détentrice de l'adresse `alice@nane.in`,
|
||||
veut envoyer un mail à son ami Bob, détenteur de
|
||||
l'adresse `bob@crans.org`.
|
||||
Ce qu'Alice ne sait pas (et n'a pas besoin de savoir),
|
||||
c'est que Bob est en train de passer ses contacts
|
||||
sur son adresse ENS, `bob@ens-cachan.fr`.
|
||||
Il transfère donc tous ses mails Cr@ns vers sa
|
||||
boîte ENS, sans avoir besoin de prévenir qui que ce soit.
|
||||
|
||||
À la réception d'un mail d'Alice, le serveur du Cr@ns (`redisdead`)
|
||||
va lire l'instruction de forwarding de Bob et va changer le champ
|
||||
`Envelope-From` de `alice@nane.in` (origine) à
|
||||
`SRS0=HHH=TT=nane.in=alice@crans.org`.
|
||||
Le `HHH` est un hash d'identification, le `TT`
|
||||
un marqueur temporel.
|
||||
|
||||
Si la boîte mail ENS de Bob est pleine, le *bounce* part sur
|
||||
l'adresse `SRS` et est ensuite retransféré à Alice, dont
|
||||
l'adresse est clairement extractible de l'adresse `SRS`.
|
||||
Et voilà !
|
||||
|
||||
*Note :* les adresses générées par `postsrsd` sont valides pendant 21 jours.
|
||||
|
||||
*Note 2 :* si un utilisateur a l'idée saugrenue de prendre
|
||||
un alias commençant par `SRS0=`, on va peut-être avoir un problème.
|
||||
Prions pour que ça n'arrive pas.
|
||||
|
||||
### Implémentation
|
||||
|
||||
TODO
|
||||
|
||||
## DKIM
|
||||
|
||||
- [La RFC](https://www.rfc-editor.org/rfc/rfc6376.html),
|
||||
- [La page Wikipédia](https://en.wikipedia.org/wiki/DomainKeys_Identified_Mail).
|
||||
|
||||
Le protocole DKIM (*Domain Key Identified Mail*) permet au serveur
|
||||
émetteur de signer les
|
||||
mails, et au serveur récepteur de vérifier cette signature, en utilisant des
|
||||
méthodes de cryptographie asymétrique.
|
||||
|
||||
### Implémentation (côté émetteur)
|
||||
|
||||
#### Serveur mail
|
||||
|
||||
Le serveur émetteur possède la clef privée. Il ajoute à tout mail sortant un
|
||||
champ à l'en-tête de la forme suivante :
|
||||
|
||||
```txt
|
||||
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=crans.org; s=mail;
|
||||
t=1702660809; bh=NqcDLO2gkZU0IxcV+mE7uZ2NRnN/yfceH73Q1nhaFg4=;
|
||||
h=From:To:Subject:Date:From;
|
||||
b=ZjomU0jkljKVwA6sUhUioCemnxh/OhSGgwwr57irEn39Gfbv8/cLF8jmHc3hmv4ly
|
||||
fLvJdj7iVTkeGlTVeW72H93wEA0qrB6LHHz81YBeHPb8eg63zm+9soDSOaP91Gux8J
|
||||
UgeY1PWXvfjdfe+MJX9JqnlBKqd4JRgpD8AXaO852Lrq+fLJy4ewLOc/3dAqpNMrTf
|
||||
swi5y6vV5QH89cuFjpjWqF3UcuD4a20RCQIpU/j5K1sxr1CTbdKjgqlsq5mt9/JSKx
|
||||
OcvZ5WTmgPwdimKKz0DfjAeXQBMac9d7V9Kb5LvCZx84kSbLQEKboGxpRRhNWGdBsK
|
||||
f3YZXjmpe8cl8cpbvuvdKYWOE7E6fRGu/CwQEyEQYqmrmljiklSYPaG8IKs5uYWKrA
|
||||
A2D4VTisIYOwGvdljFTQP5zfhPsi4OnNbiN3RVX475lCHNWbnFMh8OCF/ugLj30dyk
|
||||
s8MLAzDyYlgaccOD0uZ6VsdGJ0LK8+TCKbsc5H1ynjg0VejmRyVzZJ5TzAjXrzS6CC
|
||||
Lj9eQQex1IaO6d7uGe4P/ULghjSP90tgBcZVNFLlU3r59ylkVQyAu7THDr4CDaxFO0
|
||||
63QE7/GNDE2vZv0K5gp5Yz2veVC3wyaP1dJzIoAzZc1kZRoWz6QK9cH1Bfmnlx9nUs
|
||||
j+G+VLDQbxi2NuoYAD/I2naA=
|
||||
```
|
||||
|
||||
Le bloc contient une liste de clefs-valeurs :
|
||||
|
||||
- `v` indique la version du protocole,
|
||||
- `d` le domaine attestant de la validité du mail,
|
||||
- `s` le nom du sélecteur (/Cf/. plus bas),
|
||||
- `b` et `bh` contiennent les signatures.
|
||||
|
||||
*Notes :*
|
||||
|
||||
- Il est possible que le mail ne soit pas signé par le domaine correspondant à
|
||||
l'adresse d'envoi, puisqu'il est possible d'autoriser autrui à envoyer un
|
||||
mail à notre place (*cf*. SPF plus haut).
|
||||
- Se référer à la page Wikipédia, ou à la RFC pour une liste exhaustive des
|
||||
clefs.
|
||||
|
||||
#### Serveur DNS
|
||||
|
||||
Il faut placer dans le serveur DNS un champ TXT dont la clef est
|
||||
`sélecteur._domainkey.domain`, où `domain` (resp. `sélecteur`) est la valeur de la
|
||||
clef `d` (resp. `s`) définie plus haut.
|
||||
|
||||
Par exemple, pour le champ fourni plus haut, nous pouvons lire :
|
||||
|
||||
```txt
|
||||
"v=DKIM1; k=rsa; "
|
||||
"p=MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAtwkNVd9Mmz8S4WcfuPk0X2drG39gS8" "
|
||||
+uxAv8igRILgzWeN8j2hjeZesl8pm/1UTVU87bYcdfUgXiGfQy9nR5p/Vmt2kS7sXk9nsJ/VYENg"
|
||||
"b3IJQ6paWupSTFMyeKycJ4ZHCEZB/bVvifoG6vLKqW5jpsfCiOcfdcgXATn0UPuVx9t93yRrhoEM"
|
||||
"ntMv9TSodjqd3FKCtJUoh5cNQHo0T6dWKtxoIgNi/mvZ92D/IACwu/XOU+Rq9fnoEI8GukBQUR5A" "kP0B/
|
||||
JrvwWXWX/3EjY8X37ljEX0XUdq/ShzTl5iK+CM83stgkFUQh/rpww5mnxYEW3X4uirJ7VJH" "mY4KPoIU
|
||||
+2DPjLQj9Hz63CMWY3Ks2pXWzxD3V+GI1aJTMFOv2LeHnI3ScqFaKj9FR4ZKMb0OW2BE" "FBIY3J3aeo/
|
||||
paRwdbVCMM7twDtZY9uInR/NhVa1v9hlOxwp4/2pGSKQYoN2CkAZ1Alzwf8M3EONL"
|
||||
"KeiC43JLYwKH1uBB1oikSVhMnLjG0219XvfG/tphyoOqJR/bCc2rdv5pLwKUl4wVuygfpvOw12bc" "vnTfYuk/
|
||||
BXzVHg9t4H8k/DJR6GAoeNAapXIS8AfAScF8QdKfplhKLJyQGJ6lQ75YD9IwRAN0oV+8" "NTjl46lI/C
|
||||
+b7mpfXCew+p6YPwfNvV2shiR0Ez8ZGUQIcCAwEAAQ=="
|
||||
```
|
||||
|
||||
### Vérification (côté récepteur)
|
||||
|
||||
Côté réception (`redisdead` pour nous), nous utilisons le milter (filtre pour
|
||||
mail) fourni par `opendkim`. Ce milter écoute en local et est appelé par `postfix`.
|
||||
Lors de la réception d'un mail, postfix demande à `opendkim` quelle décision
|
||||
prendre. Ce dernier va regarder les en-têtes du mail. Si il trouve une signature
|
||||
DKIM, il va effectuer la requête DNS décrite plus haut et vérifier la signature
|
||||
du mail (valeurs des clefs `b` et `bh`).
|
||||
|
||||
## DMARC
|
||||
|
||||
- [La RFC](https://www.rfc-editor.org/rfc/rfc7489),
|
||||
- [La page Wikipédia](https://en.wikipedia.org/wiki/DMARC).
|
||||
|
||||
## ARC
|
||||
|
||||
- [La RFC](https://www.rfc-editor.org/rfc/rfc8617.html),
|
||||
- [La page Wikipédia](https://en.wikipedia.org/wiki/Authenticated_Received_Chain).
|
||||
|
||||
## MTA-STS
|
||||
|
||||
- [La RFC](https://datatracker.ietf.org/doc/html/rfc8461),
|
||||
- [La page Wikipédia](https://en.wikipedia.org/wiki/Simple_Mail_Transfer_Protocol#SMTP_MTA_Strict_Transport_Security).
|
||||
|
||||
Le MTA-STS consiste à publier les protocoles de sécurité supportés par les
|
||||
serveur mail d'un certain domaine (pour nous, les mails en `@crans.org`).
|
||||
|
||||
Contrairement au `DANE` (décrit plus bas), ce protocole ne demande pas la mise en
|
||||
place de DNSSEC. En revanche, il demande d'avoir un serveur Web accessible en
|
||||
`https` (pour nous, `https://crans.org` doit être servi par un serveur Web).
|
||||
|
||||
### Implémentation (côté infrastructure émettrice)
|
||||
|
||||
#### Dans la zone DNS
|
||||
|
||||
Il faut ajouter un champ `TXT` accessible à `_mts-sts.domain.tld`.
|
||||
|
||||
Quelques exemples :
|
||||
|
||||
- Gmail : `v=STSv1; id=20190429T010101;`,
|
||||
- Microsoft : `v=STSv1; id=20190225000000Z;`,
|
||||
- Outlook : `v=STSv1; id=20190225000000Z;`.
|
||||
|
||||
#### Sur le serveur Web
|
||||
|
||||
Il faut que le serveur Web associé serve un fichier texte accessible à l'adresse
|
||||
`https://mta-sts.domain.tld/.well-known/mta-sts.txt`
|
||||
|
||||
Quelques exemples :
|
||||
|
||||
- [Gmail](https://mta-sts.gmail.com/.well-known/mta-sts.txt),
|
||||
- [Outlook](https://mta-sts.outlook.com/.well-known/mta-sts.txt),
|
||||
- [Microsoft](https://mta-sts.microsoft.com/.well-known/mta-sts.txt).
|
||||
|
||||
Le fichier texte contient une liste de clefs-valeurs. Ces clefs décrivent quel
|
||||
protocole sera utilisé.
|
||||
|
||||
### Vérification côté récepteur
|
||||
|
||||
Est-il possible d'utiliser `postfix-mta-sts-resolver` ? N'ayant pas implémenté cette
|
||||
solution pour le moment (ni au Cr@ns, ni personnellement), nous ne pouvons pas
|
||||
commenter sur le sujet.
|
||||
|
||||
## DANE
|
||||
|
||||
- [La RFC](https://www.rfc-editor.org/rfc/rfc6698),
|
||||
- [La page Wikipédia](https://en.wikipedia.org/wiki/DNS-based_Authentication_of_Named_Entities).
|
||||
|
||||
Actuellement, pour vérifier un certificat `C` proposé par un serveur mail, il faut
|
||||
faire confiance à un certificat racine, lequel est utilisé pour signer un autre
|
||||
certificat (dit *certificat intermédiaire*), lequel est utilisé pour signer le
|
||||
certificat `C`. Pour vérifier `C`, il faut
|
||||
|
||||
- faire confiance au certificat racine,
|
||||
- vérifier les deux signatures sus-mentionnées.
|
||||
|
||||
`DANE` est une norme permettant aux propriétaires de domaines de déclarer quels
|
||||
cetificats doivent être acceptés pour quels services.
|
||||
|
||||
*Note :* cela n'est pas spécifique aux mails.
|
||||
|
||||
### Implémentation (côté infrastructure émettrice)
|
||||
|
||||
Pour mettre en place `DANE`, il suffit d'ajouter un champ DNS à sa zone :
|
||||
|
||||
- Il faut que la zone soit signée DNSSEC.
|
||||
- Le champ à ajouter est :
|
||||
- de type TLSA (TLS Authentication),
|
||||
- de clef `_port._protoL4.domain.tld`.
|
||||
- de valeur `x y z t`, où :
|
||||
- `x` est appelé `certificate usage`,
|
||||
- `y` est appelé `selector`,
|
||||
- `z` est appelé `matching type`,
|
||||
- `t` est appelé `certificate associated data`.
|
||||
|
||||
### Format du champ TLSA
|
||||
|
||||
#### Certificate usage
|
||||
|
||||
L'objectif de ce champ est d'indiquer comment vérifier le certificat.
|
||||
|
||||
| *Valeur* | *Signification* |
|
||||
|--------|----------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| 0 | Le certificat doit être valide (`root` -> `intermediate` -> `cert`), et `associated data` décrit l'un des certificats parents de `cert` |
|
||||
| 1 | `associated data` décrit `cert`, et le certificat doit aussi être valide par rapport à un certificat racine de confiance. |
|
||||
| 2 | `associated data` décrit un parent de `cert`. Ce parent est supposé de confiance, et `cert` doit bien être son descendant. |
|
||||
| 3 | `associated data` décrit `cert`. Le certificat n'a pas besoin d'être valide par rapport à un certificat racine. Il a simplement besoin de correspondre à `associated data`. |
|
||||
|
||||
#### Selector
|
||||
|
||||
Ce champ décrit ce qui est décrit par `associated data`.
|
||||
|
||||
| *Valeur* | *Signification* |
|
||||
|--------|-----------------------------|
|
||||
| 0 | Tout le certificat. |
|
||||
| 1 | Seulement la clef publique. |
|
||||
|
||||
#### Matching type
|
||||
|
||||
Ce champ indique comment vérifier `associated data` contre la donnée du certificat
|
||||
(ou de la clef publique).
|
||||
|
||||
| *Valeur* | *Signification* |
|
||||
|--------|--------------------------------------------------------|
|
||||
| 0 | `associated data` doit être égal à la donnée. |
|
||||
| 1 | `associated data` doit être égal au sha256 de la donnée. |
|
||||
| 2 | `associated data` doit être égal au sha512 de la donnée. |
|
||||
|
||||
où la donnée est décrite par le `selector` et le choix de certificat décrit par
|
||||
le `certificate usage`.
|
||||
|
||||
#### Certificate associated data
|
||||
|
||||
Chaîne de caractères au format hexadécimal.
|
||||
|
||||
### Recommandation pour le Cr@ns
|
||||
|
||||
À titre personnel, j'utilise des champs TLSA en `3 0 1`. Je pense que le Cr@ns
|
||||
peut faire la même chose (ou du `3 0 2`).
|
||||
|
||||
### Mise en place
|
||||
|
||||
Hypothèses :
|
||||
|
||||
- le serveur DNS accepte des mises à jour DNS dynamiques de la part du serveur
|
||||
mail,
|
||||
- le renouvellement du certificat utilise `certbot`.
|
||||
|
||||
Mise en place :
|
||||
|
||||
- Dans la confguration `certbot`,
|
||||
- passer en challenge DNS-01 et :
|
||||
- `manual_auth_hook` : un script mettant en place le challenge,
|
||||
- `renew_hook` : script de déploiement du certificat, lequel *ajoute* un champ
|
||||
TLSA et place le certificat à déployer dans un dossier "staging",
|
||||
- `manual_cleanup_hook` : un script retirant le challenge `acme`.
|
||||
- Roll-over scheme : Un champ DNS a une durée de vie (TTL), généralement 1h. De
|
||||
ce fait, les requêtes de chalmp TLSA peuvent être en retard d'une heure (au
|
||||
plus). Il est done conseillé d'avoir le nouveau champ TLSA en place pendant
|
||||
deux TTL avant de (1) mettre en place le nouveau certificat et (2) retirer le
|
||||
vieux champ TLSA.
|
||||
|
||||
Je propose de mettre en place un timer `systemd` qui serait activé "après
|
||||
l'arrêt de `certbot` pour plus de 2 TTLs". Ce timer lancerait un service, lequel
|
||||
aurait une condition d'activation "un certificat existe dans le dossier
|
||||
staging".
|
||||
|
||||
### Exemple
|
||||
|
||||
```txt
|
||||
dig +short TLSA _25._tcp.nanein.fr
|
||||
=> 3 0 1 50E9221F066DCD1991ED9D3BA0AD10159F3585780F6FABBAE2942E43 37789FC8
|
||||
```
|
||||
|
||||
### Implémentation (côté serveur mail destinataire)
|
||||
|
||||
Côté serveur mail destinataire, la configuration est très simple (car nous
|
||||
utilisons Postfix). Cela se fait principalement via les options suivantes :
|
||||
|
||||
- `smtp_dns_supoprt_level` (valeur `dnssec`)
|
||||
- `smtp_tls_dane_insecure_mx_policy` (valeur `dane`)
|
||||
|
||||
D'autres options de Postfix peuvent être utilisées pour permettre un contrôle
|
||||
plus fin sur le comportement du service.
|
|
@ -1,355 +0,0 @@
|
|||
-*- mode: org; org-hide-emphasis-markers: t; -*-
|
||||
|
||||
#+TITLE: Description de normes autour des emails.
|
||||
#+AUTHOR: Des nounous quelconques.
|
||||
#+EMAIL: contact@crans.org
|
||||
#+SEQ_TODO: TODO | in_progress | DONE
|
||||
#+DESCRIPTION: Pfiou que c'est fastidieux d'apprendre à parler au monde entier.
|
||||
#+INSTITUTE: Cr@ns
|
||||
#+LANGUAGE: fr
|
||||
#+STARTUP: overview
|
||||
#+OPTIONS: broken-links:t
|
||||
|
||||
* Résumé
|
||||
|
||||
** Objectif du doc
|
||||
|
||||
Description de plusieurs RFC intéressantes (ou non) autour des protocoles liés
|
||||
aux emails. Lorsque ces normes sont en application au Cr@ns (ou ont
|
||||
volontairement été repoussées à plus tard), les solutions techniques étudiées
|
||||
seront décrites.
|
||||
|
||||
/Remarques préalables/ :
|
||||
|
||||
- SMTP est un protocole incontournable car largement utilisé. Malgré tous ses
|
||||
défauts, il restera important pendant un bon bout de temps. Pour cette raison,
|
||||
de nombreuses personnes ont cherché à augmenter la sécurité des emails tant
|
||||
bien que mal, en proposant de chiffrer les mails qui transitent d'un MTA à un
|
||||
autre, signant les mails émis par un serveur, ... Toutes ces techniques sont
|
||||
mises en place autour du protocole mail, lequel ne change pas.
|
||||
|
||||
- Aujourd'hui, certains organismes influents ont le bon goût de rejeter les
|
||||
mails issus de serveurs n'implémentant pas les protocoles les plus
|
||||
importants. Quoi que l'on pense du poids de l'influence des géants, cela
|
||||
permet d'élever les standards qualités des autres. Serons-nous un jour
|
||||
spam-free ? Les publicités mentionnant nos informations personnelles (nom,
|
||||
préférences, ...) seront-elles un jour toutes chiffrées ? Je ne sais pas,
|
||||
mais je l'espère haha.
|
||||
|
||||
** Au Cr@ns
|
||||
|
||||
| | /Statut au Cr@ns/ ? | Adoption |
|
||||
|---------+-------------------+------------------------------------|
|
||||
| SPF | Implémenté | Large |
|
||||
| DKIM | Implémenté | Large |
|
||||
| SRS | Implémenté | ? |
|
||||
| DMARC | Non-implémenté | Large |
|
||||
| ARC | Non-implémenté | ? (Google l'utilise) |
|
||||
| MTA-STS | Non-implémenté | ? (MS, Méta et Google l'utilisent) |
|
||||
| DANE | Non-implémenté | Faible (requiert DNSSEC) |
|
||||
|
||||
Tous ce qui est discuté ci-dessous fonctionne de la manière suivante :
|
||||
- l'infrastructure émettrice (le Cr@ns) publie des informations la concernant,
|
||||
- les serveurs réceptionnant les mails (~MX~ des destinataires des mails émis par
|
||||
le Cr@ns) peuvent vérifier les mails à l'aide de ces informations.
|
||||
|
||||
/NB/ : Je parle d'infrastructure ou d'organisation émettrice et non pas de serveur
|
||||
émetteur car plus d'un service est souvent requis (/e.g./ un serveur DNS
|
||||
autoritaire, un serveur Web, ...).
|
||||
|
||||
|
||||
* SPF
|
||||
|
||||
- [[https://www.rfc-editor.org/rfc/rfc7208][SPF]],
|
||||
- [[https://en.wikipedia.org/wiki/Sender_Policy_Framework][Page Wikipédia]].
|
||||
|
||||
Le SPF (/Sender Policy Framework/) permet d'indiquer quels serveurs ont le droit
|
||||
d'émettre des mails en ~crans.org~ (ou tout autre domaine, bien entendu).
|
||||
|
||||
** Implémentation (côté infrastructure émettrice)
|
||||
|
||||
Pour cela, nous publions un champ ~TXT~ pour ~crans.org~. Voici le contenu que l'on
|
||||
obtient pour quelques associations (obtenues avec ~kdig -t TXT crans.org~ (~dig~
|
||||
peut être utilisé à la place de ~kdig~) :
|
||||
|
||||
- Cr@ns: ~v=spf1 mx ip4:185.230.79.1 ip6:2a0c:700:2:0:ec4:7aff:fe59:a1ad ip4:185.230.79.38 ip6:2a0c:700:2::ff:fe01:3502 ~all~
|
||||
|
||||
Cela signifie que les serveurs mail du Cr@ns (~mx~) et les adresses listées (et
|
||||
celles-ci uniquement) ont le droit d'envoyer des mails dont la source
|
||||
prétendue est /...@crans.org/.
|
||||
|
||||
Utiliser /~all/ permet d'indiquer que si un mail provient d'une autre IP, il ne
|
||||
faut pas rejeter le mail, mais le mettre en /permerror/.
|
||||
|
||||
- April: ~v=spf1 include:spf.mailjet.com mx ip4:62.73.5.35 include:spf.protection.outlook.com include:_spf.april.com ip4:37.71.69.68 ip4:37.71.69.69 ip4:37.71.69.70 include:_spf.salesforce.com -all~
|
||||
|
||||
Idem, avec des champs ~include:...~ en plus. Ces derniers permettent d'inclure
|
||||
un autre enregistrement SPF (/e.g./ celui de ~spf.mailjet.com~).
|
||||
|
||||
Utiliser ~-all~ permet de demander aux serveurs récepteurs de rejeter tout mail
|
||||
ne satisfaisant pas ce test.
|
||||
|
||||
D'autres mécanismes et formats existent, mais nous ne les présentons pas
|
||||
ici. Se référer à la RFC ou la page Wikipédia pour leur description.
|
||||
|
||||
|
||||
** Vérification (côté serveur récepteur)
|
||||
|
||||
Lorsque ~redisdead~ (~MX~ du Cr@ns) reçoit un mail, nous demandons à un service
|
||||
externe de vérifier le SPF (via la variable ~smtpd_recipient_restrictions~). Le
|
||||
service externe tourne sur la même VM et est ~postfix-policyd-spf-python~.
|
||||
|
||||
|
||||
|
||||
* TODO SRS
|
||||
|
||||
- [[https://www.libsrs2.org/srs/srs.pdf][Papier]],
|
||||
- [[https://en.wikipedia.org/wiki/Sender_Rewriting_Scheme][Page Wikipédia]].
|
||||
|
||||
/Note/ : Les adresses générées par ~postsrsd~ sont valides pendant 21 jours.
|
||||
|
||||
|
||||
* DKIM
|
||||
|
||||
- [[https://www.rfc-editor.org/rfc/rfc6376.html][RFC]].
|
||||
- [[https://en.wikipedia.org/wiki/DomainKeys_Identified_Mail][Page Wikipedia]].
|
||||
|
||||
DKIM (/Domain Key Identified Mail/) permet au serveur émetteur de signer les
|
||||
mails, et au serveur récepteur de vérifier cette signature, en utilisant des
|
||||
méthodes de cryptologie asymétrique.
|
||||
|
||||
** Implémentation (côté émetteur)
|
||||
|
||||
*** Serveur Mail
|
||||
|
||||
Le serveur émetteur possède la clef privée. Il ajoute à tout mail sortant un
|
||||
champ à l'en-tête de la forme suivante :
|
||||
#+begin_src mail
|
||||
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=crans.org; s=mail;
|
||||
t=1702660809; bh=NqcDLO2gkZU0IxcV+mE7uZ2NRnN/yfceH73Q1nhaFg4=;
|
||||
h=From:To:Subject:Date:From;
|
||||
b=ZjomU0jkljKVwA6sUhUioCemnxh/OhSGgwwr57irEn39Gfbv8/cLF8jmHc3hmv4ly
|
||||
fLvJdj7iVTkeGlTVeW72H93wEA0qrB6LHHz81YBeHPb8eg63zm+9soDSOaP91Gux8J
|
||||
UgeY1PWXvfjdfe+MJX9JqnlBKqd4JRgpD8AXaO852Lrq+fLJy4ewLOc/3dAqpNMrTf
|
||||
swi5y6vV5QH89cuFjpjWqF3UcuD4a20RCQIpU/j5K1sxr1CTbdKjgqlsq5mt9/JSKx
|
||||
OcvZ5WTmgPwdimKKz0DfjAeXQBMac9d7V9Kb5LvCZx84kSbLQEKboGxpRRhNWGdBsK
|
||||
f3YZXjmpe8cl8cpbvuvdKYWOE7E6fRGu/CwQEyEQYqmrmljiklSYPaG8IKs5uYWKrA
|
||||
A2D4VTisIYOwGvdljFTQP5zfhPsi4OnNbiN3RVX475lCHNWbnFMh8OCF/ugLj30dyk
|
||||
s8MLAzDyYlgaccOD0uZ6VsdGJ0LK8+TCKbsc5H1ynjg0VejmRyVzZJ5TzAjXrzS6CC
|
||||
Lj9eQQex1IaO6d7uGe4P/ULghjSP90tgBcZVNFLlU3r59ylkVQyAu7THDr4CDaxFO0
|
||||
63QE7/GNDE2vZv0K5gp5Yz2veVC3wyaP1dJzIoAzZc1kZRoWz6QK9cH1Bfmnlx9nUs
|
||||
j+G+VLDQbxi2NuoYAD/I2naA=
|
||||
#+end_src
|
||||
|
||||
Le bloc contient une liste de clefs-valeurs :
|
||||
- ~v~ indique la version du protocole,
|
||||
- ~d~ le domaine attestant de la validité du mail,
|
||||
- ~s~ le nom du sélecteur (/Cf/. plus bas),
|
||||
- ~b~ et ~bh~ contiennent les signatures.
|
||||
|
||||
/Notes/ :
|
||||
- Il est possible que le mail ne soit pas signé par le domaine correspondant à
|
||||
l'adresse d'envoi, puisqu'il est possible d'autoriser autrui à envoyer un
|
||||
mail à notre place (/Cf/. SPF plus haut).
|
||||
- Se référer à la page Wikipédia, ou à la RFC pour une liste exhaustive des
|
||||
clefs.
|
||||
|
||||
*** Serveur DNS
|
||||
|
||||
Il faut placer dans le serveur DNS un champ TXT dont la clef est
|
||||
~sélecteur._domainkey.domain~, où ~domain~ (resp. ~sélecteur~) est la valeur de la
|
||||
clef ~d~ (resp. ~s~) définie plus haut.
|
||||
|
||||
Par exemple, pour le champ fourni plus haut, nous pouvons lire :
|
||||
#+begin_src mail
|
||||
"v=DKIM1; k=rsa; " "p=MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAtwkNVd9Mmz8S4WcfuPk0X2drG39gS8" "+uxAv8igRILgzWeN8j2hjeZesl8pm/1UTVU87bYcdfUgXiGfQy9nR5p/Vmt2kS7sXk9nsJ/VYENg" "b3IJQ6paWupSTFMyeKycJ4ZHCEZB/bVvifoG6vLKqW5jpsfCiOcfdcgXATn0UPuVx9t93yRrhoEM" "ntMv9TSodjqd3FKCtJUoh5cNQHo0T6dWKtxoIgNi/mvZ92D/IACwu/XOU+Rq9fnoEI8GukBQUR5A" "kP0B/JrvwWXWX/3EjY8X37ljEX0XUdq/ShzTl5iK+CM83stgkFUQh/rpww5mnxYEW3X4uirJ7VJH" "mY4KPoIU+2DPjLQj9Hz63CMWY3Ks2pXWzxD3V+GI1aJTMFOv2LeHnI3ScqFaKj9FR4ZKMb0OW2BE" "FBIY3J3aeo/paRwdbVCMM7twDtZY9uInR/NhVa1v9hlOxwp4/2pGSKQYoN2CkAZ1Alzwf8M3EONL" "KeiC43JLYwKH1uBB1oikSVhMnLjG0219XvfG/tphyoOqJR/bCc2rdv5pLwKUl4wVuygfpvOw12bc" "vnTfYuk/BXzVHg9t4H8k/DJR6GAoeNAapXIS8AfAScF8QdKfplhKLJyQGJ6lQ75YD9IwRAN0oV+8" "NTjl46lI/C+b7mpfXCew+p6YPwfNvV2shiR0Ez8ZGUQIcCAwEAAQ=="
|
||||
#+end_src
|
||||
|
||||
|
||||
** Vérification (côté récepteur)
|
||||
|
||||
Côté réception (~redisdead~ pour nous), nous utilisons le milter (filtre pour
|
||||
mail) fourni par ~opendkim~. Ce milter écoute en local et est appelé par ~postfix~.
|
||||
Lors de la réception d'un mail, postfix demande à ~opendkim~ quelle décision
|
||||
prendre. Ce dernier va regarder les en-têtes du mail. S(il trouve une signature
|
||||
DKIM, il va effectuer la requête DNS décrite plus haut, et vérifier la signature
|
||||
du mail (valeurs des clefs ~b~ et ~bh~).
|
||||
|
||||
|
||||
|
||||
* TODO DMARC
|
||||
|
||||
- [[https://www.rfc-editor.org/rfc/rfc7489][RFC]],
|
||||
- [[https://en.wikipedia.org/wiki/DMARC][Page Wikipédia]].
|
||||
|
||||
|
||||
* TODO ARC
|
||||
|
||||
- [[https://www.rfc-editor.org/rfc/rfc8617.html][RFC]],
|
||||
- [[https://en.wikipedia.org/wiki/Authenticated_Received_Chain][Page Wikipedia]].
|
||||
|
||||
|
||||
* MTA-STS
|
||||
|
||||
- [[https://datatracker.ietf.org/doc/html/rfc8461][RFC]],
|
||||
- [[https://en.wikipedia.org/wiki/Simple_Mail_Transfer_Protocol#SMTP_MTA_Strict_Transport_Security][Section de page Wikipédia]].
|
||||
|
||||
Le MTA-STS consiste à publier les protocoles de sécurité supportés par les
|
||||
serveur mail d'un certain domaine (pour nous, les mails en /...@crans.org/).
|
||||
|
||||
Contrairement au ~DANE~ (décrit plus bas), ce protocole ne demande pas la mise en
|
||||
place de DNSSEC. En revanche, il demande d'avoir un serveur Web accessible en
|
||||
~https~ (pour nous, ~https://crans.org~ doit être servi par un serveur Web).
|
||||
|
||||
** Implémentation (côté infrastructure émettrice)
|
||||
|
||||
*** Dans la zone DNS
|
||||
|
||||
Il faut ajouter un champ TXT accessible à ~_mts-sts.domain.tld~.
|
||||
|
||||
Quelques exemples:
|
||||
- Gmail: ~v=STSv1; id=20190429T010101;~,
|
||||
- Microsoft: ~v=STSv1; id=20190225000000Z;~,
|
||||
- Outlook: ~v=STSv1; id=20190225000000Z;~.
|
||||
|
||||
*** Sur le serveur Web
|
||||
|
||||
Il faut que le serveur Web associé serve un fichier texte accessible à l'adresse
|
||||
~https://mta-sts.domain.tld/.well-known/mta-sts.txt~
|
||||
|
||||
Quelques exemples :
|
||||
+ [[https://mta-sts.gmail.com/.well-known/mta-sts.txt][Gmail]]
|
||||
+ [[https://mta-sts.outlook.com/.well-known/mta-sts.txt][Outlook]],
|
||||
+ [[https://mta-sts.microsoft.com/.well-known/mta-sts.txt][Microsoft]].
|
||||
|
||||
Le fichier texte contient une liste de clefs-valeurs. Ces clefs décrivent quel
|
||||
protocole
|
||||
|
||||
|
||||
** Vérification côté récepteur.
|
||||
|
||||
~postfix-mta-sts-resolver~ peut être utilisé ? N'ayant pas implémenté cette
|
||||
solution pour le moment (ni au Cr@ns, ni personnellement), nous ne pouvons pas
|
||||
commenter sur le sujet.
|
||||
|
||||
|
||||
|
||||
* DANE
|
||||
|
||||
- [[https://www.rfc-editor.org/rfc/rfc6698][RFC]],
|
||||
- [[https://en.wikipedia.org/wiki/DNS-based_Authentication_of_Named_Entities][Page Wikipédia]].
|
||||
|
||||
Actuellement, pour vérifier un certificat ~C~ proposé par un serveur mail, il faut
|
||||
faire confiance à un certificat racine, lequel est utilisé pour signer un autre
|
||||
certificat (dit /certificat intermédiaire/), lequel est utilisé pour signer le
|
||||
certificat ~C~. Pour vérifier ~C~, il faut (1) faire confiance au certificat racine
|
||||
et (2) vérifier les deux signatures sus-mentionnées.
|
||||
|
||||
DANE est une norme permettant aux propriétaires de domaines de déclarer quels
|
||||
cetificats doivent être acceptés pour quels services.
|
||||
|
||||
/Note/ : Cela n'est pas spécifique aux mails.
|
||||
|
||||
** Implémentation (côté infrastructure émettrice)
|
||||
|
||||
Pour mettre en place DANE, il suffit d'ajouter un champ DNS à sa zone :
|
||||
|
||||
- Il faut que la zone soit signée DNSSEC.
|
||||
|
||||
- Le champ à ajouter est :
|
||||
+ de type TLSA (TLS Authentiction?),
|
||||
+ de clef ~_port._protoL4.domain.tld~.
|
||||
+ de valeur ~x y z t~, où :
|
||||
* ~x~ est appelé /certificatie usage/,
|
||||
* ~y~ est appelé /selector/,
|
||||
* ~z~ est appelé /matching type/,
|
||||
* ~t~ est appelé /certificate associated data/.
|
||||
|
||||
*** Format du champ TLSA.
|
||||
|
||||
**** /Certificate usage/
|
||||
|
||||
L'objectif de ce champ est d'indiquer comment vérifier le certificat.
|
||||
|
||||
| *Valeur* | *Signification* |
|
||||
|--------+----------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| 0 | Le certificat doit être valide (root -> intermediate -> "cert"), et /associated data/ décrit l'un des certificats parents de "cert" |
|
||||
| 1 | /associated data/ décrit "cert", et le certificat doit aussi être valide /wrt/. un certificat racine de confiance. |
|
||||
| 2 | /associated data/ décrit un parent de "cert". Ce parent est supposé de confiance, et "cert" doit bien être son descendant. |
|
||||
| 3 | /associated data/ décrit "cert". Le certificat n'a pas besoin d'être valide /wrt/. un certificat racine. Il a simplement besoin de correspondre à /associated data/. |
|
||||
|
||||
**** /Selector/
|
||||
|
||||
Ce champ décrit ce qui est décrit par /associated data/.
|
||||
|
||||
| *Valeur* | *Signification* |
|
||||
|--------+-----------------------------|
|
||||
| 0 | Tout le certificat. |
|
||||
| 1 | Seulement la clef publique. |
|
||||
|
||||
**** /Matching type/
|
||||
|
||||
Ce champ indique comment vérifier /associated data/ contre la donnée du certificat
|
||||
(ou de la clef publique).
|
||||
|
||||
| *Valeur* | *Signification* |
|
||||
|--------+--------------------------------------------------------|
|
||||
| 0 | /associated data/ doit être égal à la donnée. |
|
||||
| 1 | /associated data/ doit être égal au sha256 de la donnée. |
|
||||
| 2 | /associated data/ doit être égal au sha512 de la donnée. |
|
||||
où "la donnée" est décrite par le /selector/ et le choix de certificat décrit par
|
||||
le /certificate usage/.
|
||||
|
||||
**** /Certificate associated data/
|
||||
|
||||
Chaîne de caractère au format hexadécimal.
|
||||
|
||||
|
||||
*** Recommandation pour le Cr@ns
|
||||
|
||||
À titre personnel, j'utilise des champs TLSA en ~3 0 1~. Je pense que le Cr@ns
|
||||
peut faire la même chose (ou du ~3 0 2~).
|
||||
|
||||
*** Mise en place
|
||||
|
||||
Hypothèses :
|
||||
- le serveur DNS accepte des mises à jour DNS dynamiques de la part du serveur
|
||||
mail,
|
||||
- le renouvellement du certificat utilise ~certbot~.
|
||||
|
||||
|
||||
Mise en place :
|
||||
- Dans la confguration ~certbot~,
|
||||
+ passer en challenge DNS-01 et :
|
||||
* ~manual_auth_hook~ : un script mettant en place le challenge,
|
||||
* ~renew_hook~ : script de déploiement du certificat, lequel *ajoute* un champ
|
||||
TLSA et place le certificat à déployer dans un dossier "staging",
|
||||
* ~manual_cleanup_hook~ : un script retirant le challenge ~acme~.
|
||||
- Roll-over scheme : Un champ DNS a une durée de vie (TTL), généralement 1h. De
|
||||
ce fait, les requêtes de chalmp TLSA peuvent être en retard d'une heure (au
|
||||
plus). Il est done conseillé d'avoir le nouveau champ TLSA en place pendant
|
||||
deux TTL avant de (1) mettre en place le nouveau certificat et (2) retirer le
|
||||
vieux champ TLSA.
|
||||
|
||||
Je propose de mettre en place un timer systemd qui serait activé "après
|
||||
l'arrêt de certbot pour plus de 2 TTLs". Ce timer lancerait un service, lequel
|
||||
aurait une condition d'activation "un certificat existe dans le dossier
|
||||
staging".
|
||||
|
||||
|
||||
*** Exemple
|
||||
|
||||
#+begin_src dig
|
||||
dig +short TLSA _25._tcp.nanein.fr
|
||||
=> 3 0 1 50E9221F066DCD1991ED9D3BA0AD10159F3585780F6FABBAE2942E43 37789FC8
|
||||
#+end_src
|
||||
|
||||
** Implémentation (côté serveur mail destinataire)
|
||||
|
||||
Côté serveur mail destinataire, la configuration est très simple (car nous
|
||||
utilisons Postfix). Cela se fait principalement via les options suivantes :
|
||||
- ~smtp_dns_supoprt_level~ (valeur ~dnssec~)
|
||||
- ~smtp_tls_dane_insecure_mx_policy~ (valeur ~dane~)
|
||||
|
||||
D'autres options de Postfix peuvent être utilisées pour permettre un contrôle
|
||||
plus fin sur le comportement du service.
|
Loading…
Reference in New Issue