It's time for part 3 of getting your e-mail server up and running! We have six main tasks with this segment, each of which has its own chunk of subtasks. We'll go through them in roughly this order:
- Install OpenDKIM so that we can use DomainKeys Identified Mail to help recipient domains validate that the e-mail we send actually comes from us
- Install SpamAssassin for spam filtering
- Install ClamAV for virus scanning (though this is somewhat optional, as we'll discuss when we get there)
- Configure SpamAssassin and ClamAV and talk a bit about spam filtering
- Configure our external DNS and talk a bit about how to handle internal DNS as well (as part of this, we'll set up DKIM and SPF records and also talk about reverse-lookups)
- Set up some server-side mail filters with Sieve to toss spam and do some other neat tricks
After completing part 2, our e-mail server has an almost fully configured Postfix and Dovecot stack. However, there is additional functionality that we need to bolt on to Postfix in order to make it behave like a big-boy SMTP server. We need it to be able to filter out spam and viruses, and we need to be able to tag our outgoing e-mails with a cryptographic hash to help prove that they're legit e-mails that we're actually sending.
To add this functionality to Postfix, we're going to be installing a number of milters—mail filter applications. You might have noticed a commented-out line in Postfix's main.cf
config file in part 2 that mentioned milters. Once we have them all installed, we'll uncomment that line to get them working.
The first thing we need to get operational is DKIM: DomainKeys Identified Mail. But before we do that, a quick note on virtual users: several readers have written in asking if the folder structure required for the virtual users we created back in part 2 needs to be manually created. The answer, fortunately, is no. The first time a virtual user receives mail, Dovecot will automatically create everything the virtual user needs under /var/mail/vmail/*
.
Now, let's get to it!
OpenDKIM
OpenDKIM is one of the methods we'll use to help legitimize our mail server. When you send an e-mail with OpenDKIM, your mail server first generates a hash of the message's contents, then encrypts that hash with a private key and stores it in the e-mail's headers. On receipt of the e-mail, the recipient's mail server checks your domain's public DNS records for a specially constructed TXT record containing your private key's public counterpart; the recipient server then uses that public key to decrypt the encrypted message hash. Finally, the recipient server hashes the message and compares the value to the decrypted hash your server attached. If the two hashes are the same, then the recipient can have some degree of assurance that the message was indeed sent by an authorized sender from your domain.
We'll be using the OpenDKIM package to provide DKIM functionality to Postfix. It's a quick install with apt-get
or aptitude
:
aptitude install opendkim opendkim-tools
(I'm going to stop mentioning that most of this needs to be done with root privilege; either preface your commands with sudo
or open a root shell via the method of your choice.)
The OpenDKIM package creates the accounts and Upstart jobs we need, but we're also going to create a directory to hold our OpenDKIM config files and private keys (hat tip to Drew Crawford and his excellent, in-depth tutorial for this bit). First, create the directory and set its ownership to the OpenDKIM user and group:
mkdir /etc/opendkim chown opendkim:opendkim /etc/opendkim
Next, we'll chdir into the directory and create our DKIM private/public keypair there with one of the OpenDKIM utilities:
cd /etc/opendkim opendkim-genkey -r -h sha256 -d mail.yourdomain.com -s mail
The command line parameters we're using with opendkim-genkey
restrict the key we're generating so that it can only be used to sign mail, specify SHA256 as our hashing algorithm, and tell opendkim-genkey
the hostname to use and the output file names to generate.
After you run this command, you'll have a pair of files in your directory: the private key in mail.private
, and the public key in mail.txt
. Note also that the public key file is actually structured as a DNS TXT record—this is super handy since we need to set just such a TXT record on our public DNS server. Keep this file around, and we'll come back to it shortly.
The next step is to rename the private key file from mail.private
to just mail
, and then we'll create a number of lookup tables so that OpenDKIM knows who's allowed to use the private key to sign its messages. Then we'll edit the OpenDKIM configuration file to get all our changes integrated.
First, that bit of renaming:
mv mail.private mail
Now create a file named /etc/opendkim/KeyTable
and make its contents look like the following:
mail.yourdomain.com mail.yourdomain.com:mail:/etc/opendkim/mail
This table will be used to associate mail.yourdomain.com
with the specific private key for that domain. You can also do this directly in the OpenDKIM configuration file, but using a table gives you the flexibility to manage multiple e-mail domains. If that's a future goal, you can just add the additional domains and keys below the first.
Next, create /etc/opendkim/SigningTable
and set its contents thusly:
*@yourdomain.com mail.yourdomain.com
This table will tell OpenDKIM which signature to attach to which messages—in this case, sign all e-mails from all addresses ending in @yourdomain.com
with the signature for mail.yourdomain.com
. Again, the use of a table here lets you easily add additional domains if needed.
The last file to create is /etc/opendkim/TrustedHosts
, which just needs to contain the standard link local IP address:
127.0.0.1
This table will serve a couple of different purposes: it will be used to tell OpenDKIM the list of servers for which it should sign mail rather than verify mail and also which servers it will allow to send signed mail without providing credentials. Once again, using a table here rather than hard-coding values directly into OpenDKIM's config file gives you room to add additional domains if needed.
That's it for our tables and key files. However, before we leave this directory and move on to OpenDKIM's main configuration file, we need to set their owners and groups so that the OpenDKIM user can access them (since they're probably owned by root or by your account right now):
chown -R opendkim:opendkim /etc/opendkim
The last OpenDKIM step is to modify the configuration file and plug in our tables, as well as set a few other options to make OpenDKIM do what we want. That file is at /etc/opendkim.conf
, and it should already have a few uncommented parameters in it. Leave the file's existing contents alone and append the following at the bottom:
## OpenDKIM conf stuff that I'm adding Canonicalization relaxed/relaxed ExternalIgnoreList refile:/etc/opendkim/TrustedHosts InternalHosts refile:/etc/opendkim/TrustedHosts KeyTable refile:/etc/opendkim/KeyTable SigningTable refile:/etc/opendkim/SigningTable LogWhy Yes PidFile /var/run/opendkim/opendkim.pid Socket local:/var/spool/postfix/opendkim/opendkim.sock SyslogSuccess Yes TemporaryDirectory /var/tmp UserID opendkim:opendkim
From the top down, we're setting Canonicalization
to relaxed to deal with the ways that e-mail headers occasionally get changed in transit. The next two entries tell OpenDKIM to use our TrustedHosts
file (containing just the link local IP address) in the fashion described above—saying mail coming from addresses listed in that file should actually be signed and so on. KeyTable
points to our KeyTable file, and SigningTable
points to the SigningTable file. LogWhy
tells OpenDKIM to be more verbose when explaining its signing and verification decisions. Next, we specify a pidfile for the OpenDKIM daemon and then a socket within Postfix's chroot jail in order to receive connections from Postfix. Finally, we tell OpenDKIM to log successful signatures and verifications, set our temp directory, and set the UID/GID under which OpenDKIM will run.
Now, about that socket: there isn't a /var/spool/postfix/opendkim
directory yet, so we're going to create it and then set it to be owned by the OpenDKIM user and root group to match how the rest of the directories under /var/spool/postfix are permissioned:
mkdir /var/spool/postfix/opendkim chown opendkim:root /var/spool/postfix/opendkim
Restart the OpenDKIM daemon to make our config changes live:
service opendkim restart
We face one final issue with OpenDKIM. Currently, the unix socket at /var/spool/postfix/opendkim/opendkim.sock
won't allow public writes—only its owner and group can write to it. But we need Postfix to be able to write to the socket in order to communicate with OpenDKIM, and we don't have a lot of crazy granularity with Unix permission bits. The quickest way to overcome this problem is to add the Postfix user to the OpenDKIM group, like this:
usermod -G opendkim postfix
What are the potential security implications of this? An attacker compromising the Postfix account wouldn't have access to the OpenDKIM private key (since the permissions on that file only allow read and write by its owner, the OpenDKIM user), but anything that bridges account privilege separation barriers is a less-than-desirable thing. Still, this is a small workaround. One other way to handle this situation would be to abandon unix sockets and have OpenDKIM listen on a TCP port instead (and, indeed, that's what Drew Crawford's walkthrough suggests).
reader comments
168