How to run Postfix with OpenDKIM on FreeBSD 9.0

Prime knots chartOpenDKIM is an open source implementation of the DKIM (Domain Keys Identified Mail) sender authentication system proposed by the E-mail Signing Technology Group (ESTG), now standardized by the IETF (RFC 6376). It also includes implementations of the Author Domain Signing Practises (ADSP, RFC 5617) and Vouch By Reference (VBR, RFC 5518) proposed standards.

The OpenDKIM package consists of a library that implements the DKIM service and a milter-based filter application that can plug in to any milter-aware MTA to provide that service to sufficiently recent sendmail MTAs and other MTAs that support the milter protocol.

I’m going to show you how to run Postifx with OpenDKIM on a fresh-installed FreeBSD 9.0. Some steps involve some changes on a DNS server. If you need help with DNS setup consider reading my article How to run master and slave NSD on FreeBSD 9.0 or How to run master NSD on FreeBSD 10.0

Let’s start installing Postfix.

cd /usr/ports/mail/postfix
make install clean

Then allow Postfix starting at boot time:
echo 'postfix_enable="YES"' >> /etc/rc.conf

Prepare the installation of OpenDKIM adding an opendkim user:
pw useradd -n opendkim -d /var/db/opendkim -g mail -m -s "/usr/sbin/nologin" -w no

Now install OpenDKIM:

cd /usr/ports/mail/opendkim
make install clean

Then allow OpenDKIM starting at boot time and executing as opendkim user (thanks Sugo Balugo for spotting a typo here):

echo 'milteropendkim_enable="YES"' >> /etc/rc.conf
echo 'milteropendkim_uid="opendkim"' >> /etc/rc.conf

Edit Postfix configuration file:
vi /usr/local/etc/postfix/main.cf

and instruct postfix to use dkim milter:

smtpd_milters = inet:127.0.0.1:8891
non_smtpd_milters = $smtpd_milters
milter_default_action = accept

Use a sample configuration file for OpenDKIM:
cp /usr/local/share/doc/opendkim/opendkim.conf.simple /usr/local/etc/opendkim.conf

Edit the configuration file:
vi /usr/local/etc/opendkim.conf

Feel free to use the following one slightly edited to work with myzone.demo domain:

LogWhy yes
Syslog yes
SyslogSuccess yes
Canonicalization relaxed/simple
Domain myzone.demo
Selector MYDEMO
KeyFile /var/db/opendkim/MYDEMO.private
Socket inet:8891@localhost
ReportAddress root
SendReports yes

Now generate the keys: one will be used by opendkim to sign your messages and the other to be inserted in your dns zone:
opendkim-genkey -D /var/db/opendkim -d myzone.demo -s MYDEMO

Verify what that command produced:
ls /var/db/opendkim
MYDEMO.private
MYDEMO.txt

Now insert MYDEMO.txt content in myzone.demo dns zone.
cat MYDEMO.txt
MYDEMO._domainkey IN TXT "v=DKIM1;=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDOcRbLGARxEFI9Ibwx79tk1kMi36rFeAT4aLu4iI3ctPUWa7y0WcuMZGCBQMMutolT8IM9e55AToqtr/W/rbKlhoeiA0r8qJZiIX/NkjkLIXzR+9h1i47dD5zCu4u436YN0y4DgZU9bZ3D4hvoC9hSHCcCwzosSRwBpaxIMZuRGQIDAQAB" ; ----- DKIM MYDEMO for myzone.demo

Be careful: before “=rsa” a ‘k’ is missing, so the correct TXT record would be:
MYDEMO._domainkey IN TXT "v=DKIM1;k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDOcRbLGARxEFI9Ibwx79tk1kMi36rFeAT4aLu4iI3ctPUWa7y0WcuMZGCBQMMutolT8IM9e55AToqtr/W/rbKlhoeiA0r8qJZiIX/NkjkLIXzR+9h1i47dD5zCu4u436YN0y4DgZU9bZ3D4hvoC9hSHCcCwzosSRwBpaxIMZuRGQIDAQAB" ; ----- DKIM MYDEMO for myzone.demo

In RFC 5617 has been adopted “Author Domain Signing Practices” (ADSP). It means that a domain can publish the signing practices it adopts when relaying mail on behalf of associated authors. So, insert also the ADSP record in your zone:
_adsp._domainkey.myzone.demo    IN    TXT    "dkim=unknown"

Make a query just to verify:
dig +norec @localhost -t TXT MYDEMO._domainkey.myzone.demo

; <<<< DiG 9.7.3 >>>> +norec @localhost -t TXT MYDEMO._domainkey.myzone.demo
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER< ;; flags: qr aa; QUERY: 1, ANSWER: 1, AUTHORITY: 2, ADDITIONAL: 2
;; QUESTION SECTION:
;MYDEMO._domainkey.myzone.demo. IN TXT
;; ANSWER SECTION:
MYDEMO._domainkey.myzone.demo. 3600 IN TXT "v=DKIM1\;k=rsa\; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDOcRbLGARxEFI9Ibwx79tk1kMi36rFeAT4aLu4iI3ctPUWa7y0WcuMZGCBQMMutolT8IM9e55AToqtr/W/rbKlhoeiA0r8qJZiIX/NkjkLIXzR+9h1i47dD5zCu4u436YN0y4DgZU9bZ3D4hvoC9hSHCcCwzosSRwBpaxIMZuRGQIDAQAB"
;; AUTHORITY SECTION:
myzone.demo. 3600 IN NS ns1.myzone.demo.
myzone.demo. 3600 IN NS ns2.myzone.demo.
;; ADDITIONAL SECTION:
ns1.myzone.demo. 3600 IN A 192.0.2.1
ns2.myzone.demo. 3600 IN A 192.0.2.2
;; Query time: 0 msec
;; SERVER: 127.0.0.1#53(127.0.0.1)
;; WHEN: Thu Apr 26 15:10:14 2012
;; MSG SIZE rcvd: 361

dig +norec @localhost -t TXT _adsp._domainkey.myzone.demo

; <<>> DiG 9.7.3 <<>> +norec @localhost -t TXT _adsp._domainkey.myzone.demo
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 6597
;; flags: qr aa; QUERY: 1, ANSWER: 1, AUTHORITY: 2, ADDITIONAL: 2
;; QUESTION SECTION:
;_adsp._domainkey.myzone.demo. IN TXT
;; ANSWER SECTION:
_adsp._domainkey.myzone.demo. 3600 IN TXT "dkim=unknown"
;; AUTHORITY SECTION:
myzone.demo. 3600 IN NS ns1.myzone.demo.
myzone.demo. 3600 IN NS ns2.myzone.demo.
;; ADDITIONAL SECTION:
ns1.myzone.demo. 3600 IN A 192.0.2.1
ns2.myzone.demo. 3600 IN A 192.0.2.2
;; Query time: 0 msec
;; SERVER: 127.0.0.1#53(127.0.0.1)
;; WHEN: Thu Apr 26 19:22:51 2012
;; MSG SIZE rcvd: 139

That’s fine.

Make sure your server can resolve myzone.demo via the nameservers listed in /etc/resolv.conf
Now test the key using an OpenDKIM utiliy:
opendkim-testkey -vvv -d myzone.demo -s MYDEMO -k /var/db/opendkim/MYDEMO.private
opendkim-testkey: key loaded from /var/db/opendkim/MYDEMO.private
opendkim-testkey: checking key ‘MYDEMO._domainkey.myzone.demo’
opendkim-testkey: key OK

Now start both OpenDKIM and Postifix:

/usr/local/etc/rc.d/milter-opendkim start
/usr/local/etc/rc.d/postfix start

Send an e-mail messagge:

telnet localhost 25
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
220 freebsddemo.localdomain ESMTP Postfix
helo myzone.demo
250 freebsddemo.localdomain
mail from:[email protected]
250 2.1.0 Ok
rcpt to:root@freebsddemo
250 2.1.5 Ok
data
354 End data with .
mytest
.
250 2.0.0 Ok: queued as 17882B9EB
quit
221 2.0.0 Bye

Verify in your maillog
tail /var/log/maillog
Apr 26 16:23:57 freebsddemo postfix/smtpd[1512]: connect from localhost[127.0.0.1]
Apr 26 16:24:23 freebsddemo postfix/smtpd[1512]: 17882B9EB: client=localhost[127.0.0.1]
Apr 26 16:24:27 freebsddemo postfix/cleanup[1515]: 17882B9EB: message-id=
Apr 26 16:24:27 freebsddemo opendkim[989]: 17882B9EB: DKIM-Signature header added (s=MYDEMO, d=myzone.demo)
Apr 26 16:24:27 freebsddemo postfix/qmgr[1499]: 17882B9EB: from=, size=357, nrcpt=1 (queue active)
Apr 26 16:24:27 freebsddemo postfix/local[1516]: 17882B9EB: to=, orig_to=, relay=local, delay=15, delays=15/0.01/0/0, dsn=2.0.0, status=sent (delivered to mailbox)
Apr 26 16:24:27 freebsddemo postfix/qmgr[1499]: 17882B9EB: removed
Apr 26 16:24:29 freebsddemo postfix/smtpd[1512]: disconnect from localhost[127.0.0.1]

Signature added.
Now read your e-mail:

mail
Mail version 8.1 6/6/93. Type ? for help.
"/var/mail/root": 1 message 1 unread
>U 1 [email protected] Thu Apr 26 16:24 20/819
& 1
Message 1:
From [email protected] Thu Apr 26 16:24:27 2012
X-Original-To: root@freebsddemo
Delivered-To: [email protected]
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=myzone.demo;
s=MYDEMO; t=1335450267;
bh=VO5wxPKuPx30V5DeAzbu5EKUyhb1ecy+Cexvd5E0Ulc=; h=Date:From;
b=M8xgIutWSE9sg2ZOAAFsyCHhtEzG3WtinOji/j8d/Di59Dh/nL42LeXlhWXbs8Rp9
TviK4t0r29gu9bX0USyo+8gv0Y3AaptDG0RhhZhbntqTANxQ6a7gECCIsqqYpXCWT7
WQZ3CVbe1FC2JnYLM/DHtpFvvviJH0zYLFqzo8ks=
Date: Thu, 26 Apr 2012 16:24:12 +0200 (CEST)
From: [email protected]
mytest
& quit
Saved 1 message in mbox

Look at the DKIM-signature, there it is.

Further check and analysis can be made also on the website http://www.brandonchecketts.com/emailtest.php

But, since the domain we’re using, myzone.demo, is not under a valid TLD, we’re going to use a simple workaround to make our e-mail message reach the recipient for the analysis.

From the site http://www.brandonchecketts.com/emailtest.php copy the temporary e-mail address offered and put that in /etc/aliases as root external address:
vi /etc/aliases
root: [email protected]

make Postfix aware of that change:
postalias /etc/aliases

Now, resend an e-mail message:

telnet localhost 25
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
220 freebsddemo.localdomain ESMTP Postfix
helo myzone.demo
250 freebsddemo.localdomain
mail from:[email protected]
250 2.1.0 Ok
rcpt to:root@freebsddemo
250 2.1.5 Ok
data
354 End data with .
mytest
.
250 2.0.0 Ok: queued as 17882B9EB
quit
221 2.0.0 Bye

Verify in your maillog:
tail /var/log/maillog
Apr 26 18:59:52 freebsddemo postfix/smtpd[1271]: connect from localhost[127.0.0.1]
Apr 26 19:00:11 freebsddemo postfix/smtpd[1271]: C7974BB6C: client=localhost[127.0.0.1]
Apr 26 19:00:19 freebsddemo postfix/cleanup[1290]: C7974BB6C: message-id=<[email protected]>
Apr 26 19:00:19 freebsddemo opendkim[1005]: C7974BB6C: DKIM-Signature header added (s=MYDEMO, d=myzone.demo)
Apr 26 19:00:19 freebsddemo postfix/qmgr[1082]: C7974BB6C: from=, size=363, nrcpt=1 (queue active)
Apr 26 19:00:19 freebsddemo postfix/cleanup[1290]: 8025BC039: message-id=<[email protected]>
Apr 26 19:00:19 freebsddemo postfix/local[1291]: C7974BB6C: to=, orig_to=, relay=local, delay=16, delays=16/0/0/0, dsn=2.0.0, status=sent (forwarded as 8025BC039)
Apr 26 19:00:19 freebsddemo postfix/qmgr[1082]: 8025BC039: from=, size=854, nrcpt=1 (queue active)
Apr 26 19:00:19 freebsddemo postfix/qmgr[1082]: C7974BB6C: removed
Apr 26 19:00:20 freebsddemo postfix/smtpd[1271]: disconnect from localhost[127.0.0.1]
Apr 26 19:00:24 freebsddemo postfix/smtp[1292]: 8025BC039: to=, orig_to=, relay=www.brandonchecketts.com[66.135.56.251]:25, delay=4.5, delays=0/0.09/4/0.44, dsn=2.0.0, status=sent (250 2.0.0 Ok: queued as A2ACB3838003)
Apr 26 19:00:24 freebsddemo postfix/qmgr[1082]: 8025BC039: removed

Now back on the website http://www.brandonchecketts.com/emailtest.php view the results:
the analysis will show the presence of a DKIM-signature but will mark it as invalid because of the domain name myzone.demo. If you are going to try with a valid domain name it will succeed.

Everything is working fine.
What you have now is a testbed suited to gain experience with MTA and DKIM. This is just a quick guide to get started, you are warmly encouraged to read the relevant documentation and the manuals as well:

man 8 opendkim-genkey
man 8 opendkim-testkey

Check out how anti spam measures are adopted by italian Public Administrations.

Leave a Reply