In a nutshell, DomainKeys Identified Mail (DKIM) provides means to authenticate emails from a sender. Therefore, it utilizes DNS to distribute public keys and policies on how to treat emails that aren't properly authenticated.
Source: Ale2006-from-en, Wikipedia |
Naturally, I looked into the documentation of that topic to find many tutorials but even more questions. It turned out that most of the tutorials had either minor mistakes or lacked some documentation which made me miss an important point.
Therefore, I decided to document the steps needed for an Ubuntu 20.04 server in this Blog.
Assumption: Ubuntu 20.04, postfix correctly setup, access to DNS configuration. I create one default selector for all email addresses.
I will use the placeholder <DOMAIN> for a full qualified domain such as vi4io.org.
You have to decide about a selector to use which basically provides means to use multiple keys, I use <SELECTOR> as placeholder, in my case, it is "mail".
<EMAIL> is an email where you like to receive errors.
Installation Steps
- Install required software
- $ apt-get install opendkim opendkim-tools
- Create public/private key pairs
- $ mkdir /etc/dkimkeys/<DOMAIN>
- $ cd /etc/dkimkeys/<DOMAIN>
- $ opendkim-genkey -t -s <SELECTOR> -d <DOMAIN>
- Example: $ opendkim-genkey -t -s mail -d vi4io.org
- Now secure the files:
- $ chown -R opendkim:opendkim /etc/dkimkeys/
- $ chmod -.R 700 /etc/dkimkeys/
- Configure opendkim, edit /etc/opendkim.conf
- Edit the lines as follows:
- KeyTable /etc/dkimkeys/key.table
- SigningTable refile:/etc/dkimkeys/signing.table
- Selector <SELECTOR>
- Socket inet:8892@localhost
- Create /etc/dkimkeys/key.table, this file is basically a list of references to the key files, I formated them as follows:
- <SELECTOR>._domainkey.<DOMAIN> <DOMAIN>:<SELECTOR>:/etc/dkimkeys/<DOMAIN>/<SELECTOR>.private
- Example:
- mail._domainkey.vi4io.org vi4io.org:mail:/etc/dkimkeys/vi4io.org/mail.private
- Create signing.table which defines the patterns for which email to use which key, it is a list:
- *@<DOMAIN> <SELECTOR>._domainkey.<DOMAIN>
- Example:
- *@vi4io.org mail._domainkey.vi4io.org
- Restart the opendkim service
- $ /etc/init.d/opendkim restart
- Setup the public key in DNS, modify the DNS, add a TXT prefix as follows:
- Name: <SELECTOR>._domainkey
- Example: mail._domainkey
- Value: the content of the file /etc/dkimkeys/<DOMAIN>/<SELECTOR>.txt, make sure you remove quotations.
- Example: v=DKIM1; h=sha256; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxfxhoZwKV1gahzMYv2tvEVBtAFo8LgW/8GolHibkiCGqD7urRnUPUPj/RF72mkwz/RdX+o8XTAJKgGvw5eo9g6z3DPql1xKcZEbpcUSnGbpIGQODmnNEqixaScrlEVmgtjHJsm9++Upp4RRRo7309Zlvzh4bmIfVzubwNG3umYzuf6ct/RT1xyRLWXLh5LtOa/xBNfRhCoGjxlgufu9CUqQe9af8J3MY6t2PR63XUOxwwGNBrNAlGTKw8KDc9OKn/eYCOBM4XrWjwiAR3dIVQJPT3FfSKqZ2BrBmRVg0jUiwE0j7AB+wLN/Ixsbp/ByyprcnVDFyNiXzOhr17mVOMQIDAQAB
- Test that the value is set using a DNS query tool such as dig:
- $ dig mail._domainkey.vi4io.org TXT
- Note that DNS updates may take a while depending on your provider and that replies may be cached.
- You should see in the ANSWER SECTION the output, in my case:
- ;; ANSWER SECTION:
- mail._domainkey.hpc-certification.org. 150 IN TXT "v=DKIM1; h=sha256; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtOUU+CVmGg2QRHwN9BEjpzfoF5cXS6gn9cumt2o/jtGRYLmmB0wul/a/AYQNXOb0bJygGOhB66G+KtESuVpjuPwQI9c6J+2nAi2peVyamc7TYv3Snf+aB+LCMzgv9l7M6Ur+bK4hg3tDuze04BdFzY3WWgZCswpSB8br5++RG3vMWGLr9NtKIgm" "WtVGxiISkcsEiuYoISubfjCkN+MYQzdiT4oDdXGItv2c/yPmvfEQzeLn45YLUmkaRJOjTT+0rwV9Ct9ElpYEWuaYU51nH8yRkvLFTv9EdNTX1u8IRuHkkZpL8Y0ruyGFWXhxkmk8CYKB//tA8bSto5NSo8R8SYQIDAQAB
- Setup a first DMARC policy, modify the DNS, add a TXT prefix as follows:
- Name: _dmarc
- Value: v=DMARC1; p=none; rua=mailto:<EMAIL>; ruf=mailto:<EMAIL>"
- Example: "v=DMARC1; p=none; rua=mailto:postmaster@vi4io.org; ruf=mailto:postmaster@vi4io.org"
- This policy will allow debugging, instructing that emails shall be send by mail servers providing status information about accepted and failes messages. Once everything works the policy (none here) can be changed to "reject" to tell every email server to reject emails that appear to stem from your domain but are not signed. Note that attempts to send non-signed emails may generate an email...
- Test again using DNS query tool:
- $ dig _dmarc.vi4io.org TXT
- Setup postfix to utilize the installed opendkim, edit: /etc/postfix/main.cf
- Add:
- milter_default_action = accept
- milter_protocol = 2
- smtpd_milters = inet:localhost:8892
- non_smtpd_milters = inet:localhost:8892
- Note that you must use TCP here, the usage of sockets doesn't work as ubuntu creates a jail for postfix.
- Restart postfix:
- $ /etc/init.d/postfix restart
Congratulations you should have completed the basic setup!
Testing
- Check that opendkim finds the publicly announced keys:
- $ opendkim-testkey -d <DOMAIN> -s <SELECTOR> -v -v -v
- Example: $ opendkim-testkey -d vi4io.org -s "mail" -v -v -v
- This should produce the output:
- opendkim-testkey: using default configfile /etc/opendkim.conf
- opendkim-testkey: checking key '<SELECTOR>._domainkey.<DOMAIN>'
- opendkim-testkey: key OK
- You may receive also the output:
- opendkim-testkey: key not secure
- There are various issues why that may happen, I don't know why it does for me.
- Check the correct availability of your keys, using:
- https://www.dmarcanalyzer.com/dkim/dkim-check/
- https://dmarcian.com/dkim-inspector/
- I actually used both as they provide different error messages in case something isn't correctly set up.
- Send yourself an email via your server, check the source code of the message. In Gmail you receive a nice additional report, here the report from my testemail:
- Original Message
- Message ID <20200720094515.AC62E13BE59@hpc-certification.org>
- Created at: Mon, Jul 20, 2020 at 10:45 AM (Delivered after 1 second)
- From: info@vi4io.org
- To: XXXX@XXXX
- Subject: Test
- SPF: PASS with IP 51.145.29.131 Learn more
- DKIM: 'PASS' with domain vi4io.org Learn more
- DMARC: 'PASS' Learn more
- The important parts of the original header are:
- Authentication-Results: mx.google.com;
- dkim=pass header.i=@vi4io.org header.s=mail header.b=fraCy00G;
- spf=pass (google.com: domain of info@vi4io.org designates 51.145.29.131 as permitted sender) smtp.mailfrom=info@vi4io.org;
- dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=vi4io.org
- DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=vi4io.org; s=mail; t=1595238315; bh=fdkeB/A0FkbVP2k4J4pNPoeWH6vqBm9+b0C3OY87Cw8=; h=To:Subject:From:To:Reply-To:Date:From; b=fraCy00G11f1c8Pwa26qKlDRAKCmcieXPVEEZr7nL6qWBFsxXs0DetzbQa8KfnNrf
- To verify that everything works or find mistakes, you can also use a service such as https://www.mail-tester.com/
- It is easy to use, you send an email from your server to a unique mailbox (shown when you visit the page), then you get a detailed report about the configuration.
- Note: You have 3 tries a day for the verification before you must pay, so I recommend to do this as last step.
- Once everything works, you may want to remove the "ruf" property from the DNS _dmarc TXT field (Step 9) to reduce the number of messages you receive about failed delivery.
Once everything works for you may want to change the policy in the Installation Step 9 to "reject". This minimizes the risk that email addresses from your server are spoofed and your domain is classified as source of spam...
I hope this little guide helps you to setup Postfix with DKIM. I believe that securing email is important. If you have feedback or comments, feel free to submit them.