Rotate DKIM in mail.core.io environment

Rotate the DKIM keys every half a year or maybe more often is recommended. On our mail.core.io environment we’ve multiple nodes running which could be a pain in the ass to do it manually.

Because all our infrastructure is build on SmartOS we use zones. The benefit is we could store key information in mdata. For the rotation we only need to update the mdata variables and run one script to copy the information to an local file.

Create a new key

One of the easiest steps is to create a new public and private key pair with the awesome openssl command. I’m sure you love it the same way I does ;-)

# create one variable make it easy to update

# generate private key, keep it secret
openssl genrsa -out ${DKIM_SELECTOR}.key 1024
# generate public key
openssl rsa -in ${DKIM_SELECTOR}.key -pubout > ${DKIM_SELECTOR}.crt

# convert to the public part you need for DNS
echo -n "v=DKIM1; k=rsa; p=" > ${DKIM_SELECTOR}.pub
cat ${DKIM_SELECTOR}.crt | grep -v '^--' | tr -d "\n" \
    >> ${DKIM_SELECTOR}.pub

I like to have one file ${DKIM_SELECTOR}.pub which contains the DNS part.

Update your dns records

This depends on your provider. Maybe they provide an API for your so you could create your own script to modify the DNS entry.

Your record should look like:

# Source as bash example
${DKIM_SELECTOR}._domainkey. IN TXT "$(cat ${DKIM_SELECTOR}.pub)"

# Example
submission-20150205._domainkey. IN TXT "v=DKIM1; k=rsa; p=MIGfMA0GCSqGS..."

This isn’t required but I recommend to wait half a day before deploy the new key on the production system. This will allow all DNS caches updated and share the new record.

Deploy the key to the mailserver

Deployment time :-) You need to upload and update your configuration files, reload exim service - and this needs to be done on all your mail servers. So it’s time for using ansbile ad-hoc commands.

Be sure you have an inventory which could be located at ~/.ansible/hosts:

smtp.example.de   ansible_ssh_user=root
smtp.example.com  ansible_ssh_user=root
mx.example.com    ansible_ssh_user=root
mx.example.de     ansible_ssh_user=root

For SmartOS you require the following line. This allow ansible to find the python interpreter.

ansible_python_interpreter = /opt/local/bin/python

Ready for to run? Here we go. Be sure you’re at the same location as your DKIM files.

# define the group you're using at the inventory file

# update information in mdata variables
ansible ${GROUP} -m copy  \
  -a "src=${DKIM_SELECTOR}.key dest=/root/${DKIM_SELECTOR}.key"
ansible ${GROUP} -m shell \
  -a "cat /root/${DKIM_SELECTOR}.key | mdata-put dkim_private_key"
ansible ${GROUP}          \
  -a "rm /root/${DKIM_SELECTOR}.key"
ansible ${GROUP} -m shell \
  -a "echo ${DKIM_SELECTOR} | mdata-put dkim_selector"

# run reprovision script which will write mdata information to file
ansible ${GROUP}          \
  -a '/usr/bin/bash /opt/core/var/mdata-setup/includes/31-exim.sh'

# reload exim service
ansible ${GROUP} -m service -a "name=exim state=reloaded"

Because I use the pipe to put information into mdata the -m shell is required. Ansible only support piping and other special commands if you have a valid shell.

Send your comment by mail.