From 0ac1140bd2cc725c20162e507eed4546134bb1be Mon Sep 17 00:00:00 2001 From: Michael Lohmann Date: Tue, 15 Apr 2025 07:20:46 +0200 Subject: [PATCH] WIP: make DKIM selector configurable per domain --- README.md | 1 - default.nix | 11 +++++++++-- mail-server/assertions.nix | 10 +++++++++- mail-server/opendkim.nix | 17 +++++++++-------- 4 files changed, 27 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 337163b..6c3eb96 100644 --- a/README.md +++ b/README.md @@ -65,7 +65,6 @@ can stay up to date with bug fixes and updates. ### In the future * DKIM Signing - - [ ] Allow per domain selectors - [ ] Allow passing DKIM signing keys * Improve the Forwarding Experience - [ ] Support [ARC](https://en.wikipedia.org/wiki/Authenticated_Received_Chain) signing with [Rspamd](https://rspamd.com/doc/modules/arc.html) diff --git a/default.nix b/default.nix index 4008df3..3279225 100644 --- a/default.nix +++ b/default.nix @@ -787,10 +787,17 @@ in }; dkimSelector = mkOption { - type = types.str; + type = with types; let + mapStrToDomains = (selector: + builtins.listToAttrs (map (domain: { + name = domain; + value = selector; + }) cfg.domains)); + in coercedTo str mapStrToDomains (attrsOf str); default = "mail"; description = '' - The DKIM selector. + The DKIM selectors. If you provide a string, it is applied to all + domains. Otherwise you can provide it per domain. ''; }; diff --git a/mail-server/assertions.nix b/mail-server/assertions.nix index 9ef2eb8..fe74be0 100644 --- a/mail-server/assertions.nix +++ b/mail-server/assertions.nix @@ -20,5 +20,13 @@ in { assertion = cfg.acmeCertificateName == cfg.fqdn; message = "When the certificate scheme is not 'acme' (mailserver.certificateScheme != \"acme\"), it is not possible to define mailserver.acmeCertificateName"; } - ]; + ] ++ lib.optionals cfg.dkimSigning ( + let + missingDomains = builtins.filter (d: !(cfg.dkimSelector ? "${d}")) cfg.domains; + in [ + { + assertion = missingDomains == []; + message = "Missing DKIM selector for domains: ${builtins.concatStringsSep ", " missingDomains}"; + } + ]); } diff --git a/mail-server/opendkim.nix b/mail-server/opendkim.nix index cdb283c..8f759f2 100644 --- a/mail-server/opendkim.nix +++ b/mail-server/opendkim.nix @@ -25,27 +25,28 @@ let createDomainDkimCert = dom: let - dkim_key = "${cfg.dkimKeyDirectory}/${dom}.${cfg.dkimSelector}.key"; - dkim_txt = "${cfg.dkimKeyDirectory}/${dom}.${cfg.dkimSelector}.txt"; + dkim_selector = cfg.dkimSelector[dom]; + dkim_key = "${cfg.dkimKeyDirectory}/${dom}.${dkim_selector}.key"; + dkim_txt = "${cfg.dkimKeyDirectory}/${dom}.${dkim_selector}.txt"; in '' if [ ! -f "${dkim_key}" ] then - ${pkgs.opendkim}/bin/opendkim-genkey -s "${cfg.dkimSelector}" \ + ${pkgs.opendkim}/bin/opendkim-genkey -s "${dkim_selector}" \ -d "${dom}" \ --bits="${toString cfg.dkimKeyBits}" \ --directory="${cfg.dkimKeyDirectory}" - mv "${cfg.dkimKeyDirectory}/${cfg.dkimSelector}.private" "${dkim_key}" - mv "${cfg.dkimKeyDirectory}/${cfg.dkimSelector}.txt" "${dkim_txt}" + mv "${cfg.dkimKeyDirectory}/${dkim_selector}.private" "${dkim_key}" + mv "${cfg.dkimKeyDirectory}/${dkim_selector}.txt" "${dkim_txt}" chmod 644 "${dkim_txt}" - echo "Generated key for domain ${dom} selector ${cfg.dkimSelector}" + echo "Generated key for domain ${dom} selector ${dkim_selector}" fi ''; createAllCerts = lib.concatStringsSep "\n" (map createDomainDkimCert cfg.domains); keyTable = pkgs.writeText "opendkim-KeyTable" (lib.concatStringsSep "\n" (lib.flip map cfg.domains - (dom: "${dom} ${dom}:${cfg.dkimSelector}:${cfg.dkimKeyDirectory}/${dom}.${cfg.dkimSelector}.key"))); + (dom: "${dom} ${dom}:${dkim_selector}:${cfg.dkimKeyDirectory}/${dom}.${dkim_selector}.key"))); signingTable = pkgs.writeText "opendkim-SigningTable" (lib.concatStringsSep "\n" (lib.flip map cfg.domains (dom: "${dom} ${dom}"))); @@ -56,7 +57,7 @@ in config = mkIf (cfg.dkimSigning && cfg.enable) { services.opendkim = { enable = true; - selector = cfg.dkimSelector; + selector = cfg.dkimSelector; # FIXME: opendkim can only handle a single selector. Figure out how to do this… keyPath = cfg.dkimKeyDirectory; domains = "csl:${builtins.concatStringsSep "," cfg.domains}"; configFile = pkgs.writeText "opendkim.conf" (''