Introduction
DKIM works by interfacing a proxy in postfix to add priv/pub signature to out-going emails using a private key and opendkim.
Matching public key will be exported in the DNS server so receiving SMTP can verify in the signature in the metadata matches the public key.
It helps for non being consider as a spamer.
A friend asked me to setup this on his two servers with two different domains so we’ll be setting up the whole thing here with separate keys pair for each domain/each server and we’ll allow both servers to sign emails for these domains.
Install required packages
1 |
apt install opendkim opendkim-tools rename dnsutils |
Create pub/priv keys sets
According to /usr/share/doc/opendkim/README.Debian.gz there is a tool named opendkim-genkey that can help generating the key pairs. This tool is in opendkim-tools package.
As we want to allow different servers to sign messages with different key but for the same domain, we’ll use the origin server short hostname as selector. It means the signature will be somehow prefixed with this selector, indicating the receiver SMTP which DNS entry should be queried for getting associated public key. By doing so, we’ll be able to export different public key for each server.
1 2 3 4 5 6 7 8 |
opendkim-genkey -b 1024 -d domain1.com -s `hostname -s` --directory=/etc/dkimkeys/ rename "s/`hostname -s`/`hostname -s`_domain1.com/" /etc/dkimkeys/`hostname -s`.{txt,private} opendkim-genkey -b 1024 -d domain2.com -s `hostname -s` --directory=/etc/dkimkeys/ rename "s/`hostname -s`/`hostname -s`_domain2.com/" /etc/dkimkeys/`hostname -s`.{txt,private} chown opendkim:opendkim /etc/dkimkeys/`hostname -s`_* chmod 0600 /etc/dkimkeys/`hostname -s`_* |
Now you should see the private keys as well as public key as a bind9 snippet in /etc/dkimkeys:
1 2 3 4 5 6 7 |
drwx------ 2 opendkim opendkim 4.0K May 29 22:40 . drwxr-xr-x 109 root root 8.0K May 29 22:11 .. -rw-r----- 1 root opendkim 887 May 29 22:39 ns1234_domain1.com.private -rw-r----- 1 root opendkim 329 May 29 22:39 ns1234_domain1.com.txt -rw-r----- 1 root opendkim 887 May 29 22:40 ns1234_domain2.com.private -rw-r----- 1 root opendkim 339 May 29 22:40 ns1234_domain2.com.txt -rw-r--r-- 1 root root 664 Nov 7 2015 README.PrivateKeys |
Register public key in DNS zones
Now you need to add the public signature in your DNS zone. In this example, the primary bind server for both domain1.com and domain2.com is running on the server itself so we can just do:
1 2 |
cat /etc/dkimkeys/`hostname -s`_domain1.com.txt >> /etc/bind/zones/domain1.com cat /etc/dkimkeys/`hostname -s`_domain2.com.txt >> /etc/bind/zones/domain2.com |
This is very unlikely that method is suitable for you, but you get the idea right ?
Don’t forget to bump DNS zone serial number and reload bind
1 2 3 |
sed -i "s/20\(1\|2\)[0-9][0-9]\{2\}[0-9]\{2\}[0-9]\{2\}/`date "+%Y%m%d01"`/" /etc/bind/zones/domain1.com sed -i "s/20\(1\|2\)[0-9][0-9]\{2\}[0-9]\{2\}[0-9]\{2\}/`date "+%Y%m%d01"`/" /etc/bind/zones/domain2.com systemctl reload bind9 |
We can now check with dig that our DNS server now expose the public key:
1 |
dig -t TXT `hostname -s`._domainkey.domain1.com @127.0.0.1 |
Should return something like:
1 2 3 4 5 |
;; QUESTION SECTION: ;ns1234._domainkey.domain1.com. IN TXT ;; ANSWER SECTION: ns1234._domainkey.domain1.com. 600 IN TXT "v=DKIM1; h=sha256; k=rsa; " "p=aaa1111bbbb3333cccc" |
Configure OpenDKIM
Now we need to create a KeyTable file to match domain, selector and private key file. We also need a SigningTable to actually ask for signature to be added to outgoing emails.
In /etc/opendkim.conf add the following entries at bottom of files:
1 2 3 |
LogWhy yes KeyTable refile:/etc/dkimkeys/KeyTable SigningTable refile:/etc/dkimkeys/SigningTable |
Then we we’ll create /etc/dkimkeys/KeyTable file:
1 2 |
echo -e "domain1.com domain1.com:`hostname -s`:/etc/dkimkeys/`hostname -s`_domain1.com.private" >> /etc/dkimkeys/KeyTable echo -e "domain2.com domain2.com:`hostname -s`:/etc/dkimkeys/`hostname -s`_domain2.com.private" >> /etc/dkimkeys/KeyTable |
The file now looks like:
1 2 |
domain1.com domain1.com:ns1234:/etc/dkimkeys/ns1234_domain1.com.private domain2.com domain2.com:ns1234:/etc/dkimkeys/ns1234_domain2.com.private |
Now we create /etc/dkimkeys/SigningTable file:
1 2 |
echo "*@domain1.com domain1.com" >> /etc/dkimkeys/SigningTable echo "*@domain2.com domain2.com" >> /etc/dkimkeys/SigningTable |
The file should content:
1 2 |
*@domain1.com domain1.com *@domain2.com domain2.com |
OpenDKIM is now configured, restart it
1 |
systemctl restart opendkim |
Integrate with Postfix
On Debian systems Postfix is chrooted so there are a few additionnal steps to get it working correctly:
In /etc/opendkim.conf change the socket path to Postifx chroot:
1 |
Socket local:/var/spool/postfix/var/run/opendkim/opendkim.sock |
Create proper folder in Postfix chroot and give proper permissions
1 2 |
mkdir -p /var/spool/postfix/var/run/opendkim chown opendkim:opendkim /var/spool/postfix/var/run/opendkim |
Add Postfix to opendkim group so it can write to the socket:
1 |
adduser postfix opendkim |
Enable filtering in postfix (postconf commands will edit /etc/postfix/main.cf):
Missing trailling / is not a typo !
1 2 3 4 |
postconf -e milter_protocol=6 postconf -e milter_default_action=accept postconf -e smtpd_milters=unix:var/run/opendkim/opendkim.sock postconf -e non_smtpd_milters=unix:var/run/opendkim/opendkim.sock |
Restart both services:
1 2 |
systemctl restart opendkim systemctl restart postfix |
Testing
You can send an email from the server itself using following commands:
1 2 |
echo "This is a test" | mail -s "Test DKIM domain1.com" -a "From: test@domain1.com" your@real.email echo "This is a test" | mail -s "Test DKIM domain2.com" -a "From: test@domain2.com" your@real.email |
My your@real.email server runs Postfix with Amavis so I can check the header of the email I just received and I can confirm valid DKIM signature has been seen:
1 |
X-Spam-Status: No, [...] DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VERIFIED=-0.5 [...] |