Aprè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 un p=quarantine
auquel on ajoute un pct=x
, x
variant de 0 à 100, puis on passe à p=reject
avec le pct=x
qui repart de 0 jusqu’à 100…
Docs:
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.