Use OpenDKIM instead of rmilter for DKIM
As part of #61 this moves DKIM handling from rmilter to OpenDKIM.
This commit is contained in:
parent
0c883d8bcd
commit
7036371f75
6 changed files with 122 additions and 54 deletions
|
@ -733,6 +733,7 @@ in
|
|||
./mail-server/networking.nix
|
||||
./mail-server/systemd.nix
|
||||
./mail-server/dovecot.nix
|
||||
./mail-server/opendkim.nix
|
||||
./mail-server/postfix.nix
|
||||
./mail-server/rmilter.nix
|
||||
./mail-server/nginx.nix
|
||||
|
|
90
mail-server/opendkim.nix
Normal file
90
mail-server/opendkim.nix
Normal file
|
@ -0,0 +1,90 @@
|
|||
# nixos-mailserver: a simple mail server
|
||||
# Copyright (C) 2017 Brian Olsen
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
let
|
||||
cfg = config.mailserver;
|
||||
|
||||
dkimUser = config.services.opendkim.user;
|
||||
dkimGroup = config.services.opendkim.group;
|
||||
|
||||
createDomainDkimCert = dom:
|
||||
let
|
||||
dkim_key = "${cfg.dkimKeyDirectory}/${dom}.${cfg.dkimSelector}.key";
|
||||
dkim_txt = "${cfg.dkimKeyDirectory}/${dom}.${cfg.dkimSelector}.txt";
|
||||
in
|
||||
''
|
||||
if [ ! -f "${dkim_key}" ] || [ ! -f "${dkim_txt}" ]
|
||||
then
|
||||
${pkgs.opendkim}/bin/opendkim-genkey -s "${cfg.dkimSelector}" \
|
||||
-d "${dom}" \
|
||||
--directory="${cfg.dkimKeyDirectory}"
|
||||
mv "${cfg.dkimKeyDirectory}/${cfg.dkimSelector}.private" "${dkim_key}"
|
||||
mv "${cfg.dkimKeyDirectory}/${cfg.dkimSelector}.txt" "${dkim_txt}"
|
||||
echo "Generated key for domain ${dom} selector ${cfg.dkimSelector}"
|
||||
fi
|
||||
'';
|
||||
createAllCerts = lib.concatStringsSep "\n" (map createDomainDkimCert cfg.domains);
|
||||
create_dkim_cert =
|
||||
''
|
||||
# Create dkim dir
|
||||
mkdir -p "${cfg.dkimKeyDirectory}"
|
||||
chown ${dkimUser}:${dkimGroup} "${cfg.dkimKeyDirectory}"
|
||||
|
||||
${createAllCerts}
|
||||
|
||||
chown -R ${dkimUser}:${dkimGroup} "${cfg.dkimKeyDirectory}"
|
||||
'';
|
||||
|
||||
keyTable = pkgs.writeText "opendkim-KeyTable"
|
||||
(lib.concatStringsSep "\n" (lib.flip map cfg.domains
|
||||
(dom: "${dom} ${dom}:${cfg.dkimSelector}:${cfg.dkimKeyDirectory}/${dom}.${cfg.dkimSelector}.key")));
|
||||
signingTable = pkgs.writeText "opendkim-SigningTable"
|
||||
(lib.concatStringsSep "\n" (lib.flip map cfg.domains (dom: "${dom} ${dom}")));
|
||||
|
||||
dkim = config.services.opendkim;
|
||||
args = [ "-f" "-l" ] ++ lib.optionals (dkim.configFile != null) [ "-x" dkim.configFile ];
|
||||
in
|
||||
{
|
||||
config = mkIf (cfg.dkimSigning && cfg.enable) {
|
||||
services.opendkim = {
|
||||
enable = true;
|
||||
selector = cfg.dkimSelector;
|
||||
domains = "csl:${builtins.concatStringsSep "," cfg.domains}";
|
||||
configFile = pkgs.writeText "opendkim.conf" (''
|
||||
Canonicalization relaxed/simple
|
||||
UMask 0002
|
||||
Socket ${dkim.socket}
|
||||
KeyTable file:${keyTable}
|
||||
SigningTable file:${signingTable}
|
||||
'' + (lib.optionalString cfg.debug ''
|
||||
Syslog yes
|
||||
SyslogSuccess yes
|
||||
LogWhy yes
|
||||
''));
|
||||
};
|
||||
|
||||
users.users = optionalAttrs (config.services.postfix.user == "postfix") {
|
||||
postfix.extraGroups = [ "${config.services.opendkim.group}" ];
|
||||
};
|
||||
systemd.services.opendkim = {
|
||||
preStart = create_dkim_cert;
|
||||
serviceConfig.ExecStart = lib.mkForce "${pkgs.opendkim}/bin/opendkim ${escapeShellArgs args}";
|
||||
};
|
||||
};
|
||||
}
|
|
@ -90,6 +90,17 @@ let
|
|||
|
||||
/^Message-ID:\s+<(.*?)@.*?>/ REPLACE Message-ID: <$1@${cfg.fqdn}>
|
||||
'');
|
||||
|
||||
inetSocket = addr: port: "inet:[${toString port}@${addr}]";
|
||||
unixSocket = sock: "unix:${sock}";
|
||||
|
||||
rmilter = config.services.rmilter;
|
||||
rmilterSocket = if rmilter.bindSocket.type == "unix" then unixSocket rmilter.bindSocket.path
|
||||
else inetSocket rmilter.bindSocket.address rmilter.bindSocket.port;
|
||||
|
||||
smtpdMilters =
|
||||
(lib.optional cfg.dkimSigning "unix:/run/opendkim/opendkim.sock")
|
||||
++ [ rmilterSocket ];
|
||||
in
|
||||
{
|
||||
config = with cfg; lib.mkIf enable {
|
||||
|
@ -151,6 +162,11 @@ in
|
|||
|
||||
# Configure a non blocking source of randomness
|
||||
tls_random_source = dev:/dev/urandom
|
||||
|
||||
smtpd_milters = ${lib.concatStringsSep "," smtpdMilters}
|
||||
${lib.optionalString cfg.dkimSigning "non_smtpd_milters = unix:/run/opendkim/opendkim.sock"}
|
||||
milter_protocol = 6
|
||||
milter_mail_macros = i {mail_addr} {client_addr} {client_name} {auth_type} {auth_authen} {auth_author} {mail_addr} {mail_host} {mail_mailer}
|
||||
'';
|
||||
|
||||
submissionOptions =
|
||||
|
|
|
@ -27,23 +27,8 @@ let
|
|||
};
|
||||
''
|
||||
else "";
|
||||
dkim = if cfg.dkimSigning
|
||||
# Note: domain = "*"; causes Rmilter to try to search key in the key path
|
||||
# as keypath/domain.selector.key for any domain.
|
||||
then
|
||||
''
|
||||
dkim {
|
||||
domain {
|
||||
key = "${cfg.dkimKeyDirectory}";
|
||||
domain = "*";
|
||||
selector = "${cfg.dkimSelector}";
|
||||
};
|
||||
sign_alg = sha256;
|
||||
auth_only = yes;
|
||||
header_canon = relaxed;
|
||||
}
|
||||
''
|
||||
else "";
|
||||
postfixCfg = config.services.postfix;
|
||||
rmilter = config.services.rmilter;
|
||||
in
|
||||
{
|
||||
config = with cfg; lib.mkIf enable {
|
||||
|
@ -54,7 +39,6 @@ in
|
|||
services.rmilter = {
|
||||
inherit debug;
|
||||
enable = true;
|
||||
postfix.enable = true;
|
||||
rspamd = {
|
||||
enable = true;
|
||||
extraConfig = "extended_spam_headers = yes;";
|
||||
|
@ -65,10 +49,9 @@ in
|
|||
max_size = 20M;
|
||||
|
||||
${clamav}
|
||||
|
||||
${dkim}
|
||||
'';
|
||||
};
|
||||
users.extraUsers.${postfixCfg.user}.extraGroups = [ rmilter.group ];
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -19,33 +19,6 @@
|
|||
let
|
||||
cfg = config.mailserver;
|
||||
|
||||
createDomainDkimCert = dom:
|
||||
let
|
||||
dkim_key = "${cfg.dkimKeyDirectory}/${dom}.${cfg.dkimSelector}.key";
|
||||
dkim_txt = "${cfg.dkimKeyDirectory}/${dom}.${cfg.dkimSelector}.txt";
|
||||
in
|
||||
''
|
||||
if [ ! -f "${dkim_key}" ] || [ ! -f "${dkim_txt}" ]
|
||||
then
|
||||
${pkgs.opendkim}/bin/opendkim-genkey -s "${cfg.dkimSelector}" \
|
||||
-d "${dom}" \
|
||||
--directory="${cfg.dkimKeyDirectory}"
|
||||
mv "${cfg.dkimKeyDirectory}/${cfg.dkimSelector}.private" "${dkim_key}"
|
||||
mv "${cfg.dkimKeyDirectory}/${cfg.dkimSelector}.txt" "${dkim_txt}"
|
||||
fi
|
||||
'';
|
||||
createAllCerts = lib.concatStringsSep "\n" (map createDomainDkimCert cfg.domains);
|
||||
create_dkim_cert =
|
||||
''
|
||||
# Create dkim dir
|
||||
mkdir -p "${cfg.dkimKeyDirectory}"
|
||||
chown rmilter:rmilter "${cfg.dkimKeyDirectory}"
|
||||
|
||||
${createAllCerts}
|
||||
|
||||
chown -R rmilter:rmilter "${cfg.dkimKeyDirectory}"
|
||||
'';
|
||||
|
||||
createDhParameterFile = let
|
||||
dovecotVersion = builtins.fromJSON
|
||||
(builtins.readFile (pkgs.callPackage ./dovecot-version.nix {}));
|
||||
|
@ -121,19 +94,16 @@ in
|
|||
|
||||
# Postfix requires rmilter socket, dovecot lmtp socket, dovecot auth socket and certificate to work
|
||||
systemd.services.postfix = {
|
||||
after = [ "rmilter.socket" "dovecot2.service" "mailserver-certificates.target" ];
|
||||
after = [ "rmilter.socket" "dovecot2.service" "mailserver-certificates.target" ]
|
||||
++ (lib.optional cfg.dkimSigning "opendkim.service");
|
||||
wants = [ "mailserver-certificates.target" ];
|
||||
requires = [ "rmilter.socket" "dovecot2.service" ];
|
||||
requires = [ "rmilter.socket" "dovecot2.service" ]
|
||||
++ (lib.optional cfg.dkimSigning "opendkim.service");
|
||||
};
|
||||
|
||||
# Create dkim certificates
|
||||
systemd.services.rmilter = {
|
||||
requires = [ "rmilter.socket" ];
|
||||
after = [ "rmilter.socket" ];
|
||||
preStart =
|
||||
''
|
||||
${create_dkim_cert}
|
||||
'';
|
||||
};
|
||||
};
|
||||
}
|
||||
|
|
|
@ -23,6 +23,14 @@ import <nixpkgs/nixos/tests/make-test.nix> {
|
|||
../default.nix
|
||||
];
|
||||
|
||||
services.rsyslogd = {
|
||||
enable = true;
|
||||
defaultConfig = ''
|
||||
*.* /dev/console
|
||||
'';
|
||||
};
|
||||
|
||||
|
||||
mailserver = {
|
||||
enable = true;
|
||||
debug = true;
|
||||
|
|
Loading…
Reference in a new issue