nixfiles/hosts/hetzner-vm/containers/mail/modules/mailserver/postfix.nix

205 lines
7 KiB
Nix
Raw Normal View History

{
config,
pkgs,
lib,
...
}: let
2023-09-18 03:56:58 +01:00
inherit (lib.modules) mkIf;
inherit (lib.strings) concatStringsSep;
inherit (lib.lists) flatten optional;
inherit (lib.attrsets) mapAttrsToList;
inherit (builtins) toFile;
mailConfig = config.services.mailserver;
2022-11-17 12:06:16 +00:00
tls_allowed = "TLSv1.3, TLSv1.2, TLSv1.1, !TLSv1, !SSLv2, !SSLv3";
tls_disallow = "MD5, DES, ADH, RC4, PSD, SRP, 3DES, eNULL, aNULL";
2023-09-18 03:56:58 +01:00
sendingReceivingAliases = concatStringsSep "\n" (flatten [
(mapAttrsToList (email: config:
map (
alias: "${alias} ${email} "
)
config.aliases)
mailConfig.accounts)
(mapAttrsToList (email: _config: [
# i dont know if this is actually needed
"${email} ${email}"
])
mailConfig.accounts)
]);
sendingReceivingAliasesMappedName = "sending_receiving_aliases";
sendingReceivingAliasesFile = toFile "${sendingReceivingAliasesMappedName}" sendingReceivingAliases;
extraAliasesCombinedFilePath = "/run/postfix_sending_receiving_aliases";
2022-11-17 12:06:16 +00:00
in {
2023-09-18 03:56:58 +01:00
config = mkIf (mailConfig.enable) {
systemd.tmpfiles.rules = mkIf (mailConfig.extraAliasesFile != null) [
"f ${extraAliasesCombinedFilePath} 660 root root"
];
2023-09-18 03:56:58 +01:00
systemd.services.postfix-extra-aliases-setup = mkIf (mailConfig.extraAliasesFile != null) {
wantedBy = ["multi-user.target"];
partOf = ["postfix.service"];
before = ["postfix-setup.service"];
script = ''
2023-09-18 03:56:58 +01:00
cat "${sendingReceivingAliasesFile}" > ${extraAliasesCombinedFilePath}
echo >> ${extraAliasesCombinedFilePath}
cat "${mailConfig.extraAliasesFile}" >> ${extraAliasesCombinedFilePath}
'';
};
2023-09-18 03:56:58 +01:00
services.postfix = let
mappedFile = name: "hash:/var/lib/postfix/conf/${name}";
sendingReceivingAliasesMappedFile = mappedFile sendingReceivingAliasesMappedName;
submissionOptions = {
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 = sendingReceivingAliasesMappedFile;
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";
};
in {
2022-11-17 12:06:16 +00:00
enable = true;
2023-09-18 03:56:58 +01:00
hostname = "${mailConfig.fqdn}";
2022-11-17 12:06:16 +00:00
networksStyle = "host";
2023-09-18 03:56:58 +01:00
mapFiles = {
"sending_receiving_aliases" =
if (mailConfig.extraAliasesFile == null)
then sendingReceivingAliasesFile
else "${extraAliasesCombinedFilePath}";
};
2022-11-17 12:06:16 +00:00
enableSubmission = true;
enableSubmissions = true;
2023-09-18 03:56:58 +01:00
sslCert = mailConfig.sslConfig.cert;
sslKey = mailConfig.sslConfig.key;
2022-11-17 12:06:16 +00:00
config = {
# Extra Config
mydestination = "";
recipient_delimiter = "+";
2023-09-18 03:56:58 +01:00
smtpd_banner = "${mailConfig.fqdn} ESMTP NO UCE";
2022-11-17 12:06:16 +00:00
disable_vrfy_command = true;
message_size_limit = "20971520";
2023-09-18 03:56:58 +01:00
virtual_uid_maps = "static:${toString mailConfig.vmail.userID}";
virtual_gid_maps = "static:${toString mailConfig.vmail.groupID}";
virtual_mailbox_base = "${mailConfig.vmail.directory}";
virtual_mailbox_domains = toFile "vhosts" (concatStringsSep "\n" mailConfig.domains);
virtual_mailbox_maps = sendingReceivingAliasesMappedFile;
virtual_alias_maps = sendingReceivingAliasesMappedFile;
2022-11-17 12:06:16 +00:00
virtual_transport = "lmtp:unix:/run/dovecot2/dovecot-lmtp";
lmtp_destination_recipient_limit = "1";
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"
];
2023-09-18 03:56:58 +01:00
policy-spf_time_limit = mkIf (mailConfig.spf.enable) "3600s";
2022-11-17 12:06:16 +00:00
2023-09-18 03:56:58 +01:00
smtpd_recipient_restrictions = flatten [
(optional mailConfig.spf.enable "check_policy_service unix:private/policy-spf")
2022-11-17 12:06:16 +00:00
];
smtpd_tls_security_level = "may";
smtpd_tls_eecdh_grade = "ultra";
# Only Alow Modern TLS
smtp_tls_protocols = tls_allowed;
smtpd_tls_protocols = tls_allowed;
smtp_tls_mandatory_protocols = tls_allowed;
smtpd_tls_mandatory_protocols = tls_allowed;
# Disable Old Ciphers
smtp_tls_exclude_ciphers = tls_disallow;
smtpd_tls_exclude_ciphers = tls_disallow;
smtp_tls_mandatory_exclude_ciphers = tls_disallow;
smtpd_tls_mandatory_exclude_ciphers = tls_disallow;
smtp_tls_ciphers = "high";
smtpd_tls_ciphers = "high";
smtp_tls_mandatory_ciphers = "high";
smtpd_tls_mandatory_ciphers = "high";
tls_preempt_cipherlist = true;
smtpd_tls_auth_only = true;
smtpd_tls_loglevel = "1";
tls_random_source = "dev:/dev/urandom";
milter_default_action = "quarantine";
2023-09-18 03:56:58 +01:00
smtpd_milters = flatten [
(optional mailConfig.dkim.enable "unix:/run/opendkim/opendkim.sock")
(optional mailConfig.rspamd.enable "unix:/run/rspamd/rspamd-milter.sock")
];
non_smtpd_milters = flatten [
(optional mailConfig.dkim.enable "unix:/run/opendkim/opendkim.sock")
2022-11-17 12:06:16 +00:00
];
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}";
2022-11-17 12:06:16 +00:00
};
submissionOptions = submissionOptions;
submissionsOptions = submissionOptions;
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"];
2022-11-17 12:06:16 +00:00
};
2023-09-18 03:56:58 +01:00
"policy-spf" = mkIf (mailConfig.spf.enable) {
2022-11-17 12:06:16 +00:00
type = "unix";
privileged = true;
chroot = false;
command = "spawn";
2023-09-18 03:56:58 +01:00
args = let
policydConfig = toFile "policyd-spf.conf" mailConfig.spf.policydConfig;
in [
2022-11-17 12:06:16 +00:00
"user=nobody"
"argv=${pkgs.pypolicyd-spf}/bin/policyd-spf"
2023-09-18 03:56:58 +01:00
"${policydConfig}"
2022-11-17 12:06:16 +00:00
];
};
"submission-header-cleanup" = {
type = "unix";
private = false;
chroot = false;
maxproc = 0;
command = "cleanup";
2023-09-18 03:56:58 +01:00
args = let
submissionHeaderCleanupRules = toFile "submission_header_cleanup_rules" ''
/^Received:/ IGNORE
/^X-Originating-IP:/ IGNORE
/^X-Mailer:/ IGNORE
/^User-Agent:/ IGNORE
/^X-Enigmail:/ IGNORE
/^Message-ID:\s+<(.*?)@.*?>/ REPLACE Message-ID: <$1@${mailConfig.fqdn}>
'';
in ["-o" "header_checks=pcre:${submissionHeaderCleanupRules}"];
2022-11-17 12:06:16 +00:00
};
};
};
};
2022-11-17 12:06:16 +00:00
}