205 lines
6.9 KiB
Nix
205 lines
6.9 KiB
Nix
{
|
|
config,
|
|
lib,
|
|
pkgs,
|
|
...
|
|
}:
|
|
with (import ./common.nix {inherit config pkgs;}); let
|
|
cfg = config.mailsystem;
|
|
|
|
mappedFile = name: "hash:/var/lib/postfix/conf/${name}";
|
|
|
|
runtimeDir = "/run/postfix";
|
|
aliases_file = "${runtimeDir}/virtual_aliases";
|
|
virtual_domains_file = "${runtimeDir}/virtual_domains";
|
|
denied_recipients_file = "${runtimeDir}/denied_recipients";
|
|
|
|
genPostmapsScript = pkgs.writeScript "generate-postfix-postmaps" ''
|
|
#!${pkgs.stdenv.shell}
|
|
set -euo pipefail
|
|
|
|
if (! test -d "${runtimeDir}"); then
|
|
mkdir "${runtimeDir}"
|
|
chmod 755 "${runtimeDir}"
|
|
fi
|
|
|
|
${mailnixCmd} "generate-aliases" > "${aliases_file}"
|
|
${mailnixCmd} "generate-domains" > "${virtual_domains_file}"
|
|
${mailnixCmd} "generate-denied-recipients" > "${denied_recipients_file}"
|
|
'';
|
|
|
|
submission_header_cleanup_rules = pkgs.writeText "submission_header_cleanup_rules" ''
|
|
# Removes sensitive headers from mails handed in via the submission port.
|
|
# See https://thomas-leister.de/mailserver-debian-stretch/
|
|
# Uses "pcre" style regex.
|
|
|
|
/^Received:/ IGNORE
|
|
/^X-Originating-IP:/ IGNORE
|
|
/^X-Mailer:/ IGNORE
|
|
/^User-Agent:/ IGNORE
|
|
/^X-Enigmail:/ IGNORE
|
|
|
|
# Replace the user's submitted hostname with the server's FQDN to hide the
|
|
# user's host/network.
|
|
/^Message-ID:\s+<(.*?)@.*?>/ REPLACE Message-ID: <$1@${cfg.fqdn}>
|
|
'';
|
|
|
|
tls_protocols = "TLSv1.3, TLSv1.2, !TLSv1.1, !TLSv1, !SSLv2, !SSLv3";
|
|
tls_exclude_ciphers = "MD5, DES, ADH, RC4, PSD, SRP, 3DES, eNULL, aNULL";
|
|
in {
|
|
config = lib.mkIf cfg.enable {
|
|
assertions = let
|
|
isDomain = value: !lib.hasInfix "@" value;
|
|
aliasedDomains = builtins.filter isDomain (builtins.attrNames cfg.virtualAliases);
|
|
in
|
|
map (domain: {
|
|
assertion = builtins.elem domain cfg.domains;
|
|
message = "The domain to be aliased (${domain}) must be managed by the mailserver.";
|
|
})
|
|
aliasedDomains;
|
|
|
|
services.postfix = {
|
|
enable = true;
|
|
hostname = "${cfg.reverseFqdn}";
|
|
networksStyle = "host";
|
|
|
|
sslCert = sslCertPath;
|
|
sslKey = sslKeyPath;
|
|
|
|
enableSubmissions = true;
|
|
|
|
mapFiles."virtual_aliases" = aliases_file;
|
|
mapFiles."denied_recipients" = denied_recipients_file;
|
|
|
|
submissionsOptions = {
|
|
smtpd_tls_security_level = "encrypt";
|
|
smtpd_sasl_auth_enable = "yes";
|
|
smtpd_sasl_type = "dovecot";
|
|
smtpd_sasl_path = "/run/dovecot2/auth";
|
|
smtpd_sasl_security_options = "noanonymous";
|
|
smtpd_sasl_local_domain = "$myhostname";
|
|
smtpd_client_restrictions = "permit_sasl_authenticated,reject";
|
|
smtpd_sender_login_maps = mappedFile "virtual_aliases";
|
|
smtpd_sender_restrictions = "reject_sender_login_mismatch";
|
|
smtpd_recipient_restrictions = "reject_non_fqdn_recipient,reject_unknown_recipient_domain,permit_sasl_authenticated,reject";
|
|
cleanup_service_name = "submission-header-cleanup";
|
|
};
|
|
|
|
config = {
|
|
mydestination = "";
|
|
recipient_delimiter = "+";
|
|
smtpd_banner = "${cfg.fqdn} ESMTP NO UCE";
|
|
disable_vrfy_command = true;
|
|
message_size_limit = toString cfg.messageSizeLimit;
|
|
|
|
virtual_uid_maps = "static:${toString cfg.vmailUID}";
|
|
virtual_gid_maps = "static:${toString cfg.vmailUID}";
|
|
virtual_mailbox_base = cfg.mailDirectory;
|
|
virtual_mailbox_domains = virtual_domains_file;
|
|
virtual_alias_maps = [
|
|
(mappedFile "virtual_aliases")
|
|
];
|
|
virtual_mailbox_maps = [
|
|
(mappedFile "virtual_aliases")
|
|
];
|
|
virtual_transport = "lmtp:unix:/run/dovecot2/dovecot-lmtp";
|
|
# Avoid leakage of X-Original-To, X-Delivered-To headers between recipients
|
|
lmtp_destination_recipient_limit = "1";
|
|
|
|
# sasl with dovecot (enforce authentication via dovecot)
|
|
smtpd_sasl_type = "dovecot";
|
|
smtpd_sasl_path = "/run/dovecot2/auth";
|
|
smtpd_sasl_auth_enable = true;
|
|
smtpd_relay_restrictions = [
|
|
"permit_mynetworks"
|
|
"permit_sasl_authenticated"
|
|
"reject_unauth_destination"
|
|
];
|
|
smtpd_recipient_restrictions = [
|
|
"check_recipient_access ${mappedFile "denied_recipients"}"
|
|
];
|
|
|
|
# TLS settings, inspired by https://github.com/jeaye/nix-files
|
|
# Submission by mail clients is handled in submissionOptions
|
|
smtpd_tls_security_level = "may";
|
|
|
|
# Disable obsolete protocols
|
|
smtpd_tls_protocols = tls_protocols;
|
|
smtp_tls_protocols = tls_protocols;
|
|
smtpd_tls_mandatory_protocols = tls_protocols;
|
|
smtp_tls_mandatory_protocols = tls_protocols;
|
|
|
|
smtp_tls_ciphers = "high";
|
|
smtpd_tls_ciphers = "high";
|
|
smtp_tls_mandatory_ciphers = "high";
|
|
smtpd_tls_mandatory_ciphers = "high";
|
|
|
|
# Disable deprecated ciphers
|
|
smtpd_tls_mandatory_exclude_ciphers = tls_exclude_ciphers;
|
|
smtpd_tls_exclude_ciphers = tls_exclude_ciphers;
|
|
smtp_tls_mandatory_exclude_ciphers = tls_exclude_ciphers;
|
|
smtp_tls_exclude_ciphers = tls_exclude_ciphers;
|
|
|
|
tls_preempt_cipherlist = true;
|
|
|
|
# Allowing AUTH on a non-encrypted connection poses a security risk
|
|
smtpd_tls_auth_only = true;
|
|
# Log only a summary message on TLS handshake completion
|
|
smtpd_tls_loglevel = "1";
|
|
|
|
# Configure a non-blocking source of randomness
|
|
tls_random_source = "dev:/dev/urandom";
|
|
|
|
smtpd_milters = [
|
|
"unix:${rspamdProxySocket}"
|
|
];
|
|
# Also use milter for outgoing mails (for e.g., dkim)
|
|
non_smtpd_milters = [
|
|
"unix:${rspamdProxySocket}"
|
|
];
|
|
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}";
|
|
|
|
# Fix for https://www.postfix.org/smtp-smuggling.html
|
|
smtpd_forbid_bare_newline = "yes";
|
|
smtpd_forbid_bare_newline_exclusions = "$mynetworks";
|
|
};
|
|
|
|
masterConfig = {
|
|
"lmtp" = {
|
|
# Add headers when delivering, see http://www.postfix.org/smtp.8.html
|
|
# D => Delivered-To, O => X-Original-To, R => Return-Path
|
|
args = ["flags=O"];
|
|
};
|
|
"submission-header-cleanup" = {
|
|
type = "unix";
|
|
private = false;
|
|
chroot = false;
|
|
maxproc = 0;
|
|
command = "cleanup";
|
|
args = ["-o" "header_checks=pcre:${submission_header_cleanup_rules}"];
|
|
};
|
|
};
|
|
};
|
|
|
|
systemd.services.postfix-setup = {
|
|
preStart = ''
|
|
${genPostmapsScript}
|
|
'';
|
|
};
|
|
systemd.services.postfix = {
|
|
wants = sslCertService;
|
|
after =
|
|
["dovecot2.service" "rspamd.service"]
|
|
++ sslCertService;
|
|
requires = ["dovecot2.service" "rspamd.service"];
|
|
};
|
|
|
|
networking.firewall = lib.mkIf cfg.openFirewall {
|
|
allowedTCPPorts = [
|
|
25 # smtp
|
|
465 # submissions
|
|
];
|
|
};
|
|
};
|
|
}
|