mirror of
https://gitlab.com/simple-nixos-mailserver/nixos-mailserver.git
synced 2025-05-26 04:20:57 +05:00
feat: add support for DKIM private key files
This gives people an option to declaratively manage these secrets, rather than having them generated.
This commit is contained in:
parent
433520257a
commit
bb34b1bb24
@ -22,7 +22,7 @@ SNM branch corresponding to your NixOS version.
|
|||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
* [x] Continous Integration Testing
|
* [x] Continuous Integration Testing
|
||||||
* [x] Multiple Domains
|
* [x] Multiple Domains
|
||||||
* Postfix
|
* Postfix
|
||||||
* [x] SMTP on port 25
|
* [x] SMTP on port 25
|
||||||
@ -44,6 +44,7 @@ SNM branch corresponding to your NixOS version.
|
|||||||
* [x] Via ClamAV
|
* [x] Via ClamAV
|
||||||
* DKIM Signing
|
* DKIM Signing
|
||||||
* [x] Via Rspamd
|
* [x] Via Rspamd
|
||||||
|
* [x] Allow passing DKIM signing keys
|
||||||
* User Management
|
* User Management
|
||||||
* [x] Declarative user management
|
* [x] Declarative user management
|
||||||
* [x] Declarative password management
|
* [x] Declarative password management
|
||||||
@ -64,7 +65,6 @@ SNM branch corresponding to your NixOS version.
|
|||||||
* [ ] [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
|
* DKIM Signing
|
||||||
* [ ] Allow per domain selectors
|
* [ ] 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)
|
||||||
* [ ] Support [SRS](https://en.wikipedia.org/wiki/Sender_Rewriting_Scheme) with [postsrsd](https://github.com/roehling/postsrsd)
|
* [ ] Support [SRS](https://en.wikipedia.org/wiki/Sender_Rewriting_Scheme) with [postsrsd](https://github.com/roehling/postsrsd)
|
||||||
|
19
default.nix
19
default.nix
@ -794,6 +794,21 @@ in
|
|||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
dkimDomainPrivateKeyFiles = 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 {
|
dkimKeyDirectory = mkOption {
|
||||||
type = types.path;
|
type = types.path;
|
||||||
default = "/var/dkim";
|
default = "/var/dkim";
|
||||||
@ -816,8 +831,8 @@ in
|
|||||||
};
|
};
|
||||||
|
|
||||||
dkimKeyBits = mkOption {
|
dkimKeyBits = mkOption {
|
||||||
type = types.int;
|
type = types.nullOr types.int;
|
||||||
default = 1024;
|
default = if cfg.dkimDomainPrivateKeyFiles == null then 1024 else null;
|
||||||
description = ''
|
description = ''
|
||||||
How many bits in generated DKIM keys. RFC6376 advises minimum 1024-bit keys.
|
How many bits in generated DKIM keys. RFC6376 advises minimum 1024-bit keys.
|
||||||
|
|
||||||
|
@ -14,5 +14,28 @@
|
|||||||
assertion = config.mailserver.acmeCertificateName == config.mailserver.fqdn;
|
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";
|
message = "When the certificate scheme is not 'acme' (mailserver.certificateScheme != \"acme\"), it is not possible to define mailserver.acmeCertificateName";
|
||||||
}
|
}
|
||||||
|
] ++ (
|
||||||
|
let
|
||||||
|
sortedDomains = builtins.sort (a: b: a < b) config.mailserver.domains;
|
||||||
|
sortedDkimDomains = builtins.attrNames config.mailserver.dkimDomainPrivateKeyFiles;
|
||||||
|
prettyDomains = builtins.concatStringsSep ", " sortedDomains;
|
||||||
|
prettyDkimDomains = builtins.concatStringsSep ", " sortedDkimDomains;
|
||||||
|
in
|
||||||
|
lib.optionals (config.mailserver.enable && config.mailserver.dkimDomainPrivateKeyFiles != null && sortedDomains != sortedDkimDomains) [
|
||||||
|
{
|
||||||
|
assertion = config.mailserver.dkimKeyBits != null;
|
||||||
|
message = "When you bring your own DKIM private keys (mailserver.dkimDomainPrivateKeyFiles != null), the DKIM domains (${prettyDkimDomains}) must be identical to the mailserver.domains (${prettyDomains}).";
|
||||||
|
}
|
||||||
|
]
|
||||||
|
) ++ lib.optionals (config.mailserver.enable && config.mailserver.dkimDomainPrivateKeyFiles != null) [
|
||||||
|
{
|
||||||
|
assertion = config.mailserver.dkimKeyBits == null;
|
||||||
|
message = "When you bring your own DKIM private keys (mailserver.dkimDomainPrivateKeyFiles != null), you must not specify key generation options (mailserver.dkimKeyBits)";
|
||||||
|
}
|
||||||
|
] ++ lib.optionals (config.mailserver.enable && config.mailserver.dkimDomainPrivateKeyFiles == null) [
|
||||||
|
{
|
||||||
|
assertion = config.mailserver.dkimKeyBits != null;
|
||||||
|
message = "When generating DKIM private keys (mailserver.dkimDomainPrivateKeyFiles = null), you must specify key generation options (mailserver.dkimKeyBits)";
|
||||||
|
}
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
@ -26,22 +26,37 @@ let
|
|||||||
rspamdUser = config.services.rspamd.user;
|
rspamdUser = config.services.rspamd.user;
|
||||||
rspamdGroup = config.services.rspamd.group;
|
rspamdGroup = config.services.rspamd.group;
|
||||||
|
|
||||||
createDkimKeypair = domain: let
|
createOrLinkDkimCerts = domain: let
|
||||||
privateKey = "${cfg.dkimKeyDirectory}/${domain}.${cfg.dkimSelector}.key";
|
privateKey = "${cfg.dkimKeyDirectory}/${domain}.${cfg.dkimSelector}.key";
|
||||||
publicKey = "${cfg.dkimKeyDirectory}/${domain}.${cfg.dkimSelector}.txt";
|
publicKey = "${cfg.dkimKeyDirectory}/${domain}.${cfg.dkimSelector}.txt";
|
||||||
in pkgs.writeShellScript "dkim-keygen-${domain}" ''
|
in pkgs.writeShellScript "dkim-keygen-${domain}" (
|
||||||
if [ ! -f "${privateKey}" ]
|
if cfg.dkimDomainPrivateKeyFiles != null then
|
||||||
then
|
let
|
||||||
${lib.getExe' pkgs.rspamd "rspamadm"} dkim_keygen \
|
dkimPrivateKeyFile = cfg.dkimDomainPrivateKeyFiles.${domain};
|
||||||
--domain "${domain}" \
|
in
|
||||||
--selector "${cfg.dkimSelector}" \
|
''
|
||||||
--type "${cfg.dkimKeyType}" \
|
if [ ! -e "${dkimPrivateKeyFile}" ]; then
|
||||||
--bits ${toString cfg.dkimKeyBits} \
|
echo "DKIM keyfile does not exist: ${dkimPrivateKeyFile}"
|
||||||
--privkey "${privateKey}" > "${publicKey}"
|
exit 1
|
||||||
chmod 0644 "${publicKey}"
|
fi
|
||||||
echo "Generated key for domain ${domain} and selector ${cfg.dkimSelector}"
|
|
||||||
fi
|
ln -sf "${dkimPrivateKeyFile}" "${privateKey}"
|
||||||
'';
|
''
|
||||||
|
else
|
||||||
|
''
|
||||||
|
if [ ! -f "${privateKey}" ]
|
||||||
|
then
|
||||||
|
${lib.getExe' pkgs.rspamd "rspamadm"} dkim_keygen \
|
||||||
|
--domain "${domain}" \
|
||||||
|
--selector "${cfg.dkimSelector}" \
|
||||||
|
--type "${cfg.dkimKeyType}" \
|
||||||
|
--bits ${toString cfg.dkimKeyBits} \
|
||||||
|
--privkey "${privateKey}" > "${publicKey}"
|
||||||
|
chmod 0644 "${publicKey}"
|
||||||
|
echo "Generated key for domain ${domain} and selector ${cfg.dkimSelector}"
|
||||||
|
fi
|
||||||
|
''
|
||||||
|
);
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
config = with cfg; lib.mkIf enable {
|
config = with cfg; lib.mkIf enable {
|
||||||
@ -165,7 +180,7 @@ in
|
|||||||
SupplementaryGroups = [ config.services.redis.servers.rspamd.group ];
|
SupplementaryGroups = [ config.services.redis.servers.rspamd.group ];
|
||||||
}
|
}
|
||||||
(lib.optionalAttrs cfg.dkimSigning {
|
(lib.optionalAttrs cfg.dkimSigning {
|
||||||
ExecStartPre = map createDkimKeypair cfg.domains;
|
ExecStartPre = map createOrLinkDkimCerts cfg.domains;
|
||||||
ReadWritePaths = [ cfg.dkimKeyDirectory ];
|
ReadWritePaths = [ cfg.dkimKeyDirectory ];
|
||||||
})
|
})
|
||||||
];
|
];
|
||||||
|
Loading…
x
Reference in New Issue
Block a user