DomainKeys Identified Mail (DKIM) and Postfix Header Checks

There are a lot of instructions on the web for installing and configuring DKIM but they vary considerably and many have errors. There also can be gotchas and this article details one of them. Ubuntu 14.04 with Postfix 2.11 are used.

For Ubuntu start by installing DKIM

apt-get install opendkim opendkim-tools

Postfix uses Milter (mail filter) as one method for integration with other applications. OpenDKIM and Postfix will need to communicate information between them. Milter supports two methods for communication: Unix sockets and TCP ports.  Most instructions use TCP.  The port number selected should not conflict with any in the list in the above link nor should it conflict with any ports in use on the server. To use a TCP port in /etc/opendkim.conf add

Socket inet:8891@localhost

In /etc/default/opendkim

SOCKET="inet:8891@localhost"

For Postfix, edit /etc/postfix/main.cf

smtpd_milters = inet:localhost:8891
non_smtpd_milters = inet:localhost:8891

If smtpd_milters or non_smtpd_milters are already being used then combine the lines with a comma and a space separating the values.

The next step is to generate the keys.  Here we will be assuming multiple domains are on the server. There are a lot of variations on the flags recommended and some are wrong. While details can be found in the man page

man opendkim-genkey

reading through every option takes some time. The common flags that appear are -t, -r, -s, -d and -D so we will focus on them. The flag -t will add a tag that indicates to those verifying the email that DKIM is in testing mode. This should certainly not be used for production. The flag -r restricts the use of the key for e-mail signing only. Since it is not going to be used for anything else this does not seem necessary. The -D flag outputs the generated files to the directory that follows the flag. This may be useful but is not as clear as changing to the directory so we start by creating directories and then generate the keys. If you get an error generating a key then make sure you are executing the command with sudo.

mkdir -p /etc/opendkim/keys/example.com
cd /etc/opendkim/keys/example.com
opendkim-genkey -s dkim -d example.com

The -d flag is followed by the domain for the key (example.com should be replaced with your domain).  These three commands are repeated for each domain.  This should automatically include subdomains unless the -S flag is used. The -s flag is followed by the selector. The selector specifies which key for that domain should be used and appears in several places in the configuration. Common values for selectors are "default" (which is the default if it is not specified), "mail" and "dkim." While it does not make a difference as long as it is consistent here we are going to use "dkim" because it will be clearer where the selector appears.  Once this is done then change the owner of these files.

chown -R opendkim:opendkim /etc/opendkim/

There are two files that are generated for each domain. These two files are dkim.key and dkim.txt (where the selector appears as part of the file name).  The first file contains the key while the second one contains the information that needs to be placed in a text record in DNS.  Generally the name should be the first thing in the txt file (dkim._domainkey); note the appearance of the selector again.  The value should be the information in parenthesis.  Check for documention for your webhost on whether the quotes are needed and other details.  The value includes the public key.

Now we finish editing /etc/opendkim.conf.  We need to add four lines that refer to three files and some other settings to the line we already added.

Syslog                  Yes
UMask                   002
OversignHeaders         From

AutoRestart             Yes
AutoRestartRate         10/1h
Canonicalization        relaxed/simple
ExternalIgnoreList      refile:/etc/opendkim/TrustedHosts
InternalHosts           refile:/etc/opendkim/TrustedHosts
KeyTable                refile:/etc/opendkim/KeyTable
SigningTable            refile:/etc/opendkim/SigningTable
LogWhy                  Yes
Mode                    sv
PidFile                 /var/run/opendkim/opendkim.pid
SignatureAlgorithm      rsa-sha256
Socket                  inet:8891@localhost
SyslogSuccess           Yes
UserID                  opendkim:opendkim

Lines with refile refer to regular expression files. These files consist of each line containing a pattern and a value separated by whitespace. If AutoRestart on failures is used then a loop can be created that can cause problems. AutoRestartRate of 10/1h limits the restarts to 10 in one hour. The default for SignatureAlgorithm is rsa-sha256 with a fallback of rsa-sha1. Specifying rsa-sha256 prevents the fallback. LogWhy and SyslogSuccess are for debugging and should be removed later. For more information on these settings use manpages.

man opendkim.conf

Now create /etc/opendkim/KeyTable.

dkim._domainkey.example.com example.com:dkim:/etc/opendkim/keys/example.com/dkim.private

where example.com should be replaced by your domain and the line repeated for each domain. Then create /etc/opendkim/SigningTable.

*@example.com dkim._domainkey.example.com

where example should be replaced by your domain and the line repeated for each domain. Then create the third file /etc/opendkim/TrustedHosts.

127.0.0.1
localhost
*.example.com
<ip address>

where each domain and IP address is listed.

Edit /etc/postfix/main.cf and add to the lines added earlier so it looks like the following.

# OpenDKIM
milter_default_action = accept
milter_protocol = 6
smtpd_milters = inet:localhost:8891
non_smtpd_milters = inet:localhost:8891

Some instructions use a protocol of 2 and others use 6. According to the Milter readme for Postfix 2.6 or greater milter_protocol should probably be 6 and for Postfix 2.3 to 2.5 use a milter_protocol of 2. To find the Postfix version

postconf -d | grep mail_version

Once the configuration is completed then restart the two services.

service opendkim start
service postfix restart

The keys can be tested using

opendkim-testkey -d example.com -s dkim -v -v -v

which should have an output similar to

opendkim-testkey: using default configfile /etc/opendkim.conf
opendkim-testkey: checking key 'dkim._domainkey.example.com
opendkim-testkey: key OK

If you get a message that the key is not secure then this probably can be fixed by checking file and directory permissions.

Send an email to another account and check the headers for the DKIM signature. This is where things went awry. Sometimes the emails are signed and sometimes not. It almost seemed random. Also, an error consistently showed up.

Authentication-Results:mail.example.com; dkim=permerror (bad message/signature format)

Several days of changing settings, reading manpages and searching the internet went nowhere. The log files seemed to be missing anything indicating success but also nothing that jumped out. Finally the somewhat obscure message was found amongst all the messages:

mail opendkim[24436]: 733502C67C: can't determine message sender; accepting

Searching on this message I came across Postfix opendkim and missing From header. Another person that had sunk several days into figuring out this problem. Removing unnecessary headers can avoid exposing information and protect privacy but breaks DKIM. Looking in /etc/postfix/main.cf

# Getting rid of unwanted headers. See: https://posluns.com/guides/header-removal/
header_checks = regexp:/etc/postfix/header_checks

Comment out the header_checks or look in /etc/postfix/header_checks for a line like

/^Received:/                 IGNORE

and remove it. It is also possible to use a REPLACE instead of IGNORE instead of removing the line but that will not be covered here.

Restart Postfix and try to send another email. Now the mail log shows

mail opendkim[24436]: CE46C2C67C: DKIM-Signature field added (s=dkim, d=example.com)

The signature appears in the email and we finally get

Authentication-Results: mail.example.com (amavisd-new);
    dkim=pass (1024-bit key) header.d=example.com

It seems that the issue with header_checks would be fairly common and many people as a result have either spent a great deal of time or given up installing DKIM.

Now that our email looks okay we can perform an additional check of both DKIM and Sender Policy Framework (SPF) by sending an email to check-auth@verifier.port25.com. A reply should be received back with the results of the test.

Categories