What was DomainKeys?
DomainKeys is an email authentication technology developed by Yahoo that uses cryptographic techniques to verify the sender’s domain in email messages. It helps protect against email spoofing and phishing by allowing the recipient to confirm that the message was sent from an authorised server for the domain in the “From” address. DomainKeys was later enhanced and evolved into DomainKeys Identified Mail (DKIM), which is now the industry standard.
DKIM Improvements
DKIM (DomainKeys Identified Mail) is an improved and more robust version of DomainKeys, designed to enhance email authentication, security, and interoperability. Here’s how DKIM is better than DomainKeys:
Improved Security and Flexibility
DKIM supports stronger cryptographic algorithms (such as RSA with larger key sizes), and allows for easier key rotation, allowing updates their keys without disrupting email flow,
Signature Flexibility
DKIM allows selective signing of headers and can sign multiple headers, giving administrators greater control over what part of the email is authenticated. DKIM also contains a hash of the email body in the signature, ensuring that the content hasn't been modified in transit.
Interoperability and Adoption
DKIM was developed by the IETF as a standardised protocol, which has helped make it more widely adopted and supported. Working with DMARC (Domain-based Message Authentication, Reporting, and Conformance) it creates an additional layer of protection against phishing and spoofing.
Adoption by Major Email Providers
Importantly, DKIM is required by major providers (like Google, Microsoft, and Yahoo), to ensure better deliverability and security for DKIM-signed emails,
What is OpenDKIM
OpenDKIM (Open DomainKeys Identified Mail) is an open-source implementation of DKIM, which stands for DomainKeys Identified Mail. It is a standard used to authenticate email messages, verify their integrity, and prevent email spoofing by adding cryptographic signatures to outgoing emails. OpenDKIM’s primary purpose is to sign, verify, and validate emails to improve email deliverability and security.
Configuring OpenDKIM
Install OpenDKIM using apt
root@docs:~# apt-get install opendkim
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
The following additional packages will be installed:
dns-root-data libevent-2.1-7t64 libhashkit2t64 liblua5.3-0 libmemcached11t64 libmilter1.0.1 libopendbx1-sqlite3 libopendbx1t64 libopendkim11 librbl1 libunbound8 libvbr2
opendkim-tools
The following NEW packages will be installed:
dns-root-data libevent-2.1-7t64 libhashkit2t64 liblua5.3-0 libmemcached11t64 libmilter1.0.1 libopendbx1-sqlite3 libopendbx1t64 libopendkim11 librbl1 libunbound8 libvbr2 opendkim
opendkim-tools
0 upgraded, 14 newly installed, 0 to remove and 2 not upgraded.
Need to get 1250 kB of archives.
After this operation, 3914 kB of additional disk space will be used.
Do you want to continue? [Y/n] y
Add postfix to the opendkim group created during installation of the packages
sudo gpasswd -a postfix opendkim
Edit the /etc/opendkim.conf
file locating:
- LogWhy and change it to Yes, this will add additional logging showing why decisions were taken
- Canonicalization and change it to simple (note the American Spelling)
Under OversignHeaders insert the following lines
AutoRestart yes
AutoRestartRate 10/1M
Background yes
DNSTimeout 5
SignatureAlgorithm rsa-sha256
Append the following to the bottom of the configuration file
# Map domains in From addresses to keys used to sign messages
KeyTable refile:/etc/opendkim/key.table
SigningTable refile:/etc/opendkim/signing.table
# Hosts to ignore when verifying signatures
ExternalIgnoreList /etc/opendkim/trusted.hosts
# A set of internal hosts whose mail should be signed
InternalHosts /etc/opendkim/trusted.hosts
Once completed the file should be similar to this
# This is a basic configuration for signing and verifying. It can easily be
# adapted to suit a basic installation. See opendkim.conf(5) and
# /usr/share/doc/opendkim/examples/opendkim.conf.sample for complete
# documentation of available configuration parameters.
Syslog yes
SyslogSuccess yes
LogWhy yes
# Common signing and verification parameters. In Debian, the "From" header is
# oversigned, because it is often the identity key used by reputation systems
# and thus somewhat security sensitive.
Canonicalization relaxed/simple
Mode sv
SubDomains no
OversignHeaders From
AutoRestart yes
AutoRestartRate 10/1M
Background yes
DNSTimeout 5
SignatureAlgorithm rsa-sha256
# Signing domain, selector, and key (required). For example, perform signing
# for domain "example.com" with selector "2020" (2020._domainkey.example.com),
# using the private key stored in /etc/dkimkeys/example.private. More granular
# setup options can be found in /usr/share/doc/opendkim/README.opendkim.
#Domain example.com
#Selector 2020
#KeyFile /etc/dkimkeys/example.private
# In Debian, opendkim runs as user "opendkim". A umask of 007 is required when
# using a local socket with MTAs that access the socket as a non-privileged
# user (for example, Postfix). You may need to add user "postfix" to group
# "opendkim" in that case.
UserID opendkim
UMask 007
# Socket for the MTA connection (required). If the MTA is inside a chroot jail,
# it must be ensured that the socket is accessible. In Debian, Postfix runs in
# a chroot in /var/spool/postfix, therefore a Unix socket would have to be
# configured as shown on the last line below.
Socket local:/run/opendkim/opendkim.sock
#Socket inet:8891@localhost
#Socket inet:8891
#Socket local:/var/spool/postfix/opendkim/opendkim.sock
PidFile /run/opendkim/opendkim.pid
# Hosts for which to sign rather than verify, default is 127.0.0.1. See the
# OPERATION section of opendkim(8) for more information.
#InternalHosts 192.168.0.0/16, 10.0.0.0/8, 172.16.0.0/12
# The trust anchor enables DNSSEC. In Debian, the trust anchor file is provided
# by the package dns-root-data.
TrustAnchorFile /usr/share/dns/root.key
#Nameservers 127.0.0.1
# Map domains in From addresses to keys used to sign messages
KeyTable refile:/etc/opendkim/key.table
SigningTable refile:/etc/opendkim/signing.table
# Hosts to ignore when verifying signatures
ExternalIgnoreList /etc/opendkim/trusted.hosts
# A set of internal hosts whose mail should be signed
InternalHosts /etc/opendkim/trusted.hosts
Now the initial setup for OpenDKIM has been completed, you will need to set up the Key Table, Signing Table, and Trusted Hosts Files. Before doing this, you will need to decide on what zone you are going to sign. It will be in the format of <string>.domainkey where <string> is an arbitrary string, in the following example I will be using the FQDN of home._domainkey.schwetz.au
.
Before getting to signing, we have a little housekeeping to do. Starting with the creation of the directory structure, then set the owner of the directory to opendkim:opendkim
and set it so that only the OpenDKIM user can access the keys.
sudo mkdir /etc/opendkim
sudo mkdir /etc/opendkim/keys
sudo chown -R opendkim:opendkim /etc/opendkim
sudo chmod go-rw /etc/opendkim/keys
Now it is time to edit the signing table by editing the /etc/opendkim/signing.table
adding two lines to the file. This tells OpenDKIM that if the sender matches the domain schwetz.au
or <subdomain>.schwetz.au
the email will be signed.
*@schwetz.au
*@*.schwetz.au
Edit the /etc/opendkim/key.table
and add the following line telling OpenDKIM where it can locate the private key, ensure that it is all one line.
home._domainkey.schwetz.au home:/etc/opendkim/keys/schwetz.au/home.private
Next we need to update the /etc/trusted_hosts
to allow the hosts that we trust to be signed. I permit my lan subnet (10.0.0.0/8) to be signed
127.0.0.1
localhost
10.0.0.0/8
.schwetz.au
Now it is time to create the public/private key pair that will be used to sign and authenticate the message as trusted. The first step is to create the folder to hold the keys, standard is to use the domain name.
sudo mkdir /etc/opendkim/keys/schwetz.au/
Generate the keypair using the opendkim-genkey
tool.
sudo opendkim-genkey -b 2048 -d schwetz.au -D /etc/opendkim/keys/schwetz.au -s home -v
The above command will create 2048 bit keys. -d
(domain) specifies the domain. -D
(directory) specifies the directory where the keys will be stored, and we use default as the selector -s
, also known as the name. Once the command is executed, the private key will be written to home.private
file and the public key will be written to home.txt
file.
Make opendkim as the owner of the private key and change the permissions so that only the opendkim user can read and write the file.
sudo chown opendkim:opendkim /etc/opendkim/keys/your-domain.com/default.private
Below is an example of the public key. We will prepare this so that it can be published to the internet.
root@docs:~# cat /etc/opendkim/keys/schwetz.au/home.txt
home._domainkey IN TXT ( "v=DKIM1; h=sha256; k=rsa; "
"p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAkgruYh6NHEwOPnJNrVACjUXcr8BMt1TwaUuy0/Rd3sMtMCX9eYn0YofOcnSoHqc/bYLI9RpnDCLHi2OK9xg3hSiQwtz1SaHVp42O2RE1Ne5BeDqQSl6l86F91V5Aiz42eVH2DkvCs8eVUvj/1/kOR/3igUMExrM23ctivXwzUGIElOgOByPTXr8anYNb5A+ZWhkzgvWBXuBL7/"
"Ioxddo+JtMbr5hO2gwQ+lAiQstoYx9EyCiC3czAQXIdtV5+kJVJOyoP7DlF2RIDEM0DaTD6NZ6e9IYxmiak688Ye+xdZxUmJpUhl+F9O792tqfVVqxaFEofTzqrcyudFuqZUZepwIDAQAB" ) ; ----- DKIM key home for schwetz.au
When the public key is saved by OpenDKIM it saves it split across multiple lines, and these need to be recombined, and in all of the guides that I have seen do not advise how to do it, and many years ago it took me a couple of attempts to get this part correct.
To accomplish this, remove:
- everything on the first line that prepends v=DKIM
- from after k=rsa; until the second " (inclusive)
- from the " and following " (inclusive)
- " ) ; --— DKIM key home for schwetz.au
v=DKIM1; h=sha256; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAkgruYh6NHEwOPnJNrVACjUXcr8BMt1TwaUuy0/Rd3sMtMCX9eYn0YofOcnSoHqc/bYLI9RpnDCLHi2OK9xg3hSiQwtz1SaHVp42O2RE1Ne5BeDqQSl6l86F91V5Aiz42eVH2DkvCs8eVUvj/1/kOR/3igUMExrM23ctivXwzUGIElOgOByPTXr8anYNb5A+ZWhkzgvWBXuBL7/Ioxddo+JtMbr5hO2gwQ+lAiQstoYx9EyCiC3czAQXIdtV5+kJVJOyoP7DlF2RIDEM0DaTD6NZ6e9IYxmiak688Ye+xdZxUmJpUhl+F9O792tqfVVqxaFEofTzqrcyudFuqZUZepwIDAQAB
You will then need to add the created public key to your DNS hosting, I use Cloudflare zone file and added the TXT record from above.
root@docs:~# dig txt home._domainkeys.schwetz.au
; <<>> DiG 9.18.28-0ubuntu0.24.04.1-Ubuntu <<>> txt home._domainkeys.schwetz.au
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 54675
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1232
;; QUESTION SECTION:
;home._domainkeys.schwetz.au. IN TXT
;; ANSWER SECTION:
home._domainkeys.schwetz.au. 300 IN TXT "v=DKIM1; h=sha256; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAkgruYh6NHEwOPnJNrVACjUXcr8BMt1TwaUuy0/Rd3sMtMCX9eYn0YofOcnSoHqc/bYLI9RpnDCLHi2OK9xg3hSiQwtz1SaHVp42O2RE1Ne5BeDqQSl6l86F91V5Aiz42eVH2DkvCs8eVUvj/1/kOR/3igUMExrM23ctivXwzUGIElOgOByPTXr8" "anYNb5A+ZWhkzgvWBXuBL7/Ioxddo+JtMbr5hO2gwQ+lAiQstoYx9EyCiC3czAQXIdtV5+kJVJOyoP7DlF2RIDEM0DaTD6NZ6e9IYxmiak688Ye+xdZxUmJpUhl+F9O792tqfVVqxaFEofTzqrcyudFuqZUZepwIDAQAB"
;; Query time: 15 msec
;; SERVER: 10.69.6.1#53(10.69.6.1) (UDP)
;; WHEN: Tue Nov 12 10:42:33 UTC 2024
;; MSG SIZE rcvd: 490
Testing Deployment
Enter the following command on the server to test that the key has been deployed successfully
opendkim-testkey -d schwetz.au -s home -vvv
You will then be presented with the verification
root@docs:~# opendkim-testkey -d schwetz.au -s home -vvv
opendkim-testkey: using default configfile /etc/opendkim.conf
opendkim-testkey: checking key 'home._domainkey.schwetz.au'
opendkim-testkey: key secure
opendkim-testkey: key OK
opendkim-testkey: key OK
then the key has been deployed correctlyopendkim-testkey: Key no secure
, this is not as bad as it looks, it means that the key is not secured with DNSSEC, you can continue.Connect OpenDKIM to Postfix
Create a directory to hold the OpenDKIM socket file and allow only opendkim user and postfix group to access it.
sudo mkdir /var/spool/postfix/opendkim
sudo chown opendkim:postfix /var/spool/postfix/opendkim
Edit the OpenDKIM configuration file /etc/opendkim.conf
and locate the line
Socket local:/run/opendkim/opendkim.sock
replacing it with the following line
Socket local:/var/spool/postfix/opendkim/opendkim.sock
Edit the /etc/postfix file and add the following milter configuration to the bottom of the file
# Milter configuration
milter_default_action = accept
milter_protocol = 6
smtpd_milters = local:opendkim/opendkim.sock
non_smtpd_milters = $smtpd_milters
One you have saved and closed the file restart OpenDKIM and Postfix services
sudo systemctl restart opendkim postfix