From f3910436d1ade6955208c041b80bdfcdb93e65f3 Mon Sep 17 00:00:00 2001 From: Michael Lohmann Date: Tue, 15 Apr 2025 07:31:12 +0200 Subject: [PATCH 1/2] assertions: extract cfg variable With the lines much shorter it is easier to read what is actually asserted --- mail-server/assertions.nix | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/mail-server/assertions.nix b/mail-server/assertions.nix index 0e5b15b..9ef2eb8 100644 --- a/mail-server/assertions.nix +++ b/mail-server/assertions.nix @@ -1,21 +1,23 @@ { config, lib, pkgs, ... }: -{ - assertions = lib.optionals config.mailserver.ldap.enable [ +let + cfg = config.mailserver; +in { + assertions = lib.optionals cfg.ldap.enable [ { - assertion = config.mailserver.loginAccounts == {}; + assertion = cfg.loginAccounts == {}; message = "When the LDAP support is enable (mailserver.ldap.enable = true), it is not possible to define mailserver.loginAccounts"; } { - assertion = config.mailserver.extraVirtualAliases == {}; + assertion = cfg.extraVirtualAliases == {}; message = "When the LDAP support is enable (mailserver.ldap.enable = true), it is not possible to define mailserver.extraVirtualAliases"; } { - assertion = config.mailserver.forwards == {}; + assertion = cfg.forwards == {}; message = "When the LDAP support is enable (mailserver.ldap.enable = true), it is not possible to define mailserver.forwards"; } - ] ++ lib.optionals (config.mailserver.enable && config.mailserver.certificateScheme != "acme") [ + ] ++ lib.optionals (cfg.enable && cfg.certificateScheme != "acme") [ { - assertion = config.mailserver.acmeCertificateName == config.mailserver.fqdn; + assertion = cfg.acmeCertificateName == cfg.fqdn; message = "When the certificate scheme is not 'acme' (mailserver.certificateScheme != \"acme\"), it is not possible to define mailserver.acmeCertificateName"; } ]; From 0ac1140bd2cc725c20162e507eed4546134bb1be Mon Sep 17 00:00:00 2001 From: Michael Lohmann Date: Tue, 15 Apr 2025 07:20:46 +0200 Subject: [PATCH 2/2] 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" (''