DNSSEC, SPF, DKIM and DMARC explained

over 4 years ago

Securing email authenticity can be easy, once you have everything in place. Trying to find a single location with all the information can be a little more difficult.

Here, I'll try to explain the technologies used to help secure and define email authenticity for receiving MTA using one of my domains as an example (isam.melbourne).

This diagram gives an overview of the glue for these technologies, of which I will explain a bit more after I've discussed each of them in turn:


Domain Name System Security Extensions (DNSSEC)

First off, I'll try to explain Domain Name System Security Extensions (DNSSEC) - (RFC4033 and others).

DNSSEC provides checks to DNS responses to validate the information received is correct and authoritative and hasn't been poisoned. This is achieved by first signing the zone, then uploading the Domain Keys to the parent zone via the domain's Registra which will allow query DNS servers to receive RRSIG (Resource Record Signature) types to any query against the zone.

This will provide the additional security for the DNS records required for SPF, DKIM and DMARC (explained later).

First, you need to check that DNSSEC is supported against your parent zone and that both your domain's Registra and zone host offers DNSSEC support. The later can be a bit challenging as the definition of "support" can be confused. It is possible that the host of your zone does not allow signing of the zone. For me, I host the primary zones at home on Bind 9 which does support DNSSEC so I only run into issues with the Registras not supporting upload of DS keys to the parent zone. If this is the case, you can follow ICANN's process for resolving this.

If you decide to use Bind 9 to host your zones, here's some scripts and tips for managing the zone signing and keys.

First, set up some directory structures so things don't get too confusing. I run Bind on SLES so utilise most of the default directory structures but have created some to segregate files as per the named.conf changes to the options section:

  • directory "/var/lib/named";
  • managed-keys-directory "/var/lib/named/dyn/";
  • key-directory "/etc/named.d/keys/";
  • notify yes;
  • version none;
  • hostname "dns01.isam.kiwi";
  • include "/etc/named.d/keys/forwarders.conf";
  • empty-zones-enable yes;
  • dnssec-enable yes;
  • dnssec-validation auto;
  • dnssec-lookaside auto;

I keep the original unsigned zone files in a /etc/named.d/keys/zones/master/ directory as a backup and source for changes to the zone before copying the altered file(s) to /var/lib/named/master/.

