2023-09-17 09:57:55 -07:00
|
|
|
{ config, lib, pkgs, ... }:
|
|
|
|
|
|
|
|
with lib;
|
|
|
|
let
|
|
|
|
cfg = config.fudo.mail.dkim;
|
|
|
|
|
|
|
|
ensureDomainDkimCert = keyDir: domain:
|
|
|
|
let
|
2023-09-28 22:00:55 -07:00
|
|
|
dkimKey = "${keyDir}/${domain}.${cfg.selector}.key";
|
|
|
|
dkimTxt = "${keyDir}/${domain}.${cfg.selector}.txt";
|
2023-09-17 09:57:55 -07:00
|
|
|
in ''
|
|
|
|
if [ ! -f "${dkimKey}" ] || [ ! -f ${dkimTxt} ]; then
|
2023-09-28 13:00:01 -07:00
|
|
|
OUT=$(${pkgs.coreutils}/bin/mktemp -d -t dkim-XXXXXXXXXX)
|
2023-09-17 09:57:55 -07:00
|
|
|
opendkim-genkey \
|
2023-09-28 22:00:55 -07:00
|
|
|
--selector=${cfg.selector} \
|
2023-09-28 13:00:01 -07:00
|
|
|
--domain=${domain} \
|
2023-09-17 09:57:55 -07:00
|
|
|
--bits="${toString cfg.key-bits}" \
|
2023-09-28 13:00:01 -07:00
|
|
|
--directory=$OUT
|
2023-09-28 22:00:55 -07:00
|
|
|
mv $OUT/${cfg.selector}.private ${dkimKey}
|
|
|
|
mv $OUT/${cfg.selector}.txt ${dkimTxt}
|
2023-09-17 09:57:55 -07:00
|
|
|
fi
|
|
|
|
'';
|
|
|
|
|
2023-09-24 11:00:56 -07:00
|
|
|
ensureAllDkimCerts = keyDir: domains:
|
|
|
|
concatStringsSep "\n" (map (ensureDomainDkimCert keyDir) domains);
|
2023-09-17 09:57:55 -07:00
|
|
|
|
|
|
|
makeKeyTable = keyDir: domains:
|
2023-09-28 20:32:35 -07:00
|
|
|
pkgs.writeTextDir "key.table" (concatStrings (map (dom: ''
|
2023-09-28 22:00:55 -07:00
|
|
|
${dom} ${dom}:${cfg.selector}:${keyDir}/${dom}.${cfg.selector}.key
|
2023-09-28 20:32:35 -07:00
|
|
|
'') domains));
|
2023-09-17 09:57:55 -07:00
|
|
|
|
|
|
|
makeSigningTable = domains:
|
2023-09-28 20:36:48 -07:00
|
|
|
pkgs.writeTextDir "signing.table" (concatStrings (map (dom: ''
|
2023-09-28 20:32:35 -07:00
|
|
|
${dom} ${dom}
|
|
|
|
'') domains));
|
2023-09-17 09:57:55 -07:00
|
|
|
|
2023-09-28 17:00:26 -07:00
|
|
|
keyTableDir = makeKeyTable cfg.state-directory cfg.domains;
|
|
|
|
signingTableDir = makeSigningTable cfg.domains;
|
2023-09-28 14:22:47 -07:00
|
|
|
|
2023-09-17 09:57:55 -07:00
|
|
|
in {
|
|
|
|
options.fudo.mail.dkim = with types; {
|
|
|
|
enable = mkEnableOption "Enable DKIM signature verification.";
|
|
|
|
|
|
|
|
debug = mkEnableOption "Enable debug logs.";
|
|
|
|
|
|
|
|
domains = mkOption {
|
|
|
|
type = listOf str;
|
|
|
|
description =
|
|
|
|
"List of domains to be considered local, and signed instead of verified.";
|
|
|
|
};
|
|
|
|
|
2023-09-24 10:52:57 -07:00
|
|
|
selector = mkOption {
|
|
|
|
type = str;
|
|
|
|
description = "Name to use for mail-signing keys.";
|
|
|
|
default = "mail";
|
|
|
|
};
|
|
|
|
|
2023-09-24 12:07:48 -07:00
|
|
|
key-bits = mkOption {
|
|
|
|
type = int;
|
|
|
|
description = ''
|
|
|
|
How many bits in generated DKIM keys. RFC6376 advises minimum 1024-bit keys.
|
|
|
|
|
|
|
|
If you have already deployed a key with a different number of bits than specified
|
|
|
|
here, then you should use a different selector (dkimSelector). In order to get
|
|
|
|
this package to generate a key with the new number of bits, you will either have to
|
|
|
|
change the selector or delete the old key file.
|
|
|
|
'';
|
|
|
|
default = 2048;
|
|
|
|
};
|
|
|
|
|
2023-09-17 09:57:55 -07:00
|
|
|
port = mkOption {
|
|
|
|
type = port;
|
|
|
|
description = "Port at which to listen for incoming signing requests.";
|
|
|
|
default = 5324;
|
|
|
|
};
|
|
|
|
|
|
|
|
state-directory = mkOption {
|
|
|
|
type = str;
|
|
|
|
description = "Directory at which to store DKIM state (i.e. keys).";
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
config = mkIf cfg.enable {
|
2023-09-28 12:31:03 -07:00
|
|
|
networking.firewall = {
|
|
|
|
enable = true;
|
|
|
|
allowedTCPPorts = [ cfg.port ];
|
|
|
|
};
|
|
|
|
|
2023-09-17 09:57:55 -07:00
|
|
|
services.opendkim = {
|
|
|
|
enable = true;
|
2023-09-28 22:10:29 -07:00
|
|
|
selector = cfg.selector;
|
2023-09-17 09:57:55 -07:00
|
|
|
domains = let domainString = concatStringsSep "," cfg.domains;
|
2023-09-24 11:27:27 -07:00
|
|
|
in "csl:${domainString}";
|
2023-09-17 09:57:55 -07:00
|
|
|
configFile = let
|
|
|
|
debugString = ''
|
|
|
|
Syslog yes
|
|
|
|
SyslogSuccess yes
|
|
|
|
LogWhy yes
|
|
|
|
'';
|
|
|
|
in pkgs.writeText "opendkim.conf" ''
|
|
|
|
Canonicalization relaxed/simple
|
|
|
|
Socket inet:${toString cfg.port}
|
2023-09-28 22:10:29 -07:00
|
|
|
# KeyTable file:${keyTableDir}/key.table
|
|
|
|
# SigningTable file:${signingTableDir}/signing.table
|
2023-09-17 09:57:55 -07:00
|
|
|
${optionalString cfg.debug debugString}
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
|
|
|
|
systemd = {
|
|
|
|
tmpfiles.rules = let
|
|
|
|
user = config.services.opendkim.user;
|
|
|
|
group = config.services.opendkim.group;
|
|
|
|
in [ "d ${cfg.state-directory} 0700 ${user} ${group} - -" ];
|
|
|
|
services.opendkim = {
|
2023-09-27 13:01:06 -07:00
|
|
|
path = with pkgs; [ opendkim ];
|
2023-09-24 11:00:56 -07:00
|
|
|
serviceConfig = {
|
2023-09-28 22:10:29 -07:00
|
|
|
# ExecStartPre = [
|
|
|
|
# (pkgs.writeShellScript "ensure-dkim-certs.sh"
|
|
|
|
# (ensureAllDkimCerts cfg.state-directory cfg.domains))
|
|
|
|
# ];
|
2023-09-24 11:00:56 -07:00
|
|
|
ReadWritePaths = [ cfg.state-directory ];
|
2023-09-28 17:00:26 -07:00
|
|
|
ReadOnlyPaths = [ keyTableDir signingTableDir ];
|
2023-09-24 11:00:56 -07:00
|
|
|
};
|
2023-09-17 09:57:55 -07:00
|
|
|
};
|
|
|
|
};
|
|
|
|
};
|
|
|
|
}
|