FWIW, I have the script I use (runs from cron.daily) for daily DKIM rotation
with AWS Route53 up as a gist here:

https://gist.github.com/ryancdotorg/a8f565b9e4f0902eb7b5cd4cdefeea0f

PLEASE NOTE: This script publishes the private keys after the selectors are
no longer valid to avoid giving sent email any long-term non-repudiation
properties. If you don't understand what this means, please do not use as-is.

I'm providing the script here as an example of automated key rotation using
an API rather than advocating my specific key rotation strategy.

On 2020-11-01 10:20, Mark Elkins via Exim-dev wrote:
Thank you for the comprehensive reply. OK - so this tells me that
receiving MTA's will look for a DKIM record with correct selector
(taken from the received email) and simply use that. There can
therefore only ever be one record with that selector (I re-watched
Highlander last night - There can only be One). If there are multiple,
the MTA may not check that any one of the replies works (as opposed to
DNSSEC - where any one chain that works means Success).

Thus one should use a selector which must be unique in the DNS to
specify the Key that the originating/signing MTA used.

So the Keys should change once a month (as an example of good key management).

Does Exim know the current month? Is there a Variable for the current
month in Exim? (Can I run the unix 'date' command to get the month?)

Could I then use something like...

dkim_selector = $Month

(I'd assume that EXIM works on UTC time, does it?)

If so - then I simply create new DKIM Keys for the domain say on the
24th of every month for the following month (and put the necessary
into the DNS) and then around the 8th of the month, do a clean-up of
old information. Just need to check that any new domains that appear
after the 24th are appropriately taken care of, such as, create this
and next months DKIM keys.

dkim_selector = $Month
... is simply way more readable than....
dkim_selector = ${sg{${sg{${lookup
{$dkim_domain}cdb{CDBMAILTABLES/dkim.selectors.hermes.cdb}
{$value}{OOPS}}}{\N=\w+\N}{}}}{\N\s+\N}{:}}

Having a selector of YYYYMM would also work for me - and provide a
better History.

ps  - it was a cut'n'paste plus anticipation that put a double '_'
into my previous email. I only really have one '_'.

On 2020/11/01 01:10, Phil Pennock via Exim-dev wrote:
On 2020-10-31 at 18:34 +0200, Mark Elkins via Exim-dev wrote:
[quoting:]
Of course, when you change your DKIM key pair, the public key in the DKIM
record needs to be changed as well.

That is very poorly phrased.

One selector corresponds to one DNS record.  There is no way to safely
change the public key in a given selector's DNS record: there will
always be races.

If you wish to change the public key, then you use a new selector.

Anyone advocating for changing which key one selector corresponds to,
without a major downtime/rest-period between values, does not understand distributed caching or distributed coherency. If you read such advice,
run away from it.

You pre-publish the new selector and wait for at least the zone SOA's
TTL field to expire: this is because if you use a predictable naming
scheme, then someone could pre-populate caches with the NXDOMAIN for
your new record, so you need to wait for negative cache entries to
expire.

Once your public key has been in DNS, in the new selector, for longer
than the previous update's SOA record's TTL, it's safe to start using.

You then need to wait for long enough for all mails stuck in queues
elsewhere to make their way through, for the validation to happen.

    create the domain.pem & domain.pub parts, create and publish the
    DKIM DNS record with the PUB data as "mail.__domainkey" (where
    "mail" is my selector).

No, single underscore for "_domainkey", not two.

[snip system based upon poorly worded advice]
Is this fine?

No.

If I have to have a different selector for a new DKIM key pair - and I'm signing about 40 domains - is there a suggested way to manage the currently
hard coded line in exim.conf of:-

There are two fundamental approaches to rotating selectors:

  1. Date-stamp
  2. Set of candidates (typically three)


### Date-stamp

I use the date-stamp approach: if this were coming with a From: of my
spodhuis.org domain, it would be dual-signed with the "d202008" and
"d202008e2" selectors (RSA, Ed25519).  A week from today, as the first
Saturday of "every three months", I have a calendar reminder to go ahead and generate the d202011 family of keys for my domains, and publish them in DNS. Then on Monday, I should go ahead and switch the selector used
by Exim for signing email.

As a very complicated example, the SMTP Transport in Exim has:

   dkim_domain   = ${domain:$acl_m_dkim_sender_address}
   # CDB has: domain.tld: dYYYYMM=rsa dYYYYMMe2=ed25519
dkim_selector = ${sg{${sg{${lookup {$dkim_domain}cdb{CDBMAILTABLES/dkim.selectors.hermes.cdb} {$value}{OOPS}}}{\N=\w+\N}{}}}{\N\s+\N}{:}} dkim_private_key = ${if eq{$dkim_selector}{OOPS}{false}{DKKEYDIR/${extract{$dkim_selector}{${lookup {$dkim_domain}cdb{CDBMAILTABLES/dkim.selectors.hermes.cdb}}}}.private.$dkim_selector.$dkim_domain}}
   dkim_strict   = ${if eq{$dkim_selector}{OOPS}{0}{1}}
   dkim_sign_headers = SPODHUIS_DKIM_SIGNHEADERS
# timestamps are Exim 4.92+; seconds to add to current time; 2 weeks == 1209600 seconds
   dkim_timestamps = 1209600

This is way overkill for you, but that's about as complicated as it
gets, and that's handling extracting two different selectors from the
value of a CDB lookup.  Very _very_ few people dual-sign with two
algorithms.  You can write something simpler.


### Set of candidates

I don't use this, but you see this used by mail service providers who
provide mail-sending for various companies, where they want to be able
to DKIM sign for their customers.

The MSP declares that three selectors may exist; to avoid the risk of
collisions, the sensible ones use a prefix which varies by MSP.  Thus
Fastmail have "fm1", "fm2", "fm3".  Mailchimp uses "k1", "k2", "k3".
(Some providers willing to vary selector per-customer let the customer
choose the selectors).

Assume "x1"/"x2"/"x3":

1. Your customer sets up CNAMEs for all three inside their domain, so that they have to touch DNS once, to set up the CNAMEs, then never have to change DNS again. You can rotate freely without having to
     coordinate with different DNS zones.
  2. You start with x1.  You publish it.  You use s=x1 in the DKIM
signatures. Leave x1/x2 empty, perhaps a TXT record `""`. As long as no mails are sent using those selectors, no validators will look them up in DNS, so you don't need to care. Just have something so that DNS control panels which check for "something exists for this
     CNAME" won't make life hard for your customers.
3. Later, you publish x2 in DNS. After a TTL wait, you can start using
     s=x2 in signatures.
  4. You leave x1 in DNS.  Let older signatures continue to validate.
5. Somewhere between "some time later" and "when you publish x3", you stop publishing x1 in DNS. Signatures made with that will no longer
     validate.
6. You publish x3. You unpublish x1 if it's still published. Follow
     the usual dance.
  7. After x3, circle back around to x1.

The three selectors form a ring, which conceptually have pointers:
"previous", "current", "next".  Only "current" has to exist normally;
"previous" should be left existing for some time afterwards. (Maybe two
weeks, maybe three months, it depends upon your rotation frequency).
"next" should exist for a DNS zone SOA TTL period, or longer, before it
becomes the current.


You should not ever try to change the key which an actively used
selector is pointing to.  The ring approach provides a compromise to
avoid the number of changes needed in DNS: there are static CNAMEs from the various zones to your published records. The date-stamped approach
means that things never expire, and if someone years later tries to
figure out "wait, why doesn't this signature validate" on a leaked
email, they can see the datestamp and know that it was probably
withdrawn.

-Phil


--
Mark James ELKINS  -  Posix Systems - (South) Africa
[email protected]       Tel: +27.826010496 <tel:+27826010496>
For fast, reliable, low cost Internet in ZA: https://ftth.posix.co.za
<https://ftth.posix.co.za>

--
## List details at https://lists.exim.org/mailman/listinfo/exim-dev Exim 
details at http://www.exim.org/ ##

Reply via email to