I use the following dnssec-reload.sh script to perform multiple tasks (you would update the DNSZONE array variable to match your zones - based on file "master/isam.melbourne";

  1. Create Zone and Zone Key signing keys if they don't exist.
  2. Attach DKIM entry to zone (see below) if it exists.
  3. Add the public Zone and Zone Key output to the zone.
  4. Update signed zone for use by Bind.


DNSZONES=( 'isam.melbourne' )

while [ "${index}" -lt "${DNSZONES_COUNT}" ]
	if ls K${DNSZONES[index]}*.key 1> /dev/null 2>&1;
		echo "Not regenerating keys"
		rm -f K${DNSZONES[index]}*.key
		rm -f K${DNSZONES[index]}*.private
		dnssec-keygen -a ECDSAP256SHA256 -b 2048 -n ZONE ${DNSZONES[index]}
		dnssec-keygen -f KSK -a ECDSAP256SHA256 -b 4096 -n ZONE ${DNSZONES[index]}
	cp "${DNSSEC_MSTDIR}/${DNSZONES[index]}" "${DNSSEC_MSTDIR}/${DNSZONES[index]}.zone"
	if [ -f zones/master/${DNSZONES[index]}.dkim.txt ]
		echo "Adding zones/master/${DNSZONES[index]}.dkim.txt to ${DNSSEC_MSTDIR}/${DNSZONES[index]}.zone"
		cat zones/master/${DNSZONES[index]}.dkim.txt>> "${DNSSEC_MSTDIR}/${DNSZONES[index]}.zone"
	for key in `ls K${DNSZONES[index]}*.key`
		echo "Adding $key to ${DNSSEC_MSTDIR}/${DNSZONES[index]}.zone"
		tail -1 "$key">> "${DNSSEC_MSTDIR}/${DNSZONES[index]}.zone"
	dnssec-signzone -A -3 $(head -c 1000 /dev/random | sha1sum | cut -b 1-16) -K ${DNSSEC_KEYDIR}/ -N unixtime -o ${DNSZONES[index]} -t ${DNSZONES[index]}.zone
	((index  ))

cp ${DNSSEC_MSTDIR}/dsset-* ${DNSSEC_KEYDIR}/zones/master/
chown named:named ${DNSSEC_MSTDIR}/*

This will output a lot of files, but you only need to worry about the dsset-isam.melbourne. and the isam.melbourne.zone.signed files. You'll find the later is the zone file you want to use and has a stack of RRSIG records for each zone resource record, so you want to update your Bind reference (file "master/isam.melbourne.zone.signed";) and reload named.

Next, you want to use your Registra's Control Panel to upload the 2 DS Key entries from the dsset-isam.melbourne. file (I use GoDaddy, but have had significant issues with them and have required ICANN to get involved). Refer to the above diagram's top right key that explains the following value formats (IANA DNSSEC Algorithms

isam.melbourne.		IN DS 55649 13 1 {HASH}
isam.melbourne.		IN DS 55649 13 2 {HASH}

Once all this is done, you can check that DNSSEC is fully implemented for your zone.


As you can see, the root zone is fine, the .melbourne zone is fine, and the isam.melbourne zone is fine.

You can also use a dig command similar to dig DNSKEY isam.melbourne. dnssec multi to verify the zone has loaded DNSSEC properly.

Sender Policy Framework (SPF)

Next I'll try to explain Sender Policy Framework (SPF) - (RFC4408).

This is a formatted TXT resource record at the level of the sending domain (i.e. for emails from @isam.melbourne, the TXT record needs to be at isam.melbourne.). Initially there was talk about a specific SPF Resource Record, but this has been dropped in favor of the TXT Resource Record due to the lower implementation costs.

The format is rather simple and basically "lists" the sending IP addresses that are allowed for the domain:

  • v=spf1 - the version of SPF.
  • a:mail.isam.melbourne - allow ( ) the IP (A DNS resource record for mail.isam.melbourne) to send emails from this domain.
  • include:dynu.com - include the SPF policy from dynu.com (who I relay through due to ISP restrictions).
  • -all - finally hard deny (-) everything else.

The result is that my zone record shows:

@		IN	TXT	"v=spf1  a:mail.isam.melbourne  a:relay.dynu.com  include:dynu.com -all"

Some other details on the variables and switches can also be found on Wikipedia.

DomainKeys Identified Mail (DKIM)

Thirdly, I'll try to explain DomainKeys Identified Mail (DKIM) - (RFC6376).

DKIM uses public and private keys to "sign" emails so that the receiving MTA can confirm the authenticity of the email. My relay provider offers a nice free tool for generating DKIM keys. This requires 3 inputs:

  • Domain Name - the send email domain name (isam.melbourne)
  • DomainKey Selector - the name for the DKIM key which will also be referenced in DNS (dynudkim)
  • Key Size - Size of the key (I chose 2048)

The output is the Public Key (goes into DNS) and the Private Key (used for signing the emails). GroupWise does not currently support DKIM signing, thankfully my relay provider does.

To easily add the DKIM RR to DNS, I just create the /etc/named.d/keys/zones/master/isam.melbourne.dkim.txt file as per below and re-run the dnssec-reload.sh script.

dynudkim._domainkey			IN	TXT	("v=DKIM1; k=rsa; h=sha256; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AM"
							"IIBCgKCAQEAoc k/5Vtid7 NQd/fWgK9 f0mpc0CWuUnn8Q7 5C9KtArPZmsq7"
							"xksc05jlDfZKIa0A74Nt Z7EhuCDgaG0bdl zcqkO t4ZwG9/sGgi3qfObGu9j"
							"6dWvvyuQCkNAJYsk7ZtBbbCBp7K2fBnqDWpv9N8wt8BQBc KCCC17koX2t2QW "
							"RdC4o tpVgvk8vL a3N5CE/yu/hS61uTrwaG9 ZLWCwIDAQAB")
dynudkim._domainkey.relay		IN	TXT	("v=DKIM1; k=rsa; h=sha256; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AM"
							"IIBCgKCAQEAoc k/5Vtid7 NQd/fWgK9 f0mpc0CWuUnn8Q7 5C9KtArPZmsq7"
							"xksc05jlDfZKIa0A74Nt Z7EhuCDgaG0bdl zcqkO t4ZwG9/sGgi3qfObGu9j"
							"6dWvvyuQCkNAJYsk7ZtBbbCBp7K2fBnqDWpv9N8wt8BQBc KCCC17koX2t2QW "
							"RdC4o tpVgvk8vL a3N5CE/yu/hS61uTrwaG9 ZLWCwIDAQAB")

Again this utilises the TXT Resource Record type, but does require it to be within the _domainkey subdomain of the sending email domain. The name of the RR is the DomainKey Selector entered above. The TXT has 3 components:

  • v= - the version of DKIM (DKIM1).
  • k= - Encryption (rsa).
  • h= - Signing Algorithm (sha256 - specified below).
  • p= - the public key generated above.

Next, the private key is uploaded to my relay provider for use (obviously I've taken the private key value out for this image).


When emails now go through the relay server, the dkim-signature header is added to the email for use by the receiving MTA.

Domain-based Message Authentication, Reporting, and Conformance (DMARC)

Finally, I'll try to explain Domain-based Message Authentication, Reporting, and Conformance (DMARC) - (RFC7489).

DMARC ties SPF and DKIM together. It defines the policy to enact should SPF or DKIM fail, so by definition both SPF and DKIM must be set up and functioning before deploying a DMARC policy.

Again, DMARC utilises the TXT Resource Record and must be set at the subdomain _dmarc of the sending domain.

_dmarc.isam.melbourne.	IN	TXT	"v=DMARC1; p=quarantine; sp=quarantine; pct=100; ruf=mailto:dmarc@isam.melbourne; rua=mailto:dmarc@isam.melbourne"
  • v=DMARC1 - the version of DMARC1.
  • p= - Policy to enact when SPF or DKIM fails (quarantine).
  • sp= - Policy to enact when SPF or DKIM fails for subdomains (quarantine).
  • pct= - percentage of emails to check (100%).
  • rua= - Reporting URI of aggregate reports (mailto:dmarc@isam.melbourne).
  • ruf= - Reporting URI of forensic reports (mailto:dmarc@isam.melbourne).

Some other details on the variables, switches and deployment scenarios can also be found on Google.

If your rua or ruf send reports to another domain, then additional DNS is required. For example, lets say I have email sent from domain.com that has the same DMARC as I have for isam.melbourne, then I would require the following TXT record in my isam.melbourne zone:

domain.com._report._dmarc.isam.melbourne.	IN	TXT	"v=DMARC1"


So, by implementing these technologies, receiving MTA's can be guaranteed that the email originated from an authorised sender. SPF and DKIM validate that the sending server was authorised, DMARC defines what to do on failure, and DNSSEC guarantees that the DNS records relating to SPF, DKIM and DMARC are all valid and haven't been poisoned.

Look at the first image now, it should make sense on how everything hangs together.

Comment List
Related Discussions