fix mail on pennyworth

auto-flake-update
Yorick van Pelt 2016-09-19 20:54:40 +02:00
parent 173d32bae4
commit 4aa3e48640
4 changed files with 89 additions and 120 deletions

View File

@ -14,24 +14,8 @@ with lib;
let let
cfg = config.services.mailz; cfg = config.services.mailz;
# Convert: alldomains = lib.concatLists (mapAttrsToList (n: usr: usr.domains) cfg.users);
#
# {
# a = { aliases = [ "x", "y" ]; };
# b = { aliases = [ "x" ]; };
# }
#
# To:
#
# {
# x = [ "a" "b" ];
# y = [ "a" ];
# }
aliases = foldAttrs (user: users: [user] ++ users) [ ]
(flatten (flip mapAttrsToList cfg.users
(user: options: flip map options.aliases
(alias: { ${alias} = user; }))));
files = { files = {
credentials = pkgs.writeText "credentials" credentials = pkgs.writeText "credentials"
@ -45,20 +29,8 @@ let
(flip mapAttrsToList cfg.users (flip mapAttrsToList cfg.users
(user: options: "${user}:${options.password}:::::"))); (user: options: "${user}:${options.password}:::::")));
recipients = pkgs.writeText "recipients"
(concatStringsSep "\n"
(flip concatMap cfg.domains (domain:
(map (user: "${user}@${domain}")
(attrNames cfg.users ++ flatten ((flip mapAttrsToList) cfg.users
(user: options: options.aliases)))))));
aliases = pkgs.writeText "aliases"
(concatStringsSep "\n"
(flip mapAttrsToList aliases
(alias: users: "${alias} ${concatStringsSep "," users}")));
domains = pkgs.writeText "domains" domains = pkgs.writeText "domains"
(concatStringsSep "\n" cfg.domains); (concatStringsSep "\n" alldomains);
spamassassinSieve = pkgs.writeText "spamassassin.sieve" '' spamassassinSieve = pkgs.writeText "spamassassin.sieve" ''
require "fileinto"; require "fileinto";
@ -67,15 +39,9 @@ let
} }
''; '';
# From <https://github.com/OpenSMTPD/OpenSMTPD-extras/blob/master/extras/wip/filters/filter-regex/filter-regex.conf>
regex = pkgs.writeText "filter-regex.conf" ''
helo ! ^\[
helo ^\.
helo \.$
helo ^[^\.]*$
'';
}; };
in in
{ {
@ -119,17 +85,15 @@ in
description = "Size of the generated DKIM key."; description = "Size of the generated DKIM key.";
}; };
domains = mkOption { mainUser = mkOption {
type = types.listOf types.str; example = "root";
description = "The domains to look for"; type = types.str;
example = ["example.com"];
}; };
keydir = mkOption { keydir = mkOption {
type = types.str; type = types.str;
description = "The place to look for the ssl key"; description = "The place to look for the ssl key";
default = "${config.security.acme.directory}/${cfg.domain}"; default = "${config.security.acme.directory}/${cfg.domain}";
example = ["example.com"];
}; };
users = mkOption { users = mkOption {
@ -147,19 +111,16 @@ in
<literal>smtpctl encrypt</literal>. <literal>smtpctl encrypt</literal>.
''; '';
}; };
domains = mkOption {
aliases = mkOption {
type = types.listOf types.str; type = types.listOf types.str;
default = [ ]; example = ["example.com"];
example = [ "postmaster" ];
description = "A list of aliases for this user.";
}; };
}; };
example = { example = {
"foo" = { "foo" = {
password = "encrypted"; password = "encrypted";
aliases = [ "postmaster" ];
}; };
"bar" = { "bar" = {
password = "encrypted"; password = "encrypted";
@ -170,62 +131,69 @@ in
}; };
config = mkIf (cfg.users != { }) { config = mkIf (cfg.users != { }) {
nixpkgs.config.packageOverrides = pkgs: {
# opensmtpd = overrideDerivation pkgs.opensmtpd (oldAttrs: {
# # Needed to listen on both IPv4 and IPv6
# patches = oldAttrs.patches ++ [ ./opensmtpd.diff ];
# });
opensmtpd-extras = pkgs.opensmtpd-extras.override {
# Needed to have PRNG working in chroot (for dkim-signer)
openssl = pkgs.libressl;
};
};
system.activationScripts.mailz = '' system.activationScripts.mailz = ''
# Make sure SpamAssassin database is present # Make sure SpamAssassin database is present
if ! [ -d /etc/spamassassin ]; then #if ! [ -d /etc/spamassassin ]; then
cp -r ${pkgs.spamassassin}/share/spamassassin /etc # cp -r ${pkgs.spamassassin}/share/spamassassin /etc
fi #fi
# Make sure a DKIM private key exist # Make sure a DKIM private key exist
if ! [ -d ${cfg.dkimDirectory}/${head cfg.domains} ]; then if ! [ -d ${cfg.dkimDirectory} ]; then
mkdir -p ${cfg.dkimDirectory}/${head cfg.domains} mkdir -p ${cfg.dkimDirectory}
chmod 700 ${cfg.dkimDirectory}/${head cfg.domains} chmod 700 ${cfg.dkimDirectory}
${pkgs.opendkim}/bin/opendkim-genkey --bits ${toString cfg.dkimBits} --domain ${head cfg.domains} --directory ${cfg.dkimDirectory}/${head cfg.domains} chown ${config.services.rmilter.user} ${cfg.dkimDirectory}
fi fi
''; # Generate missing keys
'' +
services.spamassassin.enable = true; (lib.concatMapStringsSep "\n" (domain: ''
# it turns out that the dkim header domain does not have to match the from address if ! [ -e ${cfg.dkimDirectory}/${domain}.default.key ]; then
# but it would be a nice-to-have ${pkgs.opendkim}/bin/opendkim-genkey --bits ${toString cfg.dkimBits} --domain ${domain} --directory ${cfg.dkimDirectory} --selector default
services.opensmtpd = { mv ${cfg.dkimDirectory}/default.private ${cfg.dkimDirectory}/${domain}.default.key
mv ${cfg.dkimDirectory}/default.txt ${cfg.dkimDirectory}/${domain}.default.txt
chown ${config.services.rmilter.user} ${cfg.dkimDirectory}/${domain}.default.*
fi
'') alldomains);
services.rspamd.enable = true;
services.rmilter = {
enable = true; enable = true;
serverConfiguration = '' socketActivation = false;
filter filter-pause pause #debug = true;
filter filter-regex regex "${files.regex}" rspamd.enable = true;
filter filter-spamassassin spamassassin "-saccept" postfix.enable = true;
filter filter-dkim-signer dkim-signer "-d${head cfg.domains}" "-p${cfg.dkimDirectory}/${head cfg.domains}/default.private" extraConfig = ''
filter in chain filter-pause filter-regex filter-spamassassin dkim {
filter out chain filter-dkim-signer domain {
key = ${cfg.dkimDirectory};
pki ${cfg.domain} certificate "${cfg.keydir}/fullchain.pem" domain = "*";
pki ${cfg.domain} key "${cfg.keydir}/key.pem" selector = "default";
};
table credentials file:${files.credentials} header_canon = relaxed;
table recipients file:${files.recipients} body_canon = relaxed;
table aliases file:${files.aliases} sign_alg = sha256;
table domains file:${files.domains} };
listen on 0.0.0.0 port 25 hostname ${cfg.domain} filter in tls pki ${cfg.domain}
#listen on :: port 25 hostname ${cfg.domain} filter in tls pki ${cfg.domain}
listen on 0.0.0.0 port 587 hostname ${cfg.domain} filter out tls-require pki ${cfg.domain} auth <credentials>
#listen on :: port 587 hostname ${cfg.domain} filter out tls-require pki ${cfg.domain} auth <credentials>
enqueuer filter out
accept from any for domain <domains> recipient <recipients> alias <aliases> deliver to lmtp localhost:24
accept from local for any relay
''; '';
procPackages = [ pkgs.opensmtpd-extras ]; };
services.postfix = {
enable = true;
destination = alldomains ++ ["$myhostname" "localhost.$mydomain" "$mydomain" "localhost"];
sslCert = "${cfg.keydir}/fullchain.pem";
sslKey = "${cfg.keydir}/key.pem";
postmasterAlias = cfg.mainUser;
enableSubmission = true;
virtual = lib.concatStringsSep "\n" (lib.mapAttrsToList (name: usr:
lib.concatMapStringsSep "\n" (dom: "@${dom} ${name}") usr.domains) cfg.users);
extraConfig = ''
mailbox_transport = lmtp:unix:dovecot-lmtp
'';
submissionOptions = {
"smtpd_tls_security_level" = "encrypt";
"smtpd_sasl_auth_enable" = "yes";
"smtpd_sasl_type" = "dovecot";
"smtpd_sasl_path" = "/var/lib/postfix/auth";
"smtpd_client_restrictions" = "permit_sasl_authenticated,reject";
#"milter_macro_daemon_name" = "ORIGINATING";
};
}; };
services.dovecot2 = { services.dovecot2 = {
@ -241,12 +209,21 @@ in
enablePAM = false; enablePAM = false;
sieveScripts = { before = files.spamassassinSieve; }; sieveScripts = { before = files.spamassassinSieve; };
extraConfig = '' extraConfig = ''
postmaster_address = postmaster@${head cfg.domains} postmaster_address = postmaster@${head alldomains}
service lmtp { service lmtp {
inet_listener lmtp { unix_listener /var/lib/postfix/queue/dovecot-lmtp {
address = 127.0.0.1 ::1 mode = 0660
port = 24 user = postfix
group = postfix
}
}
service auth {
unix_listener /var/lib/postfix/auth {
mode = 0660
# Assuming the default Postfix user and group
user = postfix
group = postfix
} }
} }

View File

@ -156,6 +156,7 @@ in
mkdir -p /etc/nginx/ mkdir -p /etc/nginx/
${pkgs.openssl}/bin/openssl dhparam -out /etc/nginx/dhparam.pem 2048 ${pkgs.openssl}/bin/openssl dhparam -out /etc/nginx/dhparam.pem 2048
fi fi
# self-sign certs in case an invalid vhost is looked up
dir=${cfg.no_vhost_keydir} dir=${cfg.no_vhost_keydir}
mkdir -m 0700 -p $dir mkdir -m 0700 -p $dir
if ! [[ -e $dir/key.pem ]]; then if ! [[ -e $dir/key.pem ]]; then

View File

@ -23,6 +23,8 @@ in
networking.hostName = secrets.hostnames.pennyworth; networking.hostName = secrets.hostnames.pennyworth;
services.nixosManual.enable = false;
environment.noXlibs = true; environment.noXlibs = true;
services.openssh.enable = true; services.openssh.enable = true;
@ -37,15 +39,14 @@ in
services.mailz = { services.mailz = {
domain = config.networking.hostName; domain = config.networking.hostName;
keydir = acmeKeyDir; keydir = acmeKeyDir;
domains = secrets.email_domains; mainUser = "yorick";
users = { users = {
yorick = { yorick = with secrets; {
password = secrets.yorick_mailPassword; password = yorick_mailPassword;
aliases = ["postmaster" "me" "ik" "info" "~"]; domains = email_domains;
}; };
}; };
}; };
# website + lets encrypt challenge hosting # website + lets encrypt challenge hosting
nginxssl = { nginxssl = {
enable = true; enable = true;
@ -63,6 +64,7 @@ in
# Let's Encrypt configuration. # Let's Encrypt configuration.
security.acme.preliminarySelfsigned = true;
security.acme.certs."yori.cc" = security.acme.certs."yori.cc" =
{ email = secrets.email; { email = secrets.email;
extraDomains = { extraDomains = {
@ -73,19 +75,6 @@ in
systemctl restart prosody.service systemctl restart prosody.service
''; '';
}; };
# Generate a dummy self-signed certificate until we get one from
# Let's Encrypt.
system.activationScripts.letsEncryptKeys =
''
dir=${acmeKeyDir}
mkdir -m 0700 -p $dir
if ! [[ -e $dir/key.pem ]]; then
${pkgs.openssl}/bin/openssl genrsa -passout pass:foo -des3 -out $dir/key-in.pem 1024
${pkgs.openssl}/bin/openssl req -passin pass:foo -new -key $dir/key-in.pem -out $dir/key.csr \
-subj "/C=NL/CN=www.example.com"
${pkgs.openssl}/bin/openssl rsa -passin pass:foo -in $dir/key-in.pem -out $dir/key.pem
${pkgs.openssl}/bin/openssl x509 -req -days 365 -in $dir/key.csr -signkey $dir/key.pem -out $dir/fullchain.pem
fi
''; '';
# hidden SSH service # hidden SSH service

View File

@ -21,9 +21,11 @@ in
path = "/old-root/boot"; path = "/old-root/boot";
devices = ["nodev"]; devices = ["nodev"];
}]; }];
splashImage = null;
}; };
initrd.availableKernelModules = [ "xen_blkfront" ]; initrd.availableKernelModules = [ "xen_blkfront" ];
}; };
sound.enable = false;
networking = { networking = {
usePredictableInterfaceNames = false; # only eth0 usePredictableInterfaceNames = false; # only eth0
interfaces.eth0 = { interfaces.eth0 = {