The importance of a certain anti-spam-method is not always easy to measure: with DKIM, the DomainKeys Identified Mail, it gets harder again.
What DKIM is about should best be explained by different sites:
That being said, DKIM is simplified a solution to ensure that a given already signed message is verifiable being sent from the server mentioned in the message. The method relies on asymmetrics cryptography with the public key being deployed as a DNS record.
A pair of private and public keys is generated with a given “selector” and a domain name. The public key is stored in a TXT record in the form of “$selector._domainkey.$domain”, the private key should not be exposed to the public ;-). With said private key, messages are signed. The signature may then be later verified using the public key from DNS.
DKIM is not a solution to identify a certain given message as spam, but to ensure the verifiable upstream of a message. This allows to identify Phishing mails using the orginal sender domain (like @paypal.com, @ebay.com etc.), as they cannot use the correct DKIM keys.
On Debian Wheezy with Postfix as a MTA, OpenDKIM as a milter is the preferred way. There are other solutions like using amavisd-new or dkim-filter as well, but those did pose other problems, especially when using multiple domains on one server.
Amavis requires a different key for each domain, so the deployment for new domains is complicated.
With OpenDKIM, multiple domains on a single server may be signed with only one selector.
This blogpost does rely on the following external sources. Please visit the pages for additional information, if required:
The domain used for signing the mails is the same as the hostname of Postfix (“$myhostname”). The selector contains the (short) hostname and the current year (to allow the yearly change of the signing key as well as a verification of old signatures after the change), resulting in my case in:
The required steps to fully enable DKIM signatures when sending messages are the following:
- install the packages:
aptitude install opendkim opendkim-tools
- create the folders for storing the configuration files and some statistics with the appropriate permissions:
mkdir /etc/opendkim /var/log/opendkim chmod 0700 /etc/opendkim /var/log/opendkim chown opendkim:opendkim /etc/opendkim /var/log/opendkim
- In /etc/default/opendkim, change the listener socket:
- Change or add the configuration directives in /etc/opendkim.conf:
Syslog yes SyslogSuccess yes LogWhy yes UMask 002 KeyFile /etc/opendkim/dkim.key Selector OURSELECTOR OversignHeaders From AutoRestart yes Background yes Canonicalization relaxed/relaxed DNSTimeout 5 Mode sv SignatureAlgorithm rsa-sha256 SubDomains no Statistics /var/log/opendkim/dkim-stats KeyTable /etc/opendkim/dkim-keytable SigningTable refile:/etc/opendkim/dkim-signingtable ExternalIgnoreList refile:/etc/opendkim/TrustedHosts InternalHosts refile:/etc/opendkim/TrustedHosts
The value for the “Selector”-Parameter should be changed to your needs, as described above! Note the “refile:”-specification of the filename. Without this, OpenDKIM would treat the given “datastet” as a single Key-Value-store. With “refile:”, the key is treated as a regular expression, allowing the use of wildcards.
- The content of /etc/opendkim/TrustedHosts is pretty straight forward: list all hosts, which mail gets signed in any case. Only localhost (or at least not external network) should be specified!
Mail sent from a SASL authenticated connection will be signed anyway.
- next up, we create the actual KeyTable. This file contains each selector/domain we want to use with the actual location of the corresponding private key:
Again, use the selector and the domainname previously specified!
- OpenDKIM uses the SigningTable in /etc/opendkim/dkim-signingtable to find the selector for a given sender address. As stated before, with “refile:” in the main configuration file, we are now able to use wildcards. OpenDKIM now signs every outgoing message with our single selector:
- Our configuration for OpenDKIM is now almost complete. The only missing part is the actual public/private key. The key is generated using OpenSSL and has a length of 1024 bit (I tried longer keys of 2048 bit, which could not be verified afterwards):
openssl genrsa -out /etc/opendkim/dkim.key 1024 openssl rsa -in /etc/opendkim/dkim.key -out /etc/opendkim/rsa.public -pubout -outform PEM
OpenSSL does not embed any information as in X.509-certificates, so the key is independent of any certain host. Also, it does not need to be signed by a CA, as it isn’t a certificate at all 🙂
- To ensure proper permissions, we set read-only permissions and change the owner:
chown opendkim:opendkim /etc/opendkim/dkim.* chmod 0600 /etc/opendkim/dkim.*
- The public key, stored in /etc/opendkim/rsa.public, has now be published as a TXT record.
The format of this record is the following:
The placeholder “$PUBLICKEY” has to be replaced by the contents of the public key, without the first and last line and without any line breaks. How to actually create the DNS record is beyond this tutorial 🙂 To verify the entry, I’d like to use “dig”:
# dig +short -t TXT hermes2014._domainkey.a1a-server.de "v=DKIM1\; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC6+19du037xwYRo0vVckAQcpi9A3sGpcfxZEo5zNarCmcsOIZyf0Chek7BYOoLGbOqwvWy26o3ByJwriHK2x1NMu4tS/DUO5PmO1zy/y432L3VoBfmAjT20NxFEvRCxNuQYYS1SthpFnOdRLmGbdqNXY37MI/2+Oa2hVn40Bi1NwIDAQAB"
- As a final step, Postfix has to connect to OpenDKIM when new messages should be delivered.
The main configuration file, /etc/postfix/main.cf, gets some new entries:
# DKIM milter_default_action = accept milter_protocol = 2 smtpd_milters = inet:localhost:8891 non_smtpd_milters = inet:localhost:8891
Make sure to specify the same inet-socket as in /etc/default/opendkim!
- after a restart of the involved daemons (namely OpenDKIM and Postfix), new messages by OpenDKIM will appear in the syslog:
Jan 1 02:31:10 hermes.a1a-server.de opendkim: 9F95E4037C: DKIM-Signature header added (s=hermes2014, d=a1a-server.de)
OpenDKIM signs every message submitted using auth credentials and additionally all messages received from trusted hosts.
- OpenDKIM also verifies incoming messages with DKIM signatures:
Jan 1 02:31:44 hermes.a1a-server.de opendkim: 0B2A94037B: outmail017.prn2.facebook.com [184.108.40.206] not internal Jan 1 02:31:44 hermes.a1a-server.de opendkim: 0B2A94037B: not authenticated Jan 1 02:31:44 hermes.a1a-server.de opendkim: 0B2A94037B: DKIM verification successful
SpamAssassin uses the signatures as well. As DKIM itself does not ensure proper spam/antispam, SA only uses larger scores if the verification of the signature fails.
- For Amavis, just insert one additional configuration directive, e.g. in /etc/amavis/conf.d/50-user:
$enable_dkim_verification = 1;
There is a single drawback of the described method: GMail and probably others will display the domain of the DKIM signature (here: “a1a-server.de“) to the recipients:
If this poses an issue, each domain should receive an individual DKIM key – but makes this page obsolete 🙂
At the end, some additional remarks:
- Individual signing keys should be preferred anyway, if possible!
- Multiple signatures in a single mail are not a problem. Open-DKIM logs those as well.
- OpenDKIM supports reading data from MySQL, if the binary is compiled against the corresponding libraries. With this, new signing domains may be added dynamically and thus reducing the overhead when new domains are added. Unfortunately, this was not used for the Debian packages.
- DKIM should be combined with Author Domain Signing Practices (ADSP) and Authorized Third-Party Signers (ATPS), which will be part of another article.