Dans une autre vie, j'avais expliqué comment implémenter un Postgrey sur un Postfix (bon je me suis rendu compte que la page qui m'a expliqué comment faire un Postfix avait disparu, va falloir trouver un remplacement, ou en réécrire une... 🤔).

Là je me suis rendu compte qu'au boulot, en utilisant un serveur mail hébergé chez OVH, Google avait tendance à rejeter certains mails (on fait de la pub pour nos activités...). Je suppose que des gens mal intentionnés abusent des offres d'OVH pour faire nimp. 😑

Mais Google est sympa, il m'indique comment éviter de me faire bloquer : Pourquoi Gmail a-t-il bloqué mes messages ? et Envoyer des messages en masse Consignes pour les expéditeurs.

Dans les consignes pour les expéditeurs d'envoi en masse, il recommande l'authentification des messages, en utilisant SPF, DKIM et DMARC.

SPF

SPF, pour Send Policy Framework, sert à vérifier le nom de domaine d'un expéditeur de mail, avec un enregistrement DNS. C'est le plus facile. 😉

Normalement, seul le propriétaire d'un domaine peut en modifier les enregistrements DNS. Donc si on consulte le DNS pour savoir quelles sont les adresses autorisées à envoyer du mail, on peut facilement discriminer les envois bidons (dons les spams).

Et ça se fait aussi simplement qu'en ajoutant ça au fichier hôte :

valken.org   IN   TXT   "v=spf1 include:_spf.google.com ~all"

En gros ça dit que pour le domaine valken.org, les hôtes autorisés à envoyer du mail sont seulement ceux indiqués. Ici _spf.google.com, vu que c'est GMail qui gère mes mails.

On peut vérifier que l'inscription est correcte en interrogeant le DNS (blabla édité) :

$ dig txt valken.org

;; QUESTION SECTION:
;valken.org. IN TXT

;; ANSWER SECTION:
valken.org. 3600 IN TXT "v=spf1 include:_spf.google.com ~all"

On obtient bien la même chose qu'on a mis, donc c'est good !

Dorénavant, les mails présentant le domaine valken.org qui ne provient pas des adresses précisées pourront être suspectées de spam.

Maintenant il faut qu'on s'assure que les messages entrants sont envoyés depuis des serveurs proprement autorisés.

On va donc installer un module Postfix, postfix-policyd-spf-perl :

$ portinstall postfix-policyd-spf-perl

On va éditer master.cf dans /usr/local/etc/postfix pour l'activer :

spf-policy unix - n n - 0 spawn
user=nobody argv=/usr/local/libexec/postfix-policyd-spf-perl

Et on va dire à Postfix de l'utiliser, en éditant main.cf dans /usr/local/etc/postfix, pour y ajouter :

 check_policy_service unix:private/spf-policy,

Et si tout va bien, on devrait avoir des lignes comme ça dans les logs :

Sep 29 15:29:11 polaris postfix/policy-spf[86930]: Policy action=PREPEND Received-SPF: pass (gmail.com ... _spf.google.com: Sender is authorized to use Cette adresse e-mail est protégée contre les robots spammeurs. Vous devez activer le JavaScript pour la visualiser.' in 'mfrom' identity (mechanism 'include:_netblocks.google.com' matched)) receiver=polaris.human-league.net; identity=mailfrom; envelope-from="Cette adresse e-mail est protégée contre les robots spammeurs. Vous devez activer le JavaScript pour la visualiser."; helo=mail-pj1-f49.google.com; client-ip=209.85.216.49 

DKIM

DKIM, ou DomainKeys Identified Mail, sert à garantir l'origine d'un message en joignant une signature numérique à chaque message.

Comme on est sur FreeBSD, on installe le port adéquat, opendkim :

$ portinstall opendkim

Ne pas oublier de choisir STOCK_RESOLVER dans les options, sinon ça installe un unbound en dépendance, pas forcément nécessaire.

Vu que DKIM est un système de signature, il faut un clé. opendkim fournit un outil, opendkim-genkey :

# opendkim-genkey -D /var/db/dkim -d valken.org -s valkenorg

Là c'est une simulation, le mien a été fabriqué par Google. 😅 On spécifie où placer les fichers de sortie avec -D, ici /var/db/dkim, le domaine concerné avec -d, ici valken.org, et on nomme la clé avec -s, ici valkenorg.

Ça créée deux fichiers, valkenorg.private qui contient la clé de signature, et valkenorg.txt, qui est l'entrée à inscrire dans le DNS.

Le fichier private est une clé RSA, rien de bien folichon, le fichier txt est plus intéressant (édité bien sûr, faut pas mettre ses clés privées sur le net 😋) :

valkenorg._domainkey IN TXT ( "v=DKIM1; k=rsa; p=ABCDEF1234567890abcdef1234567890" ) ; ----- DKIM key valkenorg for valken.org

Comme pour SPF, on ajoute cette ligne au fichier hôte du domaine.

Si tout va bien, après propagation correcte de la nouvelle entrée, on obtient ça (encore blabla édité) :

$ dig +norec -t TXT valkenorg._domainkey.valken.org

;; QUESTION SECTION:
;valkenorg._domainkey.valken.org. IN TXT

;; ANSWER SECTION:
valkenorg._domainkey.valken.org. 3600 IN TXT "v=DKIM1; k=rsa; p=ABCDEF1234567890abcdef1234567890"

C'est bon du côté DNS, ça permet aux serveurs destinataires de vérifier notre signature.

Maintenant il faut s'intéresser à la configuration de opendkim. Son fichier de configuration opendkim.conf est dans /usr/local/etc/mail. Le fichier par défaut est très complet et long, on va juste changer les paramètres qui nous intéressent :

AutoRestart yes : Permet le redémarrage de opendkim en cas de plantage.

Background Yes : Lance le process en tâche de fond (défaut mais ça mange pas de pain de le préciser).

Canonicalization relaxed/simple : Là on précise que la signature de l'en-tête sera fera sur une version normalisée (relaxed - voir DKIM signatures), et sur le corps du message non modifié (simple).

Domain valken.org : Pour quel domaine on doit signer. Si le serveur gère plusieurs domaines, on peut spécifier un nom de fichier qui comportera un domaine par ligne.

InternalHosts 127.0.0.1 : Quelles adresses IP on doit considérer comme les nôtres, donc que signer. Les autres adresses auront leur signature DKIM vérifiées. Valeur par défaut 127.0.0.1.

KeyFile /var/db/dkim/valkenorg.private : Clé à utiliser. En cas de domaines multiples, il faut utiliser les paramètres KeyTable et SigningTable en leur donnant les fichiers de correspondance. Si KeyTable et SigningTable sont utilisés, KeyFile est ignoré. Il est obligatoire d'avoir soit KeyFile soit KeyTable renseigné.

LogWhy yes : Ecrit dans le log l'explication derrière chaque décision de opendkim. Utile en debug, déconseillé en production.

ReportAddress "Toto" <Cette adresse e-mail est protégée contre les robots spammeurs. Vous devez activer le JavaScript pour la visualiser.> : Adresse où envoyer les rapports d'échec (en plus des expéditeurs) si SendReports est activé. envoyés depuis l'adresse de l'utilisateur qui a lancé le processus.

Selector valkenorg : Le Selector à utiliser pour la signature. Le nom qu'on a défini lors de la génération de la clé. Obligatoire, pas de valeur par défaut.

SendReports yes : opendkim enverra des rapports d'échec aux expéditeurs.

Socket inet:8891@localhost : Spécifie la méthode d'écoute de opendkim. Peut être un socket.

Syslog Yes : Envoyer des messages dans Syslog.

SyslogSuccess yes : Envoyer des messages de succès dans Syslog.

Il faut maintenant activer le lancement de opendkim dans /etc/rc.conf :

milteropendkim_enable="YES"

Et lancer opendkim :

# /usr/local/etc/rc.d/milter-opendkim start

Si tout va bien, on devrait obtenir :

Starting milteropendkim.

On peut voir le daemon tourner avec ps :

# ps ax | grep opendkim
33868 - Ss 0:00.00 /usr/local/sbin/opendkim -l -u mailnull:mailnull -P /var/run/milteropendkim/pid -x /usr/local/etc/mail/opendkim.conf
33869 - S 0:00.00 /usr/local/sbin/opendkim -l -u mailnull:mailnull -P /var/run/milteropendkim/pid -x /usr/local/etc/mail/opendkim.conf

Finalement, on va dire à Postfix de faire passer les messages par opendkim. Editons le fichier main.cf dans /usr/local/etc/postfix, et ajoutons les lignes suivantes :

milter_default_action = accept : Par défaut on accepte les mails. Vu que DKIM n'est pas (encore ?) le défaut dans les configurations des mailers, on va éviter de rejeter presque tous les mails... 😅

milter_protocol = 6 : La version du Milter. Après la version 2.6, Postfix utilise la version 6 par défaut.

smtpd_milters = inet:localhost:8891 : On fait passer les mails par ce filtre.

non_smtpd_milters = $smtpd_milters : On fait tout passer par les mêmes filtres. 😋

On relance Postfix :

# postfix reload

Et si tout va bien, on a ce genre de lignes dans les logs en réception :

Nov 27 12:50:52 polaris opendkim[39136]: A5FE42D63F0: no signing domain match for 'gmail.com'
Nov 27 12:50:52 polaris opendkim[39136]: A5FE42D63F0: no signing subdomain match for 'gmail.com'
Nov 27 12:50:52 polaris opendkim[39136]: A5FE42D63F0: DKIM verification successful

Google a des enregistrement DKIM, il est donc vérifié. Les deux premières lignes indiquent que gmail.com ne fait pas partie des domaines qu'on doit signer. Ça marche bien donc.😉

Et en envoi, on aura :

Nov 27 12:49:09 polaris opendkim[33869]: 5F59122578B: DKIM-Signature field added (s=valkenorg, d=valken.org)

Signature ajoutée. 😉

DMARC

DMARC, ou Domain-based Message Authentication, Reporting & Conformance, est un protocole d'authentification de stratégie et de reporting de mails, reposant sur SPF et DKIM.

D'abord, on a besoin d'un enregistrement DNS. Pour valken.org, on aurait :

_dmarc.valken.org. TXT "v=DMARC1; p=reject; sp=reject; rua=mailto:Cette adresse e-mail est protégée contre les robots spammeurs. Vous devez activer le JavaScript pour la visualiser.; ruf=mailto:Cette adresse e-mail est protégée contre les robots spammeurs. Vous devez activer le JavaScript pour la visualiser.; fo=0; adkim=r; aspf=r; pct=100; rf=afrf; ri=86400;"

 Que veut dire tout ça :

p : Politique à appliquer pour les échecs DMARC, reject, quarantine ou none.

sp : Politique à appliquer pour les sous-domaines, mêmes paramètres que p.

rua, ruf : Adresses où envoyer les rapports (rua), et les échecs (ruf). Doit être une URI (mailto:).

fo : Options de rapport d'échec. 0 pour rien, 1 pour tout échec, d pour les erreurs DKIM, s pour les erreurs SPF.

adkim, aspf : Mode de gestion DKIM et SPF. r pour relaxed, s pour strict. Le mode relaxed autorise les Organizational Domain communs à passer la validation, strict demande une correspondance exacte.

pct : Pourcentage de messages testés par DMARC. Nécessite une politique reject ou quarantine.

rf : Format des rapports, pour DMARC1, uniquement AFRF.

ri : Laps de temps entre les rapports en secondes. 1 jour par défaut.

Si tout va bien, on a ça :

$ dig -t TXT _dmarc.valken.org

;; QUESTION SECTION:
;_dmarc.valken.org. IN TXT

;; ANSWER SECTION:
_dmarc.valken.org. 3600 IN TXT "v=DMARC1; p=reject; sp=reject; rua=mailto:Cette adresse e-mail est protégée contre les robots spammeurs. Vous devez activer le JavaScript pour la visualiser.; ruf=mailto:Cette adresse e-mail est protégée contre les robots spammeurs. Vous devez activer le JavaScript pour la visualiser.; fo=0; adkim=r; aspf=r; pct=100; rf=afrf; ri=86400;"

Maintenant on installe le port idoine, opendmarc :

# portinstall opendmarc

Ça ramène un paquet de dépendances.

 Editons le fichier de configuration, opendmarc.conf. Sur FreeBSD, il est dans /usr/local/etc/mail (recopier le .sample en .conf au besoin).

Encore une fois le fichier est long, modifions uniquement ce dont on a besoin :

AuthservID mailer.valken.org : Le nom du serveur, pour les rapports.

AutoRestart true : Pour redémarrer le daemon si'il se plante.

AutoRestartCount 5 : Limiter le nombre de redémarrages automatiques en cas de problème.

Background true : Tourner en tâche de fond.

BaseDirectory /var/run/opendmarc : Où opendmarc démarrera. Pour retrouver facilement les dumps au cas où.

HistoryFile /var/run/opendmarc/opendmarc.dat : Le fichier où est inscrit l'activité de openmarc pour générer les rapports.

IgnoreHosts /usr/local/etc/mail/ignore.hosts : Fichier listant les serveurs à ne pas filtrer, nos serveurs.

PidFile /var/run/opendmarc.pid : Fichier PID.

RejectFailures false : Rejeter ou non les messages en échec. On accepte dans le doute avec false.

Socket inet:8893@localhost : Adresse et port à utiliser.

Syslog true : Ecrire dans Syslog.

TrustedAuthservIDs mailer.valken.org : Noms des serveurs dignes de confiance, normalement les notres.

Il faut maintenant activer le lancement de opendmarc dans /etc/rc.conf :

opendmarc_enable="YES"

Et lancer opendmarc :

# /usr/local/etc/rc.d/opendmarc start

Si tout va bien, on devrait obtenir :

Starting opendmarc.

On peut voir le daemon tourner avec ps :

$ ps ax | grep opendmarc
99335 - Is 0:00.00 /usr/local/sbin/opendmarc -l -P /var/run/opendmarc/pid -c /usr/local/etc/mail/opendmarc.conf -p
99336 - S 0:00.01 /usr/local/sbin/opendmarc -l -P /var/run/opendmarc/pid -c /usr/local/etc/mail/opendmarc.conf -p

Et on dit à Postfix de faire passer les messages par opendmarc. Editons encore le fichier main.cf dans /usr/local/etc/postfix, et complétons la ligne suivante :

smtpd_milters = inet:localhost:8891 

On y ajoute le milter opendmarc :

smtpd_milters = inet:localhost:8891, inet:localhost:8893

Bien sûr, si votre port/socket est différent, il faut adapter en conséquence.

On relance Postfix :

# postfix reload

Et si tout va bien, on aura des lignes comme ça dans le log :

Nov 28 11:52:02 mailer.valken.org opendmarc[1877]: BD7A32D6412: gmail.com pass

Et voilou. C'était pas trop compliqué. 😉