5.5 KiB
SPF and DKIM for Exim on FreeBSD and Debian
This work is motivated by Google, Yahoo, et alia outsourcing their spam problems to smaller folk such as I. Read Google's latest requirements.
Note that, at this writing, Google et alia are only asking for SPF and DKIM unless you are running a large bulk mailer. For the latter, ARC is also needed. As I do not run a large bulk mailer, I ignore ARC; at least this season.
This recipe set assumes the Debian or FreeBSD is current. It works on Buster and Bookworm and FreeBSD 13 with Exim 4.97. YMMV. A variant actually worked on Ubuntu 18.04.6 LTS (Bionic Beaver).
ARC
Currently, Exim packages for FreeBSD and Debian do not come with ARC enabled. It has been in experimental status for three years. I have no idea how folk are supposed to experiment. Humph!
SPF
SPF is just some gorp in the dns saying which FQDN and/or IP addresses can SMTP send from a particular domain. In the foo.com zone, it's just a TXT record, a la
foo.com. TXT "v=spf1 mx a ip4:1.2.3.4/32 ip6:1:2:3::4/126 a:sending.fqdn -all"
This says that mail with the sender of user@foo.com can legitimately be sent from that IPv4 or IPv6 space or from the host whose FQDN is sending.fqdn.
DKIM
DKIM is more complex and requires configuration of the MTA, Mail Transfer Agent, Exim in this case.
Generate DKIM Key Pair(s)
For each domain from which mail will be sent with sender user@foo, generate an RSA key pair for that domain. Google, bless their hearts, does not accept ED25519. The size of the private key should be at least 1024 bits. The 2048 bit key I prefer is a bit large, and makes a mess in the DKIM DNS record.
openssl genrsa -out foo.private 2048
openssl rsa -in foo.private -out foo.public -pubout -outform PEM
As I have a lot of sender domains, i have a directory dkim under the
Exim CONFDIR which I rsync from my main maintenance host to all Exim
SMTP senders.
$ ls /etc/exim4/dkim/
balletpixelle.org.private katandmaouche.com.public ran.psg.com.public
balletpixelle.org.public katenbush.com.private rg.net.private
bogus.com.private katenbush.com.public rg.net.public
bogus.com.public psg.com.private ymbk.com.private
do-dkim-gen* psg.com.public ymbk.com.public
katandmaouche.com.private ran.psg.com.private
This means that I need to hack Exim code to select the private key based
on ${sender_address_domain}, see below.
DKIM DNS Entry
First, decide on a DKIM-SELECTOR, an arbitrary name that will enable
the receiver to look your DKIM record up in your DNS zone. I chose
rgnet-mail and use it in all my DNS zones. Please use something
different :)
for the DNS entry, the public key payload is too large to fit in one stanza, so in, e.g. the myzone zone, I break it in half, a la
rgnet-mail._domainkey.myzone. TXT ( "v=DKIM1; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAu5rp4ph1mAhTS0nQ4VOGvDlBR1sfMrzCnED8FXPiPtHRDLiFF57HiTRjA56iVWCNPt5r79AexgngR4jLIdJMJ1+ISmfLqWiLo5G9GOh7J0CuVMXBK1iTxRiKWd/TIfhWqr919iwvjwxMAO7TjDNX"
"Dt/qZAmFUT+RCj6EIibg3E8Lt30qh5WZsMWFAB+4fCCf7UvBGVsEEOFUjLPsXDdyadBJxNnt3U7q+6p+vG16JwoimGp0onNqlladneBHTVbLPLloAVEv3zqVRBx8s1Smrt3/vp0AxLkjKkRAlJgvi2uiSAbaSukpvSNH+Gt4RRtK8yQWjxOfPDHveaxR0MEqgwIDAQAB" )
Those quote marks, ", are necessary.
Exim Configuration
First, ensure the Exim binary you are running supports DKIM.
$ exim -bV | grep Support
Support for: Content_Scanning crypteq Expand_dlfunc iconv() IPv6 PAM Perl OpenSSL TLS_resume use_setclassresources DKIM DNSSEC Event I18N OCSP PIPECONNECT PRDR Queue_Ramp SPF TCP_Fast_Open
Exim on FreeBSD
On FreeBSD, Exim requires an incantation for the SMTP transport(s).
The lookup glorp is to 'untaint' the file reference, an Exim
incantation to reduce the attack surface via malicious
${sender_address_domain}.
The normal Exim configuration section needing modification is the
remote_smtp transport. If you have multiple transports which use
the smtp driver, you may want to consider which need similar hacks.
DKIM_F = ${lookup {${sender_address_domain}.private} dsearch,ret=full {/usr/local/etc/exim/dkim}}
remote_smtp:
driver = smtp
tls_certificate = /usr/local/etc/exim/exim.crt
dkim_canon = relaxed
dkim_selector = rgnet-mail
dkim_domain = ${sender_address_domain}
dkim_private_key = ${if exists{DKIM_F}{DKIM_F}{0}}
message_linelength_limit = 52428800
If you have only one private key, you can probably skip the untainting. and just name it. I have not tried this.
Note that the dkim_selector, rgnet-mail, matches the selector in
the DNS record above.
Of course, you may have a different file where you stash your TLS certificate. And you might be more or less generous in the size of long lines :)
Exim on Debian
On Debian, the Exim hack is up front in the MAIN CONFIGURATION
SETTINGS, either in /etc/exim4/exim4.conf.template if you use the
single configuration file approach, or in
/etc/exim4/conf.d/main/01_exim4-config_listmacrosdefs if you use the
decomposed configuration option.
In either case, it is pretty simple, as in
DKIM_CANON = relaxed
DKIM_DOMAIN = ${sender_address_domain}
DKIM_F = ${lookup {DKIM_DOMAIN.private} dsearch,ret=full {CONFDIR/dkim}}
DKIM_PRIVATE_KEY = ${if exists{DKIM_F}{DKIM_F}{0}}
DKIM_SELECTOR = rgnet-mail
If you adventure down to the SMTP transport, you will see that the configuration conditionals stitch this all into the transport in the usual arcane Exim fashion.
2024.01.07