Mise en place de DKIM, SPF, DMARC sur Debian Jessie pour Exim4🔗
Introduction
Vous administrez votre propre serveur de courrier électronique: bravo, vous participez à décentraliser Internet et à lui donner un peu plus de résilience et de robustesse en plus de renforcer la protection de votre vie privée. Comme je l'ai déjà décrit il y a quelques années dans mes différents articles sur le courrier électronique, l'administration d'un ensemble de services (car il n'existe pas qu'un seul service) peut se révéler complexe. En conséquence, il vaut mieux y aller pas à pas, vérifier que tout ce qui est mis en place est correct et progressivement ajouter des services optionnels.
Aujourd'hui nous allons traiter des mesures destinées à renforcer la confiance que peut avoir le monde extérieur par rapport à votre domaine de courrier électronique. Cet article présentera 3 protocoles destinés à lutter contre le spam et à garantir l'authenticité de l'émetteur de messages électroniques. Ces trois protocoles seront, dans l'ordre, DKIM, SPF et DMARC. L'ensemble sera bien entendu appliqué, dans un cas concret, à une configuration existante sous Debian Jessie et son MTA par défaut: Exim4.
Mise en place de DKIM
À propos de DKIM
Avant de se lancer dans la configuration de DKIM, il faut essayer d'en comprendre les bases. Pour faire simple, DKIM est un système de signature de mails en sortie de votre MTA. La particularité de la signature c'est que la clef publique est disponible sur le serveur DNS qui dessert le domaine de courrier électronique.
Dans ce système, pas besoin d'autorité de certification, on va au plus simple en utilisant un champ TXT dans le DNS. Cette technique permet de garantir l'intégrité du message mais surtout de certifier que l'émetteur du message dispose du couple clef privée/clef publique dont cette dernière est référencée sur le serveur DNS du domaine de courrier électronique. Il y a donc de très grandes chances que l'émetteur soit légitime, c'est-à-dire, appartienne bien au domaine qu'il prétend annoncer dans le champ From (n'oubliez pas que dans les protocoles de courrier électronique, on peut mettre n'importe quel contenu dans le champ From par défaut).
Le système est donc assez simple, mais il vous faut un serveur DNS sur lequel vous avez la main ou bien où vous pouvez ajouter un champ TXT (c'est le cas de la majorité des registrars qui fournissent un service DNS en plus de la location du nom de domaine).
Générer un couple clef privée/clef publique
La première étape est de générer un couple clef privée/clef publique. La première sera conservée bien au chaud sur votre serveur. La seconde sera exposée sur le serveur DNS du domaine.
-- génération de la clef privée $ openssl genrsa -out example.com.dkim.pkey.pem 1024 -outform PEM -- génération de la clef publique à partir de la clef publique $ openssl rsa -in example.com.dkim.pkey.pem -out example.com.dkim.pem -pubout -outform PEM
Je vous conseille de générer ces clefs sur une machine disposant d'un certain niveau d'entropie. Concrètement, sur un plugcomputer, c'est plus difficile. Le faire sur une station de travail sera sans doute plus adapté.
Je vous conseille de déposer votre clef privée non pas dans le répertoire dédié (/etc/ssl/private
) mais dans un répertoire accessible à l'utilisateur qui fait tourner le service exim4. En effet, exim4 tourne avec un utilisateur non privilégié (Debian-exim
) qui ne peut accéder au précédent répertoire. Par commodité, je place la clef privée dans le répertoire de configuration d'Exim dans /etc/exim4/keys
.
# cp example.com.dkim.pkey.pem /etc/exim4/keys/ # chgrp Debian-exim /etc/exim4/keys/example.com.dkim.pkey.pem # chmod 640 /etc/exim4/keys/example.com.dkim.pkey.pem
Configuration de l'enregistrement DNS
Vous devez renseigner un champ TXT avec la syntaxe qui suit:
SELECTOR._domainkey.example.com IN TXT "k=rsa; p=PUBLICKEY"
SELECTOR indique un sélecteur de clef publique, car on peut héberger plusieurs clefs publiques pour un même domaine. En guise de sélecteur, on peut mettre une date ou un numéro d'identifiant. Pour ma part, je place une date, c'est bien suffisant, genre 20150806. N'oubliez pas le point à la fin du sélecteur.
PUBLICKEY est le contenu de votre clef publique sur une seule ligne.
Par exemple, voici le contenu du certificat de clef publique:
-----BEGIN PUBLIC KEY----- MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDMKspwVBt2fpRXy0Yd+Ku+rzfG cIiq80nEyNLQ4ZekA2MwqJmdGqyQxmCx0ddICrULOjcYpl+19UF0303jYsaLP6BP A0bPTMu7k0ZGBXQxFG0tPsn0aDDOeW4HonX1uN7sM+IAR3bXzuLcObYEzTQkPIko /O8M6PeVdrKWfFgPFwIDAQAB -----END PUBLIC KEY----
Sur une seule ligne, ça donne:
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDMKspwVBt2fpRXy0Yd+Ku+rzfGcIiq80nEyNLQ4ZekA2MwqJmdGqyQxmCx0ddICrULOjcYpl+19UF0303jYsaLP6BPA0bPTMu7k0ZGBXQxFG0tPsn0aDDOeW4HonX1uN7sM+IAR3bXzuLcObYEzTQkPIko/O8M6PeVdrKWfFgPFwIDAQAB
Pour vérifier la configuration DNS, utilisez dig:
$ dig -t TXT SELECTOR._domainkey.example.com +short "k=rsa\; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDMKspwVBt2fpRXy0Yd+Ku+rzfGcIiq80nEyNLQ4ZekA2MwqJmdGqyQxmCx0ddICrULOjcYpl+19UF0303jYsaLP6BPA0bPTMu7k0ZGBXQxFG0tPsn0aDDOeW4HonX1uN7sM+IAR3bXzuLcObYEzTQkPIko/O8M6PeVdrKWfFgPFwIDAQAB"
Configuration d'Exim4
Maintenant que nous avons traité la question des clefs, il reste à indiquer à Exim4 d'utiliser notre clef privée. J'utilise le démon light mais la configuration est identique pour le démon heavy.
Si vous suivez les règles Debian sur Exim4 (vous devriez), le plus simple consiste à modifier le fichier /etc/exim4/conf.d/main/000_localmacros
que j'ai déjà utilisé dans mes articles précédents. Voici le contenu à ajouter:
# Configuration DKIM DKIM_CANON = relaxed DKIM_SELECTOR = SELECTOR DKIM_DOMAIN = example.com DKIM_PRIVATE_KEY = /etc/exim4/keys/example.com.dkim.pkey.pem
N'utilisez pas la macro DKIM_FILE: elle n'est pas valide pour cette version d'Exim4.
Ensuite, le classique:
# update-exim4.conf # systemctl restart exim4
Allez faire un tour dans les logs /var/log/exim4/mainlog
pour voir s'il n'y aurait pas de problème dans votre configuration.
Tester la configuration
Le plus simple des tests consiste à envoyer un courrier électronique de votre MTA vers un correspondant extérieur qui dispose de quoi vérifier DKIM. Pour ma part, j'utilise un compte GMail qui gère DKIM et j'affiche le contenu original (seule manière d'avoir les en-têtes complètes dans GMail). Vous devriez voir des choses comme ce qui suit:
dkim=pass header.i=@example.com DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=example.com; s=SELECTOR; h=Content-Type:MIME-Version:Message-ID:Subject:To:From:Date; bh=epN+8Ir4gghSKMRQcJJjbBdVZhDiHfJEakMbvPyEbWw=; b=EDgHfrk5brLGxRHD4JwefivY2163CFDm8yu2RVbl66D+CAFRXScZIrclMDA4wF4oX9a8lSo39LDhaGIgl85MfkwvDHGk7tbcG7mcIOpVZGgesS3zI+ifSVAD210JEI3y9WwwpmJQOwJJ3CnUAcV2lo0dLydDpzmAKdOz/ohv1DQ=;
Mise en place de SPF
Introduction
Après avoir travaillé sur l'implémentation de DKIM, il nous reste à voir ce qui se passe du côté de SPF. Il s'agit d'un mécanisme permettant d'identifier les courriers électroniques usurpés. Pour faire simple, il s'agit d'un enregistrement DNS (un autre) permettant de lister quelles sont les adresses IP légitimes pour envoyer du courrier électronique pour ce domaine précis. La vérification se fait au niveau du MTA entrant donc vous n'aurez rien à faire au niveau du MTA sortant.
Concrètement, le MTA qui reçoit le courrier électronique de votre MTA va faire une requête DNS pour récupérer une information SPF. Si celle-ci existe, elle sera analysée pour vérifier si le MTA qui envoie le courrier correspond à la plage (ou les plages) d'adresses IP déclarée(s) dans le DNS.
Déclaration au niveau du DNS
SPF n'est qu'un (ou plusieurs) enregistrement(s) TXT simple(s) dont voici la forme:
"v=spf1 Règle_1 [Règle_2] … [Règle_N] NON_MATCHING"
Quelques explications basiques:
- v=spf1 permet d'identifier que le champ TXT est un champ SPF.
- Règle correspond à un ou plusieurs caractères dont la syntaxe est la suivante:
- a: cette règle est simple et n'a pas de paramètres. Concrètement, si le domaine dispose d'une adresse IP déclarée dans le DNS, ce qui veut dire que le domaine dispose d'une adresse IP résolue au niveau du nom de domaine seul, alors cette adresse est reprise et considérée comme légitime pour envoyer du courrier électronique. Cette règle s'applique sur les hébergements très simples où tout est concentré sur une seule machine (c'est souvent le cas pour de l'auto-hébergement).
- mx: cette règle est également simple et ne dispose pas non plus de paramètres. Dans ce cas, si le domaine dispose d'un enregistrement DNS MX, tous les serveurs retournés par une requête DNS MX sont déclarés comme légitimes. C'est également une situation simple qui permet de prendre en compte plusieurs serveurs de mail pour un seul domaine de courrier électronique.
- ip4: liste une adresse IPv4 ou une plage d'adresses IPv4 comme étant légitimes pour envoyer du courrier électronique. La syntaxe est du type:
ip4:xxx.xxx.xxx.xxx
pour les IPv4 simples ouip4:xxx.xxx.xxx.xxx/yy
pour les plages. - *ip6*: liste une adresse IPv6 ou une plage d'adresses IPv6 comme étant légitimes pour envoyer du courrier électronique. La syntaxe est du type:
ip6:xxxx:xxxx:..:xx
pour les IPv6 simples ouip6:xxxx:xxxx:..:xxxx/yy
pour les plages. - NON_MATCHING: permet de dire quoi faire quand une IP n'est pas dans les cas de figure des règles. On utilise le mot
all
avec un préfixe qui peut être+
(accepter quand même),-
(rejet),~
(accepter mais marquer).
Dans notre cas, nous souhaitons utiliser les règles a
et mx
et rejeter tous les autres cas. La chaîne TXT prend donc la forme suivante:
"v=spf1 a mx -all"
Vérifier la déclaration DNS
Une simple requête dig sur les champs TXT permet de voir si votre enregistrement DNS est actif:
$ dig example.com TXT +short "v=spf1 a mx -all"
Tester la configuration
Le plus simple des tests consiste à envoyer un courrier électronique de votre MTA vers un correspondant extérieur qui dispose de quoi vérifier SPF. Pour ma part, j'utilise un compte GMail et j'affiche le contenu original (seule manière d'avoir les en-têtes complètes dans GMail). Vous devriez voir des choses comme ce qui suit:
Authentication-Results: mx.google.com; spf=pass (google.com: domain of user@example.com designates xxx.xxx.xxx.xxx as permitted sender) smtp.mail=user@example.com;
Mise en place de DMARC
Introduction
DKIM et SPF permettent d'améliorer la détection des mails usurpés, mais il persiste un grand vide: DKIM n'est pas obligatoire. Ainsi, n'importe qui se trouvant au sein de votre réseau (si ce dernier est déclaré dans SPF) peut envoyer un email sans signature DKIM.
Il faut donc un moyen de dire que DKIM est obligatoire. C'est le but de DMARC.
Déclaration DNS
DMARC consiste en un (ou plusieurs) enregistrement(s) DNS TXT qui indique(nt) quelles sont les règles à respecter au niveau de DKIM et de SPF au sujet des courriers électroniques.
Sa syntaxe est la suivante:
"v=DMARC1; p=[REJECT]; adkim=[REGLE_DKIM]; aspf=[REGLE_SPF]"
- REJECT indique quelle est la politique à mener en cas de rejet. On peut utiliser les mots suivants:
none
(accepter),reject
(rejeter), ouquarantine
(mettre en quarantaine). - REGLE_DKIM indique ce qu'il faut faire en cas de non-respect de DKIM (le mail n'a pas de signature DKIM). On peut utiliser les lettres suivantes:
r
(mode relâché, on accepte le courriel) ous
(mode strict, on rejette le courriel). - REGLE_SPF indique ce qu'il faut faire en cas de non-respect de SPF (le mail provient d'une machine non déclarée dans SPF). On peut utiliser les lettres suivantes:
r
(mode relâché, on accepte le courriel) ous
(mode strict, on rejette le courriel).
En plus de ces règles on peut utiliser d'autres paramètres:
fo:
indique comment rédiger les formulaires d'alertes qui seront envoyés à l'administrateur du domaine de courrier électronique.0
indique d'envoyer un rapport si l'ensemble des règles ne sont pas respectées,1
indique d'envoyer un rapport si un seul des éléments (DKIM ou SPF) n'est pas respecté.rua:
indique l'adresse email utilisée pour récupérer les rapports d'alerte.
Dans notre cas, notre règle DMARC sera la suivante:
"v=DMARC1; p=reject; adkim=s; aspf=s; fo:1; rua:postmaster@example.com"
Conclusion
Finalement, les mécanismes de vérification de l'identité de l'émetteur d'un courrier électronique sont assez simples à comprendre et à mettre en place. Même sur une configuration légère auto-hébergée, il est donc facile de les mettre en œuvre. Sur ce plan, ils deviennent, au fur et à mesure du temps, des quasi pré-requis. Sachez que Google Mail les utilise depuis de nombreuses années pour garantir la validité des courriers électroniques que vous envoyez sur le domaine gmail.com (en plus d'autres mécanismes bien plus contraignants comme la résolution de nom inverse qu'on ne maîtrise pas toujours lorsqu'on s'auto-héberge).
Ne vous privez donc pas de les mettre en place !
Références
DKIM:
- Documentation de référence d'Exim4 sur DKIM.
- Article de Debian-administration sur DKIM.
- Spécification officielle de DKIM.
SPF:
DMARC:
Bonus: multidomaine DKIM
Notre configuration DKIM est sympathique, mais il est probable que vous ayez plusieurs domaines de courrier électroniques qui pointent vers le même MTA. Dans ce cas, comment gérer un domaine qui change en fonction des messages qui sont envoyés ?
Exim4 est assez performant: sa configuration permet de calculer des contenus de variables en fonction de règles pré-établies. Exim4 embarque donc un quasi-langage (lire sa documentation) le rendant ultra-dynamique. Exploitons ces mécanismes avec une configuration multi-domaines pour DKIM.
Voici cette configuration et les explications qui vont avec:
# Configuration DKIM DKIM_CANON = relaxed DKIM_SELECTOR = SELECTOR DKIM_DOMAIN = ${sg{${lc:${domain:$h_from:}}}{^www\.}{}} DKIM_FILE = /etc/exim4/keys/DKIM_DOMAIN.dkim.pkey.pem DKIM_PRIVATE_KEY = ${if exists {DKIM_FILE} {DKIM_FILE}{0}}
Vous devez noter que vos sélecteurs seront identiques pour toutes les déclarations DNS des clefs publiques. On commence par calculer le domaine dans la variable DKIM_DOMAIN. $h_from
permet d'extraire le contenu du champ From: du message à envoyer. ${domain:$h_from}
permet d'extraire le nom de domaine de la variable h_from. ${lc:${VAR}}
permet de mettre en minuscule le nom de domaine. Enfin, la directive $sg
permet de jouer une expression régulière. Ici, il s'agit d'éliminer un éventuel www. qui pointerait dans le nom de domaine (on aurait pu s'en passer).
Ensuite, DKIM_FILE contient le nom du fichier de clef privée. Notez bien que la variable DKIM_DOMAIN est utilisée directement. Vos noms de clefs privées doivent être du genre: domaine_fqdn.dkim.pkey.pem et situées dans /etc/exim4/keys/
.
Enfin, DKIM_PRIVATE_KEY exécute un test pour savoir si le fichier déclaré dans DKIM_FILE existe. Si c'est le cas, la variable DKIM_PRIVATE_KEY contiendra le contenu de DKIM_FILE, sinon, elle ne contiendra rien. Lorsque la variable DKIM_PRIVATE_KEY est vide, Exim4 désactive la signature DKIM pour les messages sortants.