Introduction

opendkim est un logiciel qui permet d'ajouter une signature DKIM à l'intérieur d'un courriel.

Processus php - postfix - opendkim - postfix - serveur de courriel externe

  1. Un script PHP envoie un courriel avec mail('user@example.com', 'subject', 'test', "From: user@progysm.com\r\n");
  2. la commande mail() transfère le courriel à postfix
  3. à l'aide des configurations de milter de /etc/postfix/main.cf, ouverture du socket opendkim.sock.
  4. opendkim lit le nom de domaine de l'entête From du message
  5. opendkim lit la clé selon le nom de domaine dans la table des signatures (SigningTable).
  6. opendkim lit le nom du fichier contenant la clé privée dans la table des clés (KeyTable)
  7. opendkim utilise la clé privée pour signée le courriel à l'aide de diverses entêtes et ajoute l'entête DKIM-Signature dans le courriel. Retour à postfix
  8. postfix envoie le message au serveur de courriel externe
  9. le serveur de courriel externe examine l'entête DKIM-Signature, utilise le domaine (d=) et le sélecteur (s=) pour effectuer une requête DNS TXT pour récupérer la clé publique. Comme un dig TXT sélecteur._domainkey.domaine.
  10. le serveur de courriel décode la signature encryptée avec la clé publique.

Installation

Avec debian:

root@machine# apt-get install opendkim opendkim-tools

Configuration d'openDKIM

Dans cet exemple, je configure opendkim pour les courriels qui seront envoyés avec l'entête "From: quelquechose@progysm.com" et aussi pour les courriels avec l'entête "From: quelquechose@mail.test.com". Les noms de domaine sont "progysm.com" et "mail.test.com" et le sélecteur sera l'année-mois, soit "201801".

Ajouter à la fin du fichier /etc/opendkim.conf (chmod 644)

KeyTable /etc/opendkim/key.table
SigningTable refile:/etc/opendkim/signing.table
ExternalIgnoreList /etc/opendkim/trusted.hosts
InternalHosts /etc/opendkim/trusted.hosts

Canonicalization relaxed/simple
AutoRestart yes
AutoRestartRate 10/1M
DNSTimeout 5

Créer le répertoire /etc/opendkim (chmod 644) et /etc/opendkim/keys (chmod 600)

root@machine# mkdir -p /etc/opendkim/keys

Créer une clé privée pour le nom de domaine et renommer en nomdomaine.private et nomdomaine.txt. Le sélecteur (-s) est l'année-mois.

root@machine# cd /etc/opendkim/keys
root@machine# opendkim-genkey -b 2048 -h rsa-sha256 -r -s 201801 -d progysm.com -v
root@machine# mv 201801.private progysm.private
root@machine# mv 201801.txt progysm.txt

root@machine# opendkim-genkey -b 2048 -h rsa-sha256 -r -s 201801 -d mail.test.com -v
root@machine# mv 201801.private mail.test.private
root@machine# mv 201801.txt mail.test.txt

Le nom du fichier qui contient la clé privée sera utilisé dans le fichier key.table. Le contenu du fichier texte sera utilisé pour l'enregistrement DNS TXT (DNS Record). Il contient la clé publique.

Dans le fichier /etc/opendkim/key.table.

progysm progysm.com:201801:/etc/opendkim/keys/progysm.private
mailtest mail.test.com:201801:/etc/opendkim/keys/mail.test.private

Attention, il faut absolument utiliser une espace entre la clé opendkim et les domaine:sélecteur:fichier. J'ai eu plusieurs problèmes affichés dans /var/log/mail.log (postfix) en ajoutant une espace insécable. La clé n'était donc pas trouvée dans le fichier. Exemple de l'erreur:

Jan 24 11:37:10 web opendkim[21659]: 1D7AD3B0093: signing table references unknown key 'progysm'
Jan 24 11:37:10 web postfix/cleanup[21668]: 1D7AD3B0093: milter-reject: END-OF-MESSAGE from localhost[127.0.0.1]: 4.7.1 Service unavailable - try again later; from=<root@progysm.com> to=<...>

Dans le fichier signing.table, on associe le nom de domaine des courriels à la clé du fichier key.table. Utilisation d'une espace entre les deux champs.

*@progysm.com progysm
*@mail.test.com mailtest

Dans le fichier /etc/opendkim/trusted.hosts, on ajoute les nom de domaines de confiance (pas encore certain de son utilisation).

127.0.0.1
::1
localhost
progysm.com
mail.test.com

Finalement, on donne les bons droits aux fichiers.

root@machine# chown -R opendkim:opendkim /etc/opendkim
root@machine# chmod -R go-rwx /etc/opendkim/keys

Et on redémarre.

root@machine# systemctl restart opendkim        # ou bien service opendkim restart
root@machine# systemctl status -l opendkim

Configuration DNS

Après la génération des clés privées et publiques, on peut ajouter les clés publiques dans la zone DNS des domaines. Les fichiers /etc/opendkim/keys/*.txt possède un exemple de configuration mais il faut copier/modifier/coller le contenu dans l'interface de configuration de notre zone DNS. J'utilise généralement des services externes avec des interfaces Web.

Le fichier .txt ressemble à ceci (note: j'ai remplacé la vraie clé publique avec des points):

201801._domainkey	IN	TXT	( "v=DKIM1; h=rsa-sha256; k=rsa; s=email; "
	  "p=MIIB.....................................................................................................................................................................................................................................................g"
	  "Y..........................................................................................................................................QAB" )  ; ----- DKIM key 201801 for progysm.com

Pour la majorité des interfaces sur le web et pour le nom de domaine principal (progysm.com), on devra ajouter un enregistrement TXT avec les informations suivantes:

  • Domaine: 201801._domainkey
  • Type d'enregistrement DNS: TXT
  • Valeur: v=DKIM1; h=sha256; k=rsa; s=email; p=MIIB.....................................................................................................................................................................................................................................................gY..........................................................................................................................................QAB

La valeur doit être modifiée pour enlever le préfix "rsa-" devant "rsa-sha256". On doit aussi enlever les changements de lignes et les doubles-guillemets".

Pour les sous domaines comme mail.test.com, si on édite la zone "test.com", il ne faut pas oublier d'ajouter .mail pour le domaine. Les informations seraient:

  • Domaine: 201801._domainkey.mail
  • Type d'enregistrement DNS: TXT
  • Valeur: v=DKIM1; h=sha256; k=rsa; s=email; p=MIIB.....................................................................................................................................................................................................................................................gY..........................................................................................................................................QAB

Attention, je suis tombé sur une interface Web très mal écrite sur enom.com qui ajoute un maxlength="250" dans la balise INPUT du champ de la valeur. Or, la valeur fait au moins 430 caractères. J'ai donc dû ouvrir la console de développement DOM de Firefox, modifier la valeur maxlength à 2500, copier/coller la valeur et enregistrer. À chaque modification, je dois corriger l'attribut maxlength de la balise INPUT. La majorité des interfaces de modification de zone DNS possède une meilleure interface pour les enregistrements TXT.

Test DNS de la clé

On peut tester la clé à l'aide des outils de opendkim et aussi vérifier les enregistrements DNS à l'aide de dig.

root@machine# opendkim-testkey -d progysm.com -s 201801 -vvv

opendkim-testkey: using default configfile /etc/opendkim.conf
opendkim-testkey: checking key '201801._domainkey.progysm.com'
opendkim-testkey: key not secure
opendkim-testkey: key OK

root@machine# dig TXT 201801._domainkey.progysm.com
;; ANSWER SECTION:
201801._domainkey.progysm.com. 1800 IN	TXT	"v=DKIM1; h=sha256; k=rsa; s=email; p=MIIB.......AB"

root@machine# opendkim-testkey -d mail.test.com -s 201801 -vvv
...

root@machine# dig TXT 201801._domainkey.mail.test.com
...

On veut un "key OK" à la fin d'openkim-testkey. Je crois que "key not secure" signifie que le chemin d'accès /, /etc, /etc/opendkim n'est pas assez sécurisé au goût d'opendkim-testkey.

Il ne faut pas être trop impatient car il faut attendre bien souvent la diffusion/réplication des zones DNS sur les serveurs DNS secondaires. Il faut aussi penser que la majorité des requêtes DNS seront cachées sur des serveurs DNS intermédiaires. Si vous avec un serveur bind9 local, vous pouvez effacer le cache avec la commande "rndc flush".

Configuration avec postfix

Cette configuration permet d'intégrer la clé DKIM à l'intérieur des messages envoyés par postfix (même s'ils sont envoyés à l'aide de la commande mail() de PHP.

Avec debian:

Ajouter l'utilisateur postfix dans le groupe opendkim, cette commande sera utile pour le socket plus tard.

root@machine# adduser postfix opendkim

Si on n'ajoute pas postfix dans le groupe, on pourrait avoir une erreur qui ressemble à:

15216 Jan 24 11:12:36 web opendkim[21332]: OpenDKIM Filter: Unable to bind to port local:/opendkim/opendkim.sock: No such file or directory
15217 Jan 24 11:12:36 web opendkim[21332]: OpenDKIM Filter: Unable to create listening socket on conn local:/opendkim/opendkim.sock
15218 Jan 24 11:12:36 web opendkim[21332]: smfi_opensocket() failed
15219 Jan 24 11:12:36 web opendkim[21324]: exited with status 69, restarting

Créer le répertoire pour le socket d'opendkim.

root@machine# mkdir -p /var/spool/postfix/opendkim
root@machine# chown opendkim:postfix /var/spool/postfix/opendkim

Modifier le socket utilisé par opendkim dans le fichier /etc/default/opendkim

SOCKET="local:/var/spool/postfix/opendkim/opendkim.sock"

Sur Debian 8, il faut régénérer le fichier du service pour que la variable SOCKET de debian soit prise en compte. Si on ne régénère pas le fichier, le SOCKET sera toujours celui dans le fichier /etc/opendkim.conf.

root@machine# /lib/opendkim/opendkim.service.generate
root@machine# systemctl daemon-reload

Solution trouvée sur serverfault.com

Ajouter les configurations à la fin du fichier /etc/postfix/main.cf:

milter_default_action = accept
milter_protocol = 6
smtpd_milters = local:/opendkim/opendkim.sock
non_smtpd_milters = local:/opendkim/opendkim.sock

Note: postfix fonctionne dans un environnement chrooté, c'est à dire que la racine est /var/spool/postfix, c'est pourquoi le chemin est différent dans le fichier /etc/default/opendkim et /etc/postfix/main.cf.

Finalement, on redémarre les deux services

root@machine# service opendkim restart
root@machine# service postfix reload