Guillaume Vaillant : postfix, spf, dkim, dmarc avec plusieurs domaines
mardi 13 janvier 2015 à 15:53Après m’être un peu battu, voilà mes notes
Cas d’utilisation:
{ Internet }----[ relai smtp dmz ]----[ serveur de mail réel bien à l'abri ]
Du coup, sur le relai en DMZ, niveau SMTP, je gère toute la partie:
- vérification spf/dkim/dmarc des mails qui arrivent ;
- signature (dkim) des messages qui partent ;
- authentification pour ceux qui envoient les mails.
Tout ce qui est anti-spam/anti-virus se fait sur la machine réelle.
Bien entendu, je gère aussi les mails pour plusieurs domaines.
Prérequis/divers
- un postfix qui marche (c’est à dire: reverse dns correct, pas en mode relai ouvert, et qui sait déjà envoyer/recevoir des mails) ;
- avoir au moins jeté un œil sur les RFC et autres documentes de référence pour DKIM/DMARC et SPF histoire de savoir ce que c’est et comment ça marche1 ;
- un serveur DNS fonctionnel (pas un truc qui bloque/filtre les enregistrement TXT/SRV)
- pour info: la partie DKIM (signature+vérification) peut aussi se faire avec amavisd.
SPF
DNS
enregistrement TXT et/ou SRV (j’utilise un a:…
et pas mx
car tous les MX n’ont pas vocation à envoyer du mail pour un domaine donné):
example.net IN TXT "v=spf1 a:smtp.example.net ~all" example.net IN SRV "v=spf1 a:smtp.example.net ~all"
note: On peut remplacer le ~all (softfail) par
-all
(fail)
Postfix
But, seulement avoir un entête Received-SPF:
qui sera utilisé par la suite. Mais ceux qui veulent peuvent aussi avoir des bounces quand il n’y a pas d’enregistrement SPF ou quand le teste échoue.
postfix-policyd-spf-python
Installer le package si nécessaire, puis le configurer (/etc/postfix/policyd-spf.conf):
debugLevel = 1 defaultSeedOnly = 0 HELO_reject = False Mail_From_reject = False PermError_reject = False TempError_Defer = False skip_addresses = 127.0.0.0/8,::ffff:127.0.0.0//104,::1//128,subnetLAN,ipPubliques
postfix/main.cf
smtpd_recipient_restrictions = […votre bazar habituel…] check_policy_service unix:private/policyd-spf
postfix/master.cf
policyd-spf unix - n n - 0 spawn user=nobody argv=/usr/bin/python /usr/bin/policyd-spf /etc/postfix/policyd-spf.conf
DKIM
opendkim
/etc/default/opendkim
SOCKET="local:/var/spool/postfix/var/run/opendkim/opendkim.sock"
note: la socket doit-être dans le chroot de postfix, sinon, postfix ne la verra jamais (cf: saslauthd), ce qui implique:
mkdir /var/spool/postfix/var/run/opendkim/ chown opendkim:opendkim /var/spool/postfix/var/run/opendkim/ adduser postfix opendkim
/etc/opendkim.conf
Syslog yes SyslogFacility mail LogWhy no X-Header no UMask 002 AutoRestart yes AutoRestartCount 5 RequireSafeKeys no InternalHosts /etc/postfix/dkim/trusted.dat ExternalIgnoreList /etc/postfix/dkim/trusted.dat KeyTable /etc/postfix/dkim/keys.dat SigningTable /etc/postfix/dkim/signing.dat Canonicalization relaxed/relaxed Mode sv DisableADSP yes OversignHeaders From
LogWhy
est utile en phase de debug/tests, période où le mettre à yes est utile. Idem pour X-Header
qui sert juste à savoir si on est bien passé dans opendkim.
/etc/postfix/dkim/trusted.dat
## localhost 127.0.0.1 localhost ::1 ## localnet (local.example.net) 192.168.1.0/24 fe80::/10 local.example.net
/etc/postfix/dkim/signing.dat
# "pattern" "%selector%._domainkey.%domain% example.net example._domainkey.example.net example.com example._domainkey.example.com exemple.fr example._domainkey.exemple.fr
notes:
- On peut utiliser un selector différent par domaine si on le souhaite
- On peut utiliser une clé différente par domaine si on le souhaite
/etc/postfix/dkim/keys.dat
#format: # selector._domainkey.domain domain:selector:/path/to/private/key example._domainkey.example.net example.net:example:/etc/postfix/dkim/example.private example._domainkey.example.com example.com:example:/etc/postfix/dkim/example.private example._domainkey.exemple.fr exemple.fr:example:/etc/postfix/dkim/example.private
Clés
On génère la clé privée:
openssl genrsa -out /etc/postfix/dkim/example.private 2048
note: On peut se limiter à 1024, mais ça n’est pas recommandé.
On extrait la clé publique:
openssl rsa -inform PEM -outform PEM -in /etc/postfix/dkim/example.private -out /etc/postfix/dkim/example.txt -pubout
On la formatte pour l’enregistrement DNS:
grep -ve "BEGIN PUBLIC KEY" -ve "END PUBLIC KEY" -ve '^\\s*$' /etc/postfix/dkim/example.txt | base64
Pour cette clé publique:
-----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAp/ugSjDXVPt9CnwGhtty b3wG/uJW/Roi3D/woYrHBspi/ToYS3Su4KsNx44FS01AcOHwPkT3jBPcyjPc63rk 1lAskDSFoShZL8sTT5NB9a8NoA++vObNEGWSbqLRdgQ1KexEoC/90pSeBb9L2YDB NKlyQYTq0ePDfPleTuotD0JFxyEHxXM+9oxa0FtbaAhJhqi9rgH0+PDgfJnPkKhS Og6O1nI2cQm1zQmg+hoCW0s7j973uSIpyNhfXxfBIF2/8ff/enBCFAQzfZK8jiUx KDOLmW2XwVGFGrQIAuuCZgX4O+r8e4WyVRYQBnlUaffrU+PpO7jVRmH25SLox1aV gQIDAQAB -----END PUBLIC KEY-----
ça donne:
TUlJQklqQU5CZ2txaGtpRzl3MEJBUUVGQUFPQ0FROEFNSUlCQ2dLQ0FRRUFwL3VnU2pEWFZQdDlDbndHaHR0eQpiM3dHL3VKVy9Sb2kzRC93b1lySEJzcGkvVG9ZUzNTdTRLc054NDRGUzAxQWNPSHdQa1QzakJQY3lqUGM2M3JrCjFsQXNrRFNGb1NoWkw4c1RUNU5COWE4Tm9BKyt2T2JORUdXU2JxTFJkZ1ExS2V4RW9DLzkwcFNlQmI5TDJZREIKTktseVFZVHEwZVBEZlBsZVR1b3REMEpGeHlFSHhYTSs5b3hhMEZ0YmFBaEpocWk5cmdIMCtQRGdmSm5Qa0toUwpPZzZPMW5JMmNRbTF6UW1nK2hvQ1cwczdqOTczdVNJcHlOaGZYeGZCSUYyLzhmZi9lbkJDRkFRemZaSzhqaVV4CktET0xtVzJYd1ZHRkdyUUlBdXVDWmdYNE8rcjhlNFd5VlJZUUJubFVhZmZyVStQcE83alZSbUgyNVNMb3gxYVYKZ1FJREFRQUIK
DNS
enregistrement TXT
example._domainkey.example.net IN TXT "k=rsa; t=s; p=cléPublique" example._domainkey.example.com IN TXT "k=rsa; t=s; p=cléPublique" example._domainkey.exemple.fr IN TXT "k=rsa; t=s; p=cléPublique"
notes:
- La clé est encodée en base64
- Il ne faut pas oublier les ; entre les champs
Postfix
main.cf
En fin de fichier, on ajoute:
milter_default_action = accept milter_protocol = 6 smtpd_milters = unix:/var/run/opendkim/opendkim.sock non_smtpd_milters = unix:/var/run/opendkim/opendkim.sock
note: Cette partie ne permet d’avoir que la vérification des éventuelles signatures des messages reçus
master.cf
Si on veut que les messages sortant soient bien signés:
submission inet n - - - - smtpd […votre bazar habituel…] -o smtpd_milters=unix:/var/run/opendkim/opendkim.sock smtps inet n - - - - smtpd […votre bazar habituel…] -o smtpd_milters=unix:/var/run/opendkim/opendkim.sock
DMARC
Installation d’opendmarc
Pour ceux qui tournent en Debian stable, il est disponible dans les backports, il faut donc au préalable:
Ajouter la source qui va bien dans apt (/etc/apt/sources.list.d/deb_bpo.list):
deb http://ftp.fr.debian.org/debian/ wheezy-backports main contrib non-free
Ajouter le pining qui va bien pour ne pas installer par défaut un package backporté plutôt qu’un officiel (/etc/apt/preferences.d/pining):
Package: * Pin: release a=stable Pin-Priority: 900 Package: * Pin: release a=wheezy-backports Pin-Priority: 1 Package: * Pin: release a=testing Pin-Priority: -10 Package: * Pin: release a=experimental Pin-Priority: -10 Package: * Pin: release a=oldstable Pin-Priority: -10
Configuration d’opendmarc
/etc/default/opendmarc
SOCKET="local:/var/spool/postfix/var/run/opendmarc/opendmarc.sock"
note: Comme pour opendkim ou saslauthd, on met la socket dans le chroot de postfix:
mkdir /var/spool/postfix/var/run/opendmarc/ chown opendmarc:opendmarc /var/spool/postfix/var/run/opendmarc/ adduser postfix opendmarc
/etc/opendmarc.conf
AuthservID HOSTNAME PidFile /var/run/opendmarc.pid RejectFailures false Syslog true SyslogFacility mail TrustedAuthservIDs HOSTNAME UMask 0002 UserID opendmarc:opendmarc IgnoreHosts /etc/postfix/dkim/trusted.dat AuthservIDWithJobID true
notes:
- On peut remplacer le
HOSTNAME
par le$myorigin
ou le$myhostname
de postfix. - On réutilise une partie de la conf de opendkim (le trusted.dat).
Configuration de postfix
postfix/main.cf
Il suffit de modifier les lignes smtpd_milters et non_smtpd_milters, en ajoutant à la fin le chemin vers la socket d’opendmarc (chemin relatif au chroot de postfix)
smtpd_milters = unix:/var/run/opendkim/opendkim.sock,unix:/var/run/opendmarc/opendmarc.sock non_smtpd_milters = unix:/var/run/opendkim/opendkim.sock,unix:/var/run/opendmarc/opendmarc.sock
DNS
Enregistrements TXT comme suit:
_dmarc.example.net IN TXT "v=DMARC1; rf=afrf; p=none; rua=mailto:postmaster@example.net" _dmarc.example.com IN TXT "v=DMARC1; rf=afrf; p=none; rua=mailto:postmaster@example.com" _dmarc.exemple.fr IN TXT "v=DMARC1; rf=afrf; p=none; rua=mailto:postmaster@exemple.fr"
note:
- Le mail dans le champs
rua
doit matcher le domaine dans_dmarc…
. - La mise en place de DMARC est progressive: on commence avec un
p=none
, puis unp=quarantine
auquel on ajoute unpct=x
,x
variant de 0 à 100, puis on passe àp=reject
avec lepct=x
qui repart de 0 jusqu’à 100…
Docs:
- http://www.openspf.org/
- spécifications de SPF
- présentation de SPF chez Google
- http://www.opendkim.org/
- spécifications de DKIM
- présentation de DKIM chez Google
- http://www.dmarc.org/
- spécification de DMARC
- présentation de DMARC chez Google
Exemple:
Quand tout marche bien, on trouve ce genre de choses:
Jan 13 12:47:29 MX postfix/smtpd[3255]: 2557039028: client=mail-lb0-x230.google.com[2a00:1450:4010:c04::230] Jan 13 12:47:29 MX postfix/cleanup[2864]: 2557039028: message-id=Jan 13 12:47:29 MX opendkim[61062]: 2557039028: mail-lb0-x230.google.com [2a00:1450:4010:c04::230] not internal Jan 13 12:47:29 MX opendkim[61062]: 2557039028: not authenticated Jan 13 12:47:29 MX opendmarc[2585]: 2557039028: gmail.com pass
Jan 13 15:13:06 MX postfix/smtpd[19051]: 8E86D39028: client=somehost.somedomain.net[x.y.z.t] Jan 13 15:13:06 MX postfix/cleanup[19046]: 8E86D39028: message-id=Jan 13 15:13:06 MX opendkim[61062]: 8E86D39028: somehost.somedomain.net[x.y.z.t] not internal Jan 13 15:13:06 MX opendkim[61062]: 8E86D39028: not authenticated Jan 13 15:13:06 MX opendkim[61062]: 8E86D39028: no signature data Jan 13 15:13:06 MX opendmarc[2585]: 8E86D39028: somedomain.net none
Original post of Guillaume Vaillant.Votez pour ce billet sur Planet Libre.
Articles similaires
- Guillaume Vaillant : Cryptage de partitions sous Linux (04/07/2012)
- Guillaume Vaillant : Corriger le “Postfix untrusted TLS certificate” (16/01/2015)
- Guillaume Vaillant : Install et conf de base d’une Debian (14/06/2012)
- Guillaume Vaillant : Appliquer automatiquement les mises à jour de sécurité de Debian (05/12/2012)
- Guillaume Vaillant : OpenVPN: log et fail2ban (06/01/2014)