Wednesday, June 29, 2016

Making a Mailserver (Part 4) - Credibility is Critical

This is an instalment in my series on setting up a Linux based mailserver. See these posts:
Your mailserver has no reputation on the Internet. Even if it did, years of good reputation can be wiped away in a few 'open relay' minutes.

It's time to setup SPF and DKIM with bind and exim4.


To ensure to the rest of the Internet that your server right at this moment is one of the good guys, set up everything you can within the DMARC framework.

The DMARC (Domain-based Message Authentication, Reporting & Conformance) concept is A Good Thing. The principles allow a mail server to express its validity. The DMARC methods allow sender validation through one or both of SPF and DKIM. That means, it is still possible for someone to spoof emails from your domain, but when your mailserver sends a message, SPF and DKIM validation is proof that that message at that moment is positively from your approved mail agent.

Some mail receivers will fail the DMARC validation lookup on messages and still deliver the email. However, if your mailserver starts out with a higher spam score (for whatever reason), the DMARC validation on your mailserver may be enough to mark down the spam score and get your email to its intended recipient.

In this example. we will set up:
  • SPF
  • DKIM
These standards try to solve the same problem (sender validity), but are often both checked, so we'll set up both. It's remarkably easy to configure them, particularly if you have unrestricted control of your DNS records.


This is dead simple to setup.

In part 1 we set up the minimum required DNS records, including the mail server (MX) record. Now we head back to bind9 to add a TXT record. Put this in the top level $ORIGIN section; i,e, where the NS records hang out.

TXT     "v=spf1 mx -all"
This record states that the SPF version is 1 and that all MX DNS records are entitled to deliver mail for MX is the record type, but could also include IP or IPv6 addresses. The "-all" says that anything in the list is authorised for the domain.

Visit The SPF Project website for detailed information on syntax.

In earlier times, this was an "SPF" record instead of "TXT", but "SPF" has been deprecated in favour of a "TXT" record.


Review this debian-administration page before carrying out the steps, in order to make sense of the details. DKIM (DomainKeys Identified Mail) is easy to understand if your familiar with the concepts of PKI. If not, understanding what you're about to do next will be a steep but highly valuable learning curve.

Quoting a couple of points from the debian page mentioned above.
When a mail is sent a number of fields are hashed together, and that hash is then signed with the private key.
To validate an incoming message the receiver can see the from-address, perform the DNS-lookup necessary to find the public-key, and then repeat the hashing-process to compute the signature. If it matches then the result will be a "pass".
The intention is that only somebody who has control of the DNS for a domain can send mail from it - because all others will be missing the private key, and unable to sign the message.
We will create a private and public key so that your mailserver can put a signature, using the private key, to each email that can be verified by using the public key. The public key is retrieved with a query to your DNS server. The public key can be used to verify the signature, but cannot be used to forge your signature. That's the beauty of PKI.

In the next set of commands, we create the DKIM keys with openssl.
# sudo mkdir /etc/exim4/dkim
# cd /etc/exim4/dkim
# sudo openssl genrsa -out 1024 -outform PEM
# sudo openssl rsa -in -out -pubout -outform PEM
On my Debian system, I set the file permissions on the dkim directory (and files within) as so: 
drwxr-x---  2 root Debian-exim  4096 Jun  5 21:34 dkim
The Debian-exim group has permission to read the directory and files, while other (non root) users are permitted no access to these files whatsoever. This step may not be required, but it made sense to me in the context of how exim4 wants certificate file permissions to be set (see part 3).

Now tell exim4 that you want to sign messages with DKIM and where the key files are:

DKIM_CANON = relaxed
DKIM_SELECTOR = 20160629
DKIM_DOMAIN = ${lc:${domain:$h_from:}}
DKIM_PRIVATE_KEY=${if exists{/etc/exim4/dkim/${dkim_domain}.pem} {/etc/exim4/dkim/${dkim_domain}.pem}
  • The 20160629 is an arbitrary value, which for me indicates the date YYYYMMDD. There's nothing intrinsically important about the value here, but we reference it shortly when we create the DNS record.
  • I'm using a dynamic DKIM_DOMAIN and DKIM_PRIVATE_KEY configuration because I handle email for multiple domains, This configuration avoids repetitious configuration per domain. You don't need to think about it as long as the key names match the domain you are handling email for. Exim4 will (with a small computational overhead) dynamically work out the correct key to sign each email.
Now regenerate the configuration and restart exim4 :
# update-exim4.conf 
# service exim4 restart
The update-exim4.conf is essential. If email is going out, but no dkim signing is happening, then this is quite likely because the new configuration hasn't been picked up. Only restarting exim4 is not enough.

Put the public key file into a DNS TXT record, located within the correct $origin section.

_domainkey      IN TXT  "t=y;o=~;" 20160629._domainkey     IN TXT "k=rsa; p=XXX"
  • I have changed the email address to use to stop bots scraping my email address from this blog post. You must use a real address.
  • p=XXX is the literal public key contained in the file, which you generated earlier. There's no problem from a security standpoint with me repeating the string in this post (it's publicly available by definition), but it is lengthy and it is useless to anyone other than me.
Of course, if you are handling email for multiple domains, you'll want to do this for each domain's zone file.

Surprisingly, you will get a daily summary email from other domains, primarily from hotmail, google and yahoo. I believe (but I'm not not absolutely sure) that this is standard when in 'testing mode'. The t=y element of the record means (according to RFC6376):
t= Flags, represented as a colon-separated list of names plain-
   text; OPTIONAL, default is no flags set).  Unrecognized flags MUST
   be ignored.  The defined flags are as follows:

  y  This domain is testing DKIM.  Verifiers MUST NOT treat messages
     from Signers in testing mode differently from unsigned email,
     even should the signature fail to verify.  Verifiers MAY wish
     to track testing mode results to assist the Signer.
That is to say, that "y" means "testing mode" and messages don't get dropped. During initial setup or server migration this is critical. Review the emails for SPF and DKIM 'fail' results as this will tell you if something is wrong. The results may tell you what other hosts are impersonating your mailserver!

My experience is that some mailservers are badly configured (or designed) and don't handle well messages that are relayed through a mailing list. There are different ways that this can go wrong, but I have personally seen SPF lookups fail because the sending list server is not (obviously enough) in my list of MX servers. This appears to be faulty logic on the recipient's behalf, because the receiver has looked up the SPF on my domain instead of the mailing list domain. [If you want to correct or fill this point in, please use the comments section, I really want to learn some more about this.]

Once you set up the DKIM record, you'll start to receive summary messages from a few places. The xml attachment will look similar to the following and gives you an indication on who's been sending email on your behalf as well as what passed and failed.
In the above, you can see that for the sender 64.x.x.x DKIM failed while SPF passed. The message is probably legitimate, but DKIM has possibly been set up incorrectly [Editor's note: it was]. SPF passed so it appears that the final result was that 1 message was successful received.


The debian-administration website was at one point wrong. The page is great but used exim4 variable syntax that just did not work and was plainly wrong in the context of the wider example as they dropped "-private" from the DKIM_PRIVATE_KEY.

Further References 
I highly recommend this site to check your setup: 
This site does a basic check on whether your DKIM DNS is okay:

No comments:

Post a Comment