Add support for DKIM key management

After bumping the generation of new DKIM keys to RSA 2048 in NixOS 25.11
key rotation for existing users could not be done safely.

To resolve this situation we now support multiple generations of
selectors per domain to enable proper DKIM key transitions as described
in RFC6376 3.1. The added documentation introduces and motivates DKIM
and guides the user through a DKIM key rotation.

Additionally, DKIM key material can now also be treated as a managed
secrets when autogenerated state on the mail server host is undesirable.

This change is fully backwards compatible in behavior and will continue
to use the previously generated DKIM key without any additional
configuration up until the point when DKIM selectors are configured
explicitly.
This commit is contained in:
Martin Weinelt
2026-03-06 02:36:42 +01:00
parent ea775773d9
commit 6ff4a50f02
11 changed files with 512 additions and 86 deletions
+2 -3
View File
@@ -46,6 +46,8 @@ SNM branch corresponding to your NixOS version.
* [x] Via ClamAV * [x] Via ClamAV
* DKIM Signing * DKIM Signing
* [x] Via Rspamd * [x] Via Rspamd
* [x] Automatic key generation
* [x] Multiple selectors per Domain
* User Management * User Management
* [x] Declarative user management * [x] Declarative user management
* [x] Declarative password management * [x] Declarative password management
@@ -66,9 +68,6 @@ SNM branch corresponding to your NixOS version.
* [ ] [Autoconfig](https://web.archive.org/web/20210624004729/https://developer.mozilla.org/en-US/docs/Mozilla/Thunderbird/Autoconfiguration) * [ ] [Autoconfig](https://web.archive.org/web/20210624004729/https://developer.mozilla.org/en-US/docs/Mozilla/Thunderbird/Autoconfiguration)
* [ ] [Autodiscovery](https://learn.microsoft.com/en-us/exchange/architecture/client-access/autodiscover?view=exchserver-2019) * [ ] [Autodiscovery](https://learn.microsoft.com/en-us/exchange/architecture/client-access/autodiscover?view=exchserver-2019)
* [ ] [Mobileconfig](https://support.apple.com/guide/profile-manager/distribute-profiles-manually-pmdbd71ebc9/mac) * [ ] [Mobileconfig](https://support.apple.com/guide/profile-manager/distribute-profiles-manually-pmdbd71ebc9/mac)
* DKIM Signing
* [ ] Allow per domain selectors
* [ ] Allow passing DKIM signing keys
* Improve the Forwarding Experience * Improve the Forwarding Experience
* [ ] Support [ARC](https://en.wikipedia.org/wiki/Authenticated_Received_Chain) signing with [Rspamd](https://rspamd.com/doc/modules/arc.html) * [ ] Support [ARC](https://en.wikipedia.org/wiki/Authenticated_Received_Chain) signing with [Rspamd](https://rspamd.com/doc/modules/arc.html)
* User management * User management
+164 -50
View File
@@ -917,63 +917,170 @@ in
''; '';
}; };
dkimSigning = mkOption { dkim = {
type = types.bool; enable = mkEnableOption "DKIM signing" // {
default = true; default = true;
description = '' };
Whether to activate dkim signing.
'';
};
dkimSelector = mkOption { keyDirectory = mkOption {
type = types.str; type = types.path;
default = "mail"; default = "/var/dkim";
description = '' description = ''
The DKIM selector. The path where DKIM siging keys are stored.
''; '';
}; };
dkimKeyDirectory = mkOption { defaults = {
type = types.path; selector = mkOption {
default = "/var/dkim"; type = types.str;
description = '' default = "mail";
The DKIM directory. description = ''
''; The default selector used to reference and lookup DKIM keys.
};
dkimKeyType = mkOption { This value should most likely not be changed. Instead manage
type = types.enum [ {option}`mailserver.dkim.domains.<name>.selectors` to sign with one
"rsa" or multiple DKIM key pairs and manage migrations.
"ed25519" '';
]; };
default = "rsa";
description = ''
The key type used for generating DKIM keys. Ed25519 support was
introduced in RFC6376 (2018).
:::{warning} keyType = mkOption {
Ed25519 DKIM keys are currently not recommended for primary use, as type = types.enum [
various DKIM validators out there lack support and consider the keypair invalid. "rsa"
::: "ed25519"
];
default = "rsa";
description = ''
The key type used for generating DKIM keys. Ed25519 support was
introduced in RFC6376 (2018).
If you have already deployed a key with a different type than specified :::{warning}
here, then you should use a different selector ({option}`mailserver.dkimSelector`). In order to get Ed25519 DKIM keys are currently not recommended for sole use, as
this package to generate a key with the new type, you will either have to various DKIM validators out there lack support and consider the
change the selector or delete the old key file. keypair invalid.
''; :::
};
dkimKeyBits = mkOption { This value should most likely not be changed. Once DKIM keys for
type = types.int; domain and selector are generated changing this value will not
default = 2048; regenerate the keypair. Instead create a new selector and configure
description = '' {option}`mailserver.dkim.domains.<name>.selectors.<name>.keyType`.
How many bits in generated DKIM keys. RFC8301 suggests a minimum RSA key length of 2048 bit. '';
};
If you have already deployed a key with a different number of bits than specified keyLength = mkOption {
here, then you should use a different selector ({option}`mailserver.dkimSelector`). In order to get type = types.int;
this package to generate a key with the new number of bits, you will either have to default = 2048;
change the selector or delete the old key file. description = ''
''; The default key length used for generating new DKIM keys.
Only applies for RSA keys, Ed25519 keys use a fixed key length.
Per [RFC8301 3.2] the minimum RSA key length should be at least
2048 bit.
This value should most likely not be changed. Once DKIM keys for
domain and selector are generated changing this value will not
regenerate the keypair. Instead create a new selector and configure
{option}`mailserver.dkim.domains.<name>.selectors.<name>.keyLength`.
[RFC8301 3.2]: https://datatracker.ietf.org/doc/html/rfc8301#section-3.2
'';
};
};
domains = mkOption {
description = "DKIM configuration per domain.";
type = types.attrsOf (
types.submodule ({
options = {
selectors = mkOption {
description = ''
DKIM selectors used for signing outgoing mail for this domain.
When no selector is configured a default selector will be
created with settings inherited from {option}`mailserver.defaults.dkim <mailserver.dkim.defaults.keyLength>`.
'';
type = types.attrsOf (
types.submodule ({
options = {
keyType = mkOption {
type =
with types;
nullOr (enum [
"rsa"
"ed25519"
]);
default = null;
example = "rsa";
description = ''
The key type used for generating this DKIM keypair.
:::{warning}
Ed25519 DKIM keys are currently not recommended for sole use, as
various DKIM validators out there lack support and consider the
keypair invalid.
:::
This option is mutually exclusive with `keyFile`.
'';
};
keyLength = mkOption {
type = with types; nullOr int;
default = null;
example = 2048;
description = ''
The key length used for generating this DKIM key.
Only applies for RSA keys, Ed25519 keys use a fixed key size.
This option is mutually exclusive with `keyFile`.
'';
};
keyFile = mkOption {
type =
with types;
nullOr (pathWith {
inStore = false;
});
default = null;
example = "/run/keys/example.com-dkim-rsa-2026-03.key";
description = ''
Path to an existing DKIM private key file.
DKIM keys can be generated using `rspamadm dkim_keygen`.
This option is mutually exclusive with `keyType` and `keyLength`.
'';
};
};
})
);
default = { };
example = lib.literalExpression ''
{
"mail" = {
# inherit defaults from mailserver.dkim.defaults
};
"rsa-2026-03".keyFile = "/run/keys/example.com-dkim-rsa-2026-03.key";
};
'';
};
};
})
);
default = { };
example = lib.literalExpression ''
{
"example.com".selectors = {
"mail" = {
# inherit defaults from mailserver.dkim.defaults
};
"rsa-2026-03".keyFile = "/run/keys/example.com-dkim-rsa-2026-03.key";
};
};
'';
};
}; };
dmarcReporting = { dmarcReporting = {
@@ -1468,6 +1575,13 @@ in
(mkRemovedOptionModule [ "mailserver" "smtpdForbidBareNewline" ] '' (mkRemovedOptionModule [ "mailserver" "smtpdForbidBareNewline" ] ''
The workaround for the SMTP Smuggling attack is default enabled in Postfix >3.9. Use `services.postfix.config.smtpd_forbid_bare_newline` if you need to deviate from its default. The workaround for the SMTP Smuggling attack is default enabled in Postfix >3.9. Use `services.postfix.config.smtpd_forbid_bare_newline` if you need to deviate from its default.
'') '')
(mkRenamedOptionModule [ "mailserver" "dkimSigning" ] [ "mailserver" "dkim" "enable" ])
(mkRenamedOptionModule [ "mailserver" "dkimKeyDirectory" ] [ "mailserver" "dkim" "keyDirectory" ])
(mkRenamedOptionModule
[ "mailserver" "dkimSelector" ]
[ "mailserver" "dkim" "defaults" "selector" ]
)
(mkRenamedOptionModule [ "mailserver" "dkimKeyType" ] [ "mailserver" "dkim" "defaults" "keyType" ])
(mkRenamedOptionModule [ "mailserver" "dmarcReporting" "domain" ] [ "mailserver" "systemDomain" ]) (mkRenamedOptionModule [ "mailserver" "dmarcReporting" "domain" ] [ "mailserver" "systemDomain" ])
(mkRenamedOptionModule (mkRenamedOptionModule
[ "mailserver" "dmarcReporting" "organizationName" ] [ "mailserver" "dmarcReporting" "organizationName" ]
+4 -4
View File
@@ -21,7 +21,7 @@ Maildir.
To backup spam and ham training data, backup ``/var/lib/redis-rspamd``. To backup spam and ham training data, backup ``/var/lib/redis-rspamd``.
Finally you can (optionally) make a backup of ``/var/dkim`` (or whatever Finally you can (optionally) make a backup of ``/var/dkim`` (or whatever you
you specified as ``dkimKeyDirectory``). If you should lose those dont specified as :option:`mailserver.dkim.keyDirectory`). If you should lose those
worry, new ones will be created on the fly. But you will need to repeat dont worry, new ones will be created on the fly. But you will need to update
step ``B)5`` and correct all the ``dkim`` keys. the DKIM TXT records to reflect the new key material.
+201
View File
@@ -0,0 +1,201 @@
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 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
+1
View File
@@ -25,6 +25,7 @@ Welcome to NixOS Mailserver's documentation!
:maxdepth: 1 :maxdepth: 1
:caption: Features :caption: Features
dkim
fts fts
ldap ldap
srs srs
+7
View File
@@ -11,6 +11,12 @@ NixOS 26.05
:option:`mailserver.x509.privateKeyFile` instead. Support for automatic :option:`mailserver.x509.privateKeyFile` instead. Support for automatic
creation of self-signed certificates has been removed. creation of self-signed certificates has been removed.
Check the updated `setup guide`_ for a basic ACME HTTP-01 example. Check the updated `setup guide`_ for a basic ACME HTTP-01 example.
- `DKIM key management`_ is now available with multiple concurrent selectors per
domain enabling proper DKIM key rotation. While we still generate a default
key for backwards compatibility we now also support passing pre-created
key material. If your DKIM keys were automatically created before the 25.11
release they are 1024 bit RSA keys and should be rotated out.
See :option:`mailserver.dkim.domains` for further relevant options.
- Cleartext password files can now be configured for login accounts. This - Cleartext password files can now be configured for login accounts. This
is an alternative to hashed passwords that integrates well with workflows is an alternative to hashed passwords that integrates well with workflows
established by `agenix`_/`sops-nix`_ that instead rely on encryption. This established by `agenix`_/`sops-nix`_ that instead rely on encryption. This
@@ -18,6 +24,7 @@ NixOS 26.05
See :option:`mailserver.loginAccounts.<name>.passwordFile`. See :option:`mailserver.loginAccounts.<name>.passwordFile`.
.. _setup guide: setup-guide.html#setup-the-server .. _setup guide: setup-guide.html#setup-the-server
.. _DKIM key management: dkim.html
.. _agenix: https://github.com/ryantm/agenix .. _agenix: https://github.com/ryantm/agenix
.. _sops-nix: https://github.com/Mic92/sops-nix .. _sops-nix: https://github.com/Mic92/sops-nix
+14
View File
@@ -53,6 +53,20 @@ in
message = "Configure either an ACME certificate (`mailserver.x509.useACMEHost`) or pass an existing certificate (`mailserver.x509.certificateFile`, `mailserver.x509.privateKeyFile`)."; message = "Configure either an ACME certificate (`mailserver.x509.useACMEHost`) or pass an existing certificate (`mailserver.x509.certificateFile`, `mailserver.x509.privateKeyFile`).";
} }
] ]
++ lib.optionals config.mailserver.dkim.enable (
lib.flatten (
lib.mapAttrsToList (
domain: domainAttrs:
lib.mapAttrsToList (selector: selectorAttrs: [
{
assertion =
selectorAttrs.keyFile != null -> (selectorAttrs.keyType == null && selectorAttrs.keyLength == null);
message = "${domain} DKIM selector ${selector} can only use either `keyType`, `keyLength` OR `keyFile` not both.";
}
]) domainAttrs.selectors
) config.mailserver.dkim.domains
)
)
++ lib.optionals config.mailserver.ldap.enable [ ++ lib.optionals config.mailserver.ldap.enable [
{ {
assertion = config.mailserver.loginAccounts == { }; assertion = config.mailserver.loginAccounts == { };
+1 -1
View File
@@ -450,7 +450,7 @@ in
smtpd_tls_loglevel = "1"; smtpd_tls_loglevel = "1";
smtpd_milters = smtpdMilters; smtpd_milters = smtpdMilters;
non_smtpd_milters = lib.mkIf cfg.dkimSigning [ "unix:/run/rspamd/rspamd-milter.sock" ]; non_smtpd_milters = lib.mkIf cfg.dkim.enable [ "unix:/run/rspamd/rspamd-milter.sock" ];
milter_protocol = "6"; milter_protocol = "6";
milter_mail_macros = "i {mail_addr} {client_addr} {client_name} {auth_authen}"; milter_mail_macros = "i {mail_addr} {client_addr} {client_name} {auth_authen}";
}; };
+93 -22
View File
@@ -31,27 +31,80 @@ let
rspamdGroup = config.services.rspamd.group; rspamdGroup = config.services.rspamd.group;
createDkimKeypair = createDkimKeypair =
domain: {
domain,
selector,
type,
bits,
...
}:
let let
privateKey = "${cfg.dkimKeyDirectory}/${domain}.${cfg.dkimSelector}.key"; privkey = "${cfg.dkim.keyDirectory}/${domain}.${selector}.key";
publicKey = "${cfg.dkimKeyDirectory}/${domain}.${cfg.dkimSelector}.txt"; pubkey = "${cfg.dkim.keyDirectory}/${domain}.${selector}.txt";
in in
pkgs.writeShellScript "dkim-keygen-${domain}" '' pkgs.writeShellScript "dkim-keygen-${domain}-${selector}" ''
if [ ! -f "${privateKey}" ] if [ ! -f "${privkey}" ]
then then
export PATH=${lib.makeBinPath [ pkgs.openssl ]} ${lib.getExe' pkgs.rspamd "rspamadm"} dkim_keygen ${
${lib.getExe' pkgs.rspamd "rspamadm"} dkim_keygen \ lib.cli.toCommandLineShellGNU { } {
--domain "${domain}" \ inherit
--selector "${cfg.dkimSelector}" \ domain
--type "${cfg.dkimKeyType}" \ selector
--bits ${toString cfg.dkimKeyBits} \ type
--privkey "${privateKey}" > "${publicKey}" bits
chmod 0644 "${publicKey}" privkey
echo "Generated key for domain ${domain} and selector ${cfg.dkimSelector}" ;
}
} > "${pubkey}"
chmod 0644 "${pubkey}"
echo "Generated key for domain ${domain} and selector ${selector}"
fi fi
''; '';
dkimDomains = lib.unique (cfg.domains ++ (lib.optionals cfg.srs.enable [ cfg.srs.domain ])); mailDomains = lib.unique (
# primary mailserver domains
config.mailserver.domains
# all dkim domains, even extra domains specified
++ lib.attrNames cfg.dkim.domains
# and the srs domain, if one is configured
++ lib.optionals (cfg.srs.domain != null) [ cfg.srs.domain ]
);
dkimKeys = lib.concatMap (
domain:
let
configuredSelectors = config.mailserver.dkim.domains.${domain}.selectors or { };
finalSelectors =
if configuredSelectors == { } then
# synthesize default dkim key, if none configured
{
"${config.mailserver.dkim.defaults.selector}" = {
keyType = null;
keyLength = null;
keyFile = null;
};
}
else
configuredSelectors;
in
lib.mapAttrsToList (selector: settings: rec {
inherit domain selector;
keyFile = settings.keyFile;
keyPath = if keyFile != null then keyFile else "${cfg.dkim.keyDirectory}/${domain}.${selector}.key";
bits =
if settings.keyLength != null then
settings.keyLength
else
config.mailserver.dkim.defaults.keyLength;
type =
if settings.keyType != null then settings.keyType else config.mailserver.dkim.defaults.keyType;
}) finalSelectors
) mailDomains;
dkimKeysToGenerate = lib.filter (key: key.keyFile == null) dkimKeys;
dkimKeysByDomain = lib.groupBy (item: item.domain) dkimKeys;
in in
{ {
config = lib.mkIf cfg.enable { config = lib.mkIf cfg.enable {
@@ -110,13 +163,31 @@ in
}; };
"dkim_signing.conf" = { "dkim_signing.conf" = {
text = '' text = ''
enabled = ${lib.boolToString cfg.dkimSigning}; enabled = ${lib.boolToString cfg.dkim.enable};
path = "${cfg.dkimKeyDirectory}/$domain.$selector.key"; # Only sign explicitly configured domains
selector = "${cfg.dkimSelector}"; try_fallback = false;
# Allow for usernames w/o domain part # Allow for usernames w/o domain part
allow_username_mismatch = true; allow_username_mismatch = true;
# Don't normalize DKIM key selection for subdomains # Don't normalize DKIM key selection for subdomains
use_esld = false; use_esld = false;
domain {
${lib.concatStringsSep "\n\n" (
map (domain: ''
${domain} {
selectors [
${lib.concatStringsSep ",\n" (
map (selector: ''
{
path: "${selector.keyPath}";
selector: "${selector.selector}";
}'') dkimKeysByDomain.${domain}
)}
]
}
'') (lib.attrNames dkimKeysByDomain)
)}
}
''; '';
}; };
"dmarc.conf" = { "dmarc.conf" = {
@@ -183,7 +254,7 @@ in
services.redis.servers.rspamd.enable = lib.mkDefault cfg.redis.configureLocally; services.redis.servers.rspamd.enable = lib.mkDefault cfg.redis.configureLocally;
systemd.tmpfiles.settings."10-rspamd.conf" = { systemd.tmpfiles.settings."10-rspamd.conf" = {
"${cfg.dkimKeyDirectory}" = { "${cfg.dkim.keyDirectory}" = {
d = { d = {
# Create /var/dkim owned by rspamd user/group # Create /var/dkim owned by rspamd user/group
user = rspamdUser; user = rspamdUser;
@@ -204,9 +275,9 @@ in
{ {
SupplementaryGroups = [ config.services.redis.servers.rspamd.group ]; SupplementaryGroups = [ config.services.redis.servers.rspamd.group ];
} }
(lib.optionalAttrs cfg.dkimSigning { (lib.optionalAttrs cfg.dkim.enable {
ExecStartPre = map createDkimKeypair dkimDomains; ExecStartPre = map createDkimKeypair dkimKeysToGenerate;
ReadWritePaths = [ cfg.dkimKeyDirectory ]; ReadWritePaths = [ cfg.dkim.keyDirectory ];
}) })
]; ];
}; };
+2 -2
View File
@@ -66,9 +66,9 @@ in
after = [ after = [
"dovecot.service" "dovecot.service"
] ]
++ lib.optional cfg.dkimSigning "rspamd.service" ++ lib.optional cfg.dkim.enable "rspamd.service"
++ certificateDeps; ++ certificateDeps;
requires = [ "dovecot.service" ] ++ lib.optional cfg.dkimSigning "rspamd.service"; requires = [ "dovecot.service" ] ++ lib.optional cfg.dkim.enable "rspamd.service";
}; };
}; };
} }
+23 -4
View File
@@ -49,7 +49,21 @@
"example2.com" "example2.com"
]; ];
rewriteMessageId = true; rewriteMessageId = true;
dkimKeyBits = 1535; dkim = {
defaults.keyLength = 1535;
domains."example2.com".selectors = {
"dkim-rsa" = {
# rsa 1535 bits via defaults
};
"dkim-ed25519" = {
keyType = "ed25519";
keyLength = null;
};
"dkim-file" = {
keyFile = "/run/rspamd/dkim-test.key";
};
};
};
dmarcReporting.enable = true; dmarcReporting.enable = true;
loginAccounts = { loginAccounts = {
@@ -369,6 +383,9 @@
"set +e; timeout 1 nc -U /run/rspamd/rspamd-milter.sock < /dev/null; [ $? -eq 124 ]" "set +e; timeout 1 nc -U /run/rspamd/rspamd-milter.sock < /dev/null; [ $? -eq 124 ]"
) )
server.succeed("rspamadm dkim_keygen > /run/rspamd/dkim-test.key")
server.succeed("chown rspamd: /run/rspamd/dkim-test.key")
client.execute("cp -p /etc/root/.* ~/") client.execute("cp -p /etc/root/.* ~/")
client.succeed("mkdir -p ~/mail") client.succeed("mkdir -p ~/mail")
client.succeed("ls -la ~/ >&2") client.succeed("ls -la ~/ >&2")
@@ -404,10 +421,10 @@
with subtest("dkim has user-specified size"): with subtest("dkim has user-specified size"):
server.succeed( server.succeed(
"openssl rsa -in /var/dkim/example.com.mail.key -text -noout | grep 'Private-Key: (1535 bit'" "openssl rsa -in /var/dkim/example2.com.dkim-rsa.key -text -noout | grep 'Private-Key: (1535 bit'"
) )
with subtest("dkim singing, multiple domains"): with subtest("dkim signing, multiple domains"):
client.execute("rm ~/mail/*") client.execute("rm ~/mail/*")
# send email from user2 to user1 # send email from user2 to user1
client.succeed( client.succeed(
@@ -418,7 +435,9 @@
client.succeed("fetchmail --nosslcertck -v") client.succeed("fetchmail --nosslcertck -v")
client.succeed("cat ~/mail/* >&2") client.succeed("cat ~/mail/* >&2")
# make sure it is dkim signed # make sure it is dkim signed
client.succeed("grep DKIM-Signature: ~/mail/*") client.succeed("grep 's=dkim-rsa' ~/mail/*")
client.succeed("grep 's=dkim-ed25519' ~/mail/*")
client.succeed("grep 's=dkim-file' ~/mail/*")
with subtest("aliases"): with subtest("aliases"):
client.execute("rm ~/mail/*") client.execute("rm ~/mail/*")