diff --git a/default.nix b/default.nix index 60dbceb..b187868 100644 --- a/default.nix +++ b/default.nix @@ -794,6 +794,21 @@ in ''; }; + dkimPrivateKeyFiles = mkOption { + type = types.nullOr (types.attrsOf types.path); + default = null; + example = { + "mail.example.com" = "/run/secrets/dkim/mail.example.com.mail.key"; + }; + description = '' + Paths to opendkim private keys generated with `opendkim-genkey`, + indexed by domain name. + If `null`, then the keys are auto generated. + If set, then there must be an entry for every domain in + {option}`config.mailserver.domains`. + ''; + }; + dkimKeyDirectory = mkOption { type = types.path; default = "/var/dkim"; @@ -803,8 +818,8 @@ in }; dkimKeyBits = mkOption { - type = types.int; - default = 1024; + type = types.nullOr types.int; + default = if cfg.dkimPrivateKeyFiles == null then 1024 else null; description = '' How many bits in generated DKIM keys. RFC6376 advises minimum 1024-bit keys. diff --git a/mail-server/assertions.nix b/mail-server/assertions.nix index 0e5b15b..f4b6633 100644 --- a/mail-server/assertions.nix +++ b/mail-server/assertions.nix @@ -1,4 +1,4 @@ -{ config, lib, pkgs, ... }: +{ config, lib, ... }: { assertions = lib.optionals config.mailserver.ldap.enable [ { @@ -18,5 +18,15 @@ assertion = config.mailserver.acmeCertificateName == config.mailserver.fqdn; message = "When the certificate scheme is not 'acme' (mailserver.certificateScheme != \"acme\"), it is not possible to define mailserver.acmeCertificateName"; } + ] ++ lib.optionals (config.mailserver.enable && config.mailserver.dkimPrivateKeyFiles != null) [ + { + assertion = config.mailserver.dkimKeyBits == null; + message = "When you bring your own DKIM private keys (mailserver.dkimPrivateKeyFiles != null), you must not specify key generation options (mailserver.dkimKeyBits)"; + } + ] ++ lib.optionals (config.mailserver.enable && config.mailserver.dkimPrivateKeyFiles == null) [ + { + assertion = config.mailserver.dkimKeyBits != null; + message = "When generating DKIM private keys (mailserver.dkimPrivateKeyFiles = null), you must specify key generation options (mailserver.dkimKeyBits)"; + } ]; } diff --git a/mail-server/opendkim.nix b/mail-server/opendkim.nix index cdb283c..2899b66 100644 --- a/mail-server/opendkim.nix +++ b/mail-server/opendkim.nix @@ -23,14 +23,24 @@ let dkimUser = config.services.opendkim.user; dkimGroup = config.services.opendkim.group; - createDomainDkimCert = dom: + createOrLinkDkimCerts = dom: let dkim_key = "${cfg.dkimKeyDirectory}/${dom}.${cfg.dkimSelector}.key"; dkim_txt = "${cfg.dkimKeyDirectory}/${dom}.${cfg.dkimSelector}.txt"; + dkimPrivateKeyFile = cfg.dkimPrivateKeyFiles.${dom}; in + if cfg.dkimPrivateKeyFiles != null then '' - if [ ! -f "${dkim_key}" ] - then + if [ ! -e "${dkimPrivateKeyFile}" ]; then + echo "DKIM keyfile does not exist: ${dkimPrivateKeyFile}" + exit 1 + fi + + ln -sf "${dkimPrivateKeyFile}" "${dkim_key}" + '' + else + '' + if [ ! -e "${dkim_key}" ]; then ${pkgs.opendkim}/bin/opendkim-genkey -s "${cfg.dkimSelector}" \ -d "${dom}" \ --bits="${toString cfg.dkimKeyBits}" \ @@ -41,7 +51,7 @@ let echo "Generated key for domain ${dom} selector ${cfg.dkimSelector}" fi ''; - createAllCerts = lib.concatStringsSep "\n" (map createDomainDkimCert cfg.domains); + createOrLinkAllCerts = lib.concatStringsSep "\n" (map createOrLinkDkimCerts cfg.domains); keyTable = pkgs.writeText "opendkim-KeyTable" (lib.concatStringsSep "\n" (lib.flip map cfg.domains @@ -76,7 +86,7 @@ in postfix.extraGroups = [ "${dkimGroup}" ]; }; systemd.services.opendkim = { - preStart = lib.mkForce createAllCerts; + preStart = lib.mkForce createOrLinkAllCerts; serviceConfig = { ExecStart = lib.mkForce "${pkgs.opendkim}/bin/opendkim ${escapeShellArgs args}"; PermissionsStartOnly = lib.mkForce false;