206 lines
7.0 KiB
ReStructuredText
206 lines
7.0 KiB
ReStructuredText
.. _dkim:
|
|
|
|
DKIM Signing
|
|
============
|
|
|
|
DKIM (DomainKeys Identified Mail) is an email authentication mechanism that
|
|
allows a mailserver to digitally sign outgoing emails for a domain. Receiving
|
|
mail servers can verify this signature using a public key published in DNS to
|
|
confirm the message was authorized by the domain and was not modified during
|
|
transit.
|
|
|
|
How DKIM works in practice
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
1. ``bob@bar.example`` sends an email to ``alice@foo.example``. The sending
|
|
mail server for ``bar.example`` selects one or multiple DKIM keys using a
|
|
**selector** (e.g., ``mail``) and creates one or multiple cryptographic
|
|
signature for selected headers and the message body, adding a ``DKIM-Signature``
|
|
header that references the selector.
|
|
|
|
2. The message arrives at ``foo.example``. The receiving mail server reads the
|
|
``DKIM-Signature`` headers, looks up the public keys for ``bar.example`` for
|
|
each of the specified selectors (e.g., ``mail._domainkey.bar.example``), and
|
|
verifies that at least one signature matches the message content.
|
|
|
|
3. With a valid signature, the receiver knows the message was authorized by
|
|
``bar.example`` and that the signed headers and body were not modified in
|
|
transit. If the content or signed headers were changed, the DKIM verification
|
|
fails. The use of selectors allows ``bar.example`` to rotate or migrate keys
|
|
without disrupting verification for previously sent messages.
|
|
|
|
Enabling DKIM Signing
|
|
~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
Because DKIM signing is crucial for reliable mail delivery it is enabled by
|
|
default and without further configuration a DKIM keypair will be generated for
|
|
each :option:`mailserver.domains` (including :option:`mailserver.srs.domain`,
|
|
if set) based on :option:`mailserver.dkim.defaults
|
|
<mailserver.dkim.defaults.keyLength>`.
|
|
|
|
.. code:: nix
|
|
|
|
{
|
|
mailserver = {
|
|
domains = [ "example.com" ];
|
|
dkim.enable = true; # enabled by default
|
|
};
|
|
}
|
|
|
|
|
|
.. note::
|
|
If you set up NixOS Mailserver before the `25.11 release`_ your DKIM keys were
|
|
generated with 1024 bit RSA and we recommend replacing them with 2048 bit
|
|
RSA key material per `RFC8301 3.2`_.
|
|
|
|
.. _25.11 release: release-notes.html#nixos-25-11
|
|
.. _RFC8301 3.2: https://www.rfc-editor.org/rfc/rfc8301#section-3.2
|
|
|
|
.. _dkim-key-rotation:
|
|
|
|
DKIM Key Rotation
|
|
~~~~~~~~~~~~~~~~~
|
|
|
|
DKIM key rotation replaces a domain's signing keys to maintain
|
|
strong email authentication and support algorithm upgrades. Rotation is
|
|
essential for migrating away from weaker or deprecated algorithms.
|
|
|
|
Selectors allow multiple keys to coexist during the transition: a new key can
|
|
be deployed under a different selector while the old key remains valid for a
|
|
limited period to verify messages still in transit. Once all messages signed
|
|
with the old key have been delivered, the key can be safely retired, ensuring a
|
|
reliable migration without breaking verification.
|
|
|
|
|
|
1. Make the automatically generated key explicit
|
|
************************************************
|
|
|
|
First we need to make sure we keep the current DKIM key configured. If you were
|
|
relying on automatically generated keys before, you now need to start explicitly
|
|
defining that key, because explicit selector configuration takes precedence.
|
|
|
|
.. code:: nix
|
|
|
|
{
|
|
mailserver = {
|
|
domains = [ "example.com" ];
|
|
dkim.domains = {
|
|
"example.com".selectors = {
|
|
"${config.mailserver.dkim.defaults.selector}" = { };
|
|
};
|
|
};
|
|
};
|
|
}
|
|
|
|
|
|
2. Create the new DKIM keypair
|
|
******************************
|
|
|
|
Next we need to create a new DKIM key with a unique selector, you can
|
|
for example choose the current date. Without any settings passed a new
|
|
key will be generated from the current :option:`mailserver.dkim.defaults
|
|
<mailserver.dkim.defaults.keyLength>`, which should be sufficient.
|
|
|
|
.. code:: nix
|
|
|
|
{
|
|
mailserver = {
|
|
domains = [ "example.com" ];
|
|
dkim = {
|
|
enable = true;
|
|
domains."example.com".selectors = {
|
|
"${config.mailserver.dkim.defaults.selector}" = { };
|
|
"rsa-2026-03" = {
|
|
keyType = "rsa";
|
|
keyLength = 2048;
|
|
};
|
|
};
|
|
};
|
|
};
|
|
}
|
|
|
|
.. warning::
|
|
While DKIM does support Ed25519 keys (`RFC8463`_), many validators still lack
|
|
proper support and may treat Ed25519 key material as invalid. As a result,
|
|
mail signed only with Ed25519 DKIM keys may fail verification at some
|
|
receivers.
|
|
|
|
.. _RFC8463: https://datatracker.ietf.org/doc/html/rfc8463
|
|
|
|
Once this configuration is applied the new keypair will be generated below
|
|
:option:`mailserver.dkim.keyDirectory`, which defaults to ``/var/dkim``. The
|
|
mailserver then begins signing outgoing mail with this key, so that it is now
|
|
signing with two DKIM keys simultaneously.
|
|
|
|
To allow receiving servers to verify the new DKIM signature its
|
|
public key needs to be published into DNS. Look up the public key from
|
|
``/var/dkim/example.com.rsa-2026-03.txt`` and create the following DNS record by
|
|
substituting selector and public key.
|
|
|
|
.. csv-table::
|
|
:header: "Name", "TTL", "Type", "Value"
|
|
:widths: 30, 10, 10, 50
|
|
|
|
rsa-2026-03._domainkey.example.com., 86400, TXT, v=DKIM1; k=rsa; p=<public key>
|
|
|
|
.. note::
|
|
If you created an Ed25519 key, make sure to set the correct key type: ``k=ed25519``
|
|
|
|
Now wait for a few minutes and then check DNS propagation to show the value specified.
|
|
|
|
.. code-block:: console
|
|
|
|
$ nix-shell -p dig --command "dig @ns1.example.org TXT rsa-2026-03._domainkey.example.com"
|
|
|
|
You can use https://www.mail-tester.com to test the new DKIM signature passes
|
|
validation. They allow you to view the message source where you can check that
|
|
the correct number of ``DKIM-Signature`` keys are present in the mail header.
|
|
|
|
|
|
3. Stop signing with the old DKIM keypair
|
|
*****************************************
|
|
|
|
Once validation passes we need to stop signing with the old DKIM keypair, so
|
|
mail in transit eventually stops depending on the key material we want to rotate
|
|
out. Removing the selector will not remove the key material from disk, but it
|
|
will stop using it to sign outgoing mail.
|
|
|
|
.. code:: nix
|
|
|
|
{
|
|
mailserver = {
|
|
domains = [ "example.com" ];
|
|
dkim = {
|
|
enable = true;
|
|
domains."example.com".selectors = {
|
|
"rsa-2026-03" = {
|
|
keyType = "rsa";
|
|
keyLength = 2048;
|
|
};
|
|
};
|
|
}
|
|
}
|
|
}
|
|
|
|
Apply the configuration.
|
|
|
|
|
|
4. Remove the old DKIM selector from DNS
|
|
****************************************
|
|
|
|
.. warning::
|
|
Do not remove the DNS records for the old selector immediately. Keeping them
|
|
in place is essential to ensure that messages still in transit can be verified
|
|
and delivered successfully.
|
|
|
|
Mail delivery is not always instantaneous. In the worst case, multiple retries
|
|
over several days may be required. According to `RFC5321 4.5.4.1`_ delivery
|
|
should be retried for at least 4-5 days.
|
|
|
|
This means messages signed only with the old DKIM key could still be in transit
|
|
and rely on the old selector to verify their signatures. To ensure reliable
|
|
delivery, we recommend waiting **at least five days** before removing the old
|
|
DKIM selector from DNS.
|
|
|
|
.. _RFC5321 4.5.4.1: https://www.rfc-editor.org/rfc/rfc5321#section-4.5.4.1
|