Domainkeys
From Qmailtoaster
Contents |
Introduction
What are DomainKeys? See Yahoo!'s DomainKeys page for an explaination and further resources.
This is a step by step guide for setting up DomainKeys on QmailToaster. It includes modifications needed to DNS.
This guide assumes you have installed QmailToaster and have created at least one domain. The example name for your domain used throughout this guide is yourdomain.com. The example DomainKey Selector name (the identifier of the key pair) is private. While this can be confusing, it is done because private is the default Selector name used by qmail-dk. To help make things clearer, these names are italicized in this guide.
There are three main steps to setting up DomainKeys on your toaster:
- DomainKey Generation
- DNS Configuration
- QmailToaster Configuration
DomainKey Generation
The qmail-dk default filename for the private key is:
/var/qmail/control/domainkeys/yourdomain.com/private
Create the directory for your domain's private key:
# cd /var/qmail/control/domainkeys # mkdir yourdomain.com
Create your domain's key pair (a private key and a corresponding public key) with the dknewkey command:
# cd yourdomain.com # dknewkey private > public.txt
When you execute the dknewkey command this way, it creates the public key you will need for your domain's dns server as the file named public.txt, in the format of a bind dns record. It also creates the private key in a file named private.
You want to be sure that the private key is kept private, so to change its ownership and permissions accordingly:
# chmod 440 private # cd .. # chown -R root:vchkpw yourdomain.com
At this point, you have created your domain's key pair. You still need to configure qmail toaster to use domain keys, and make your public key, well, public, by including it in your authoritative DNS server. Let's continue with the DNS server modifications.
DNS Configuration
Caching Nameserver
You should have a caching nameserver installed on your toaster. This is so that your toaster doesn't create unnecessary network traffic (and delays) every time it needs to look up DNS information (DomainKey, SPF, and blacklists) for each email that is received. Once information is retrieved for a domain, it is cached locally for some period of time, saving network and DNS resources and improving the toaster's performance.
You can use djbdns or bind. You cannot use both.
djbdns
To install djbdns caching server on your mail server, follow the write up here: http://www.qmailtoaster.com/qt-doc/QT-README.djbdns
bind
If you prefer to use the bind dns server, you can simply:
# yum -y install bind caching-nameserver
If caching-nameserver isn't found, substitute the appropriate package for your distro.
Authoritative Nameserver
The Authoritative Nameserver is the DNS responsible for your domain (not a caching nameserver). In order to configure the Authoritative DNS for DomainKeys, you will need to add two "TXT" type records to the Authoritative Nameserver for your domain.
Policy Record
The first TXT record is a Policy record. It tells the receiving mail servers if you are using DomainKeys, in testing mode or not, and if all email from your domain will contain DomainKey signatures.
An example entry for djbdns would look like:
_domainkey.yourdomain.com:t=y; o=-; r=postmaster@yourdomain.com
while a bind entry would look like:
_domainkey.yourdomain.com IN TXT "t=y; o=-; r=postmaster@yourdomain.com"
{edit: I believe that you want to include an additional period after the domain name for a Bind entry - so a corrected way would be:
_domainkey.yourdomain.com. IN TXT "t=y; o=-;"
hope that helps - dave /edit}
The "_domainkey.yourdomain.com" part declares that this is the DomainKey policy for the domain, and the options are in the TXT part.
The "o=-;" option tells the receiving mail server that this domain signs ALL email. This is the only option you really need. The r=postmaster@yourdomain.com is outdated, according to Yahoo!'s site.
You will also want to use
"t=y;"
This tells the the receiving mail server that you are in test mode, and not to reject unverified email from this domain. Once you have successfully tested your DomainKey configuration and are sure that it's working properly, you can drop "t=y;". Do not change it to "t=n;". (I wonder why that is -ES) Once you are done testing, simply delete it, and the only entry you should have is "o=-".
Selector Record
The second TXT record you need is a Selector record, containing the public key that was generated when you ran the dknewkey command. It should be in /var/qmail/control/domainkeys/yourdomain/public.txt if you followed these directions. The public.txt file contains exactly what you need for your bind record. Here is an example of an entry for djbdns:
private._domainkey.yourdomain.com:k=rsa; p=MEwwDQYJKoZIhvcNAQEBBQ . . .
The first part, "private._domainkey.yourdomain.com", enables the receiving mail server find the key. Remember that when we created the DomainKey pair, we named it private (# dknewkey private > public.txt). This Selector record contains the public key part of the DomainKey pair named private for yourdomain.com. The TXT string tells the mail server the kind of encryption and the key value. Note, the names in this example can be confusing. The key value that goes here is what's contained in the public.txt file, not the file named private.
Modifying DNS
If you make a mistake and need to change a value in one of your DNS TXT records, you should be aware that it might take a while for records to expire from DNS servers that already have cached the old record (they will have cached it when they first accessed it). The time it will take a DNS record to expire from a cache is the TTL value (TimeToLive, in seconds) for your TXT record minus the time elapsed since the record was cached. If you know the name or IP address of the server where the errant record is cached (doubtful), you can dig it to see how long it will be before the record expires. Otherwise, you will need to wait, probably several hours, possibly a couple of days before the old record expires and the new one is obtained. This is the normal behavior of DNS. If it bothers you, you should change the TTL value for your TXT records to whatever you think is appropriate (which is beyond our scope here).
bind
If you are running a bind Authoritative Nameserver, use the exact contents of the public.txt file from the dknewkey command as the Selector record. You can manually enter the policy record. Together, they should look like this:
_domainkey.yourdomain.com IN TXT "t=y; o=-" private._domainkey.yourdomain.com IN TXT "k=rsa; p=XXXXXXXXXXXXXXXXXXXXXXXX"
djbdns
If you are running a djbdns Authoritative Nameserver, you've hopefully noticed that the records you need to add have already been shown above. Here they are again, together for your convenience:
_domainkey.yourdomain.com:t=y; o=-; r=postmaster@yourdomain.com private._domainkey.yourdomain.com:k=rsa; p=MEwwDQYJKoZIhvcNAQEBBQ . . .
DNS Management Services
If you use a DNS Management Service, the way to create DomainKey DNS TXT records varies. Here are some examples:
GoDaddy
using godaddy wizard:
TXT name is: _domainkey.yourdomain.com
TXT value is: t=y; o=-
TXT name is: private._domainkey.yourdomain.com
TXT value is: k=rsa; p=XXXxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.........
FreeDNS.Afraid.org
You add them to your domain as two TXT records. The "_domainkey" and "private._domainkey" go in the subdomain field, and the "t=y;o=-" and "k=rsa; p=XXXXXXXXXXXXXXXXXXXXXXXX" are entered to their respective subdomains in the "address" field.
DynDNS.org
You add them to your domain as two TXT records. The "_domainkey" and "private._domainkey" go in the Hostname field (without .yourdomain.com, which is added automatically), and the quoted text goes in the TXT Data field. DynDNS will add a backslash before each semicolon in the text string. That's ok.
Your DNS configuration is now complete. The last basic step is to configure your toaster.
QmailToaster Configuration
QmailToaster uses the /etc/tcprules.d/tcp.smtp file for DomainKeys configuration. You might need to change something there, so check it out to make sure everything is as you want it.
man qmail-dk excerpt: qmail-dk has been patched with qmail-dk-0.54-auth.patch, which sets up a bit of automatic behavior. If [the variable] RELAYCLIENT is found in the environment, qmail-dk imports the DKSIGN environment variable and tries to sign the mail. If RELAYCLIENT is not found in the environment, DKVERIFY is imported, and it attempts to verify the mail.
Outgoing
DKSIGN
In order for QmailToaster to generate and insert a DomainKey signature in your outgoing email, there needs to be a DKSIGN variable defined that contains the location of the private key part of the DomainKey pair. It should look like this:
DKSIGN="/var/qmail/control/domainkeys/%/private"
It needs to be included on each line in tcp.smtp for which you want corresponding outgoing mail signed, typically all (both) of them. You do not need to include DKSIGN when the RELAYCLIENT variable is used if your private key is in the default location (see man excerpt below).
The "%" is replaced by the domain name in the From: header.
To turn off signing for given tcp.smtp line, simply point DKSIGN to a file that does not exist, but be sure to keep a % somewhere in DKSIGN's value.
man qmail-dk excerpt: If, after substituting the %, that file does not exist, the message will not be signed. If there is no % [in the DKSIGN variable] and the file does not exist, the message will be rejected with error 32.
The Selector (private in our examples) is taken from the basename of the file named by the DKSIGN variable.
If neither DKSIGN nor DKVERIFY is set, then DKSIGN will be set as above (the default) and if such a file exists then it will be used to sign messages from the domain.
Incoming
In order for the toaster to check the authenticity of a DomainKey signature on incoming mail, there are two environment variables, DKQUEUE and DKVERIFY, that the qmail-dk program uses. They should exist on every line in tcp.smtp which processes incoming (external) mail, typically the second or last line (not the first line).
DKQUEUE
The DKQUEUE variable points to the original qmail-queue program for passing the message on down the line when verification completes:
DKQUEUE="/var/qmail/bin/qmail-queue.orig"
This is probably not necessary, but is provided for clarity.
man qmail-dk excerpt: qmail-dk will ordinarily spawn qmail-queue, but if DKQUEUE is set in the environment, the program that it points to will be executed instead. If DKQUEUE is not set, and qmail-dk has been invoked as qmail-queue then qmail-queue.orig is spawned instead.
DKVERIFY
DKVERIFY allows you to specify the desired action to be taken by qmail-dk on incoming messages.
qmail-dk determines a unique status for each incoming message it processes. The following table shows the possible results:
code | status name | message tag | status description |
---|---|---|---|
A,a | DK_STAT_OK | good | signature is valid |
B,b | DK_STAT_BADSIG | bad | signature failed to verify against public key |
C,c | DK_STAT_NOSIG | no signature | no signature available in message |
D,d | DK_STAT_NOKEY | no key | no public key available (permanent failure) |
E,e | DK_STAT_BADKEY | bad key | unusable public key |
F,f | DK_STAT_CANTVRFY | no key | cannot get public domain key to verify signature (temporary failure) |
G,g | DK_STAT_SYNTAX | bad format | message is not valid syntax, signature could not be checked |
H,h | DK_STAT_NORESOURCE | no resources | could not get critical resource (temporary failure) |
I,i | DK_STAT_ARGS | bad format | arguments are not usable |
J,j | DK_STAT_REVOKED | revoked | key has been revoked |
K,k | DK_STAT_INTERNAL | bad format | cannot call this routine in this context - internal error |
For each message processed, if the code for the message's status is not contained in DKVERIFY, then qmail-dk passes the message on for delivery with no action. If the code for a message's status is contained in DKVERIFY in upper case, the message is permanently rejected (message should not be resent). If the code for a message's status is contained in DKVERIFY in lower case, the message is temporarily rejected (message should be resent later).
The default QmailToaster definition of DKVERIFY looks like this:
DKVERIFY="DEGIJKfh"
To make the verification more stringent by permanently rejecting incoming mail that has a DomainKey signature but fails to verify against the published public key for the sender's domain, add "B" to the list:
DKVERIFY="BDEGIJKfh"
Obviously, you should not include the letters "A" or "a" in DKVERIFY, as that would reject messages with valid signatures.
An example tcp.smtp file with two records would look similar to this ('\' added for readability):
127.:allow,RELAYCLIENT="",DKSIGN="/var/qmail/control/domainkeys/%/private" :allow,BADMIMETYPE="",BADLOADERTYPE="M",\ QMAILQUEUE="/var/qmail/bin/simscan",\ CHKUSER_RCPTLIMIT="50",CHKUSER_WRONGRCPTLIMIT="10",\ DKSIGN="/var/qmail/control/domainkeys/%/private",\ DKVERIFY="DEGIJKfh",DKQUEUE="/var/qmail/bin/qmail-queue.orig"
Don't forget to:
# qmailctl cdb
to rebuild tcp.smtp.cdb if you change tcp.smtp.
Now you have DomainKeys set up on your QmailToaster server, your public key is on your DNS server, and your caching nameserver is up and running. You need to see if everything's working as it should.
Testing and Troubleshooting
Here are some tools for making sure you have things configured correctly. These tests can be, and probably should be, done from any computer, not necessarily the toaster.
DNSstuff: Free fast, advanced and comprehensive web-based DNS and domain name tools for DNS hosting.
In the far right column (Hostname Tests) you can do a standard hostname lookup. You need to put in your FQDN (Fully Qualified Domain Name) for your DomainKey, set the type to TXT, and click the lookup button.
For example, when you put in "private._domainkey.yourdomain.com", set it to TXT and click lookup, the next page will tell you what domain servers it queried, and will show the result, the "k=rsa; p=XXXxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" part of your DNS TXT entry.
You can do the same thing for the _domainkey.yourdomain.com entry to make sure you get the right result for that query.
Alternatively, you can use the dig command from a command line:
# dig _domainkey.yourdomain.com TXT # dig private._domainkey.yourdomain.com TXT
Dig it? :)
Yahoo! has also provided the same basic tools:
The mail servers that receive your mail will be making these same queries, so this is how you can find out if your dns entries are correct.
Once you think you have everything set up properly (after all, you followed the directions, right?), you should go to the:
Skylist Sender ID/SPF/DomainKeys Test Server
At the bottom of the page you can send an email to them, then review the results of their analysis of what you sent. This verifies that your outgoing domainkey and SPF settings are correct.
You can also test your configuration at the ESPC's SenderID/SPF/DomainKeys Test Server.
I don't know at this point how to verify that incoming domainkey processing is working properly. Maybe someone who knows will update the wiki here.