summaryrefslogtreecommitdiff
path: root/sys/mta/default.nix
diff options
context:
space:
mode:
authorAlejandro Soto <alejandro@34project.org>2025-03-30 17:56:39 -0600
committerAlejandro Soto <alejandro@34project.org>2025-03-30 22:24:37 -0600
commit903e9d67ee6018380732df1e593ce85f7b36762c (patch)
tree2ed5110959e9c132e48ef14f1292af07a3681699 /sys/mta/default.nix
parentc64a88251a81fddf666106fcc1a5fdc6594b0b10 (diff)
sys/mta: implement backup MX
Diffstat (limited to 'sys/mta/default.nix')
-rw-r--r--sys/mta/default.nix188
1 files changed, 113 insertions, 75 deletions
diff --git a/sys/mta/default.nix b/sys/mta/default.nix
index 84afee5..35508e6 100644
--- a/sys/mta/default.nix
+++ b/sys/mta/default.nix
@@ -5,12 +5,25 @@ with lib; let
inherit (config.local) domains virtual users;
inherit (config.networking) domain;
+ isBackup = cfg.mode == "backup";
+ isPrimary = cfg.mode == "primary";
+
+ allDomains = optional (! virtualDomains ? ${domain}) domain ++ attrNames virtualDomains;
virtualDomains = filterAttrs (name: _: name != domain) virtual;
+
+ mdaTransport =
+ if isPrimary
+ then "lmtp:inet:${cfg.mdaAddr}:${toString cfg.lmtpPort}"
+ else "error:bad transport";
in
{
options.local.mta = {
enable = mkEnableOption "mail transfer agent";
+ mode = mkOption {
+ type = types.enum [ "primary" "backup" ];
+ };
+
mdaAddr = mkOption {
type = types.str;
};
@@ -22,6 +35,10 @@ in
lmtpPort = mkOption {
type = types.port;
};
+
+ relayListen = mkOption {
+ type = types.str;
+ };
};
config = mkIf cfg.enable {
@@ -30,7 +47,7 @@ in
filter = "postfix[mode=aggressive]";
};
- opendkim = {
+ opendkim = mkIf isPrimary {
enable = true;
group = "postfix";
@@ -45,45 +62,60 @@ in
postfix =
let
- cert = config.security.acme.certs.${domains.smtp.main}.directory;
+ cert = config.security.acme.certs.${mtaDomain.main}.directory;
+
+ mtaDomain =
+ if isPrimary
+ then domains.smtp
+ else domains.smtp-backup;
in
{
enable = true;
enableSmtp = true;
- enableSubmissions = true;
+ enableSubmissions = isPrimary;
inherit domain;
- hostname = domains.smtp.main;
+ hostname = mtaDomain.main;
+
#TODO: check_recipient_access para rechazar localhost desde afuera
- destination = [ "localhost" "$mydomain" ];
+ destination = optionals isPrimary [ "localhost" "$mydomain" ];
origin = "$mydomain";
networksStyle = "host";
+ relayHost = optionalString isBackup domains.smtp.main;
+ lookupMX = false;
+
+ relayDomains =
+ if isBackup
+ then allDomains
+ else null;
+
sslKey = "${cert}/key.pem";
sslCert = "${cert}/fullchain.pem";
# También es postmaster
rootAlias = config.local.sysadmin;
- extraAliases = concatLines
- (flatten (mapAttrsToList
+ extraAliases = optionalString isPrimary
+ (concatLines (flatten (mapAttrsToList
(name: user: map
(alias: "${alias}: ${name}")
user.hardAliases)
- users));
+ users)));
- localRecipients = map
- (user: "${user}@${domain}")
- (attrNames (users // virtual.${domain}.users));
+ localRecipients = optionals isPrimary
+ (map (user: "${user}@${domain}")
+ (attrNames (users // virtual.${domain}.users)));
- virtual = concatLines (flatten (mapAttrsToList
- (name: virtual: mapAttrsToList
- (alias: targets: "${alias}@${name} ${concatStringsSep ", " targets}")
- virtual.aliases)
- virtual));
+ virtual = optionalString isPrimary
+ (concatLines (flatten (mapAttrsToList
+ (name: virtual: mapAttrsToList
+ (alias: targets: "${alias}@${name} ${concatStringsSep ", " targets}")
+ virtual.aliases)
+ virtual)));
- mapFiles = {
+ mapFiles = optionalAttrs isPrimary {
sender_ccerts =
pkgs.writeText "postfix-sender_ccerts"
(concatLines (flatten (mapAttrsToList
@@ -118,63 +150,66 @@ in
virtual)));
};
- config =
- let
- mdaTransport = "lmtp:inet:${cfg.mdaAddr}:${toString cfg.lmtpPort}";
- in
- {
- # user+extension@domain.tld
- recipient_delimiter = "+";
-
- message_size_limit = toString (50 * 1048576);
-
- virtual_alias_maps = mkAfter [ "pcre:/etc/postfix/virtual_rules" ];
- virtual_mailbox_domains = attrNames virtualDomains;
- virtual_mailbox_maps = [ "hash:/etc/postfix/virtual_recipients" ];
-
- local_transport = mdaTransport;
- virtual_transport = mdaTransport;
-
- smtpd_sasl_type = "dovecot";
- smtpd_sasl_path = "inet:${cfg.mdaAddr}:${toString cfg.saslPort}";
- smtpd_sasl_local_domain = "$mydomain";
- smtpd_sasl_security_options = [ "noanonymous" ];
-
- smtpd_tls_auth_only = true;
- # Nota: smtpd_tls_dh1024_param_file fue deprecado en 3.9
-
- smtpd_tls_CAfile = "${config.local.pki.ca.mail.fullchain}";
- smtpd_tls_ccert_verifydepth = "1";
- tls_append_default_CA = false; # Crítico
-
- # Inventado, no es parámetro de postfix
- local_submission_client_restrictions = [
- "permit_tls_all_clientcerts"
- "permit_sasl_authenticated"
- "reject"
- ];
-
- smtpd_relay_restrictions = [
- "permit_mynetworks"
- "permit_tls_all_clientcerts"
- "permit_sasl_authenticated"
- "reject_unauth_destination"
- ];
-
- smtpd_sender_login_maps = [ "hash:/etc/postfix/sender_login" ];
-
- smtpd_sender_restrictions = [
- "check_sender_access hash:/etc/postfix/sender_ccerts"
- "reject_sender_login_mismatch"
- ];
-
- smtpd_milters = "unix:/run/opendkim/opendkim.sock";
- non_smtpd_milters = "$smtpd_milters";
- milter_default_action = "accept";
- };
+ config = {
+ # user+extension@domain.tld
+ recipient_delimiter = optionalString isPrimary "+";
+
+ message_size_limit = toString (50 * 1048576);
+
+ local_transport = mdaTransport;
+ virtual_transport = mdaTransport;
+
+ smtpd_tls_auth_only = true;
+ # Nota: smtpd_tls_dh1024_param_file fue deprecado en 3.9
+
+ tls_append_default_CA = false; # Crítico
+ } // optionalAttrs isPrimary {
+ virtual_alias_maps = mkAfter [ "pcre:/etc/postfix/virtual_rules" ];
+ virtual_mailbox_domains = attrNames virtualDomains;
+ virtual_mailbox_maps = [ "hash:/etc/postfix/virtual_recipients" ];
+
+ smtpd_sasl_type = "dovecot";
+ smtpd_sasl_path = "inet:${cfg.mdaAddr}:${toString cfg.saslPort}";
+ smtpd_sasl_local_domain = "$mydomain";
+ smtpd_sasl_security_options = [ "noanonymous" ];
+
+ smtpd_tls_CAfile = "${config.local.pki.ca.mail.fullchain}";
+ smtpd_tls_ccert_verifydepth = "1";
+
+ # Inventado, no es parámetro de postfix
+ local_submission_client_restrictions = [
+ "permit_tls_all_clientcerts"
+ "permit_sasl_authenticated"
+ "reject"
+ ];
+
+ smtpd_sender_login_maps = [ "hash:/etc/postfix/sender_login" ];
+
+ smtpd_relay_restrictions = [
+ "permit_mynetworks"
+ "permit_tls_all_clientcerts"
+ "permit_sasl_authenticated"
+ "reject_unauth_destination"
+ ];
+
+ smtpd_sender_restrictions = [
+ "check_sender_access hash:/etc/postfix/sender_ccerts"
+ "reject_sender_login_mismatch"
+ ];
+
+ smtpd_milters = "unix:/run/opendkim/opendkim.sock";
+ non_smtpd_milters = "$smtpd_milters";
+ milter_default_action = "accept";
+ } // optionalAttrs isBackup {
+ inet_interfaces = [ cfg.relayListen ];
+
+ smtpd_relay_restrictions = [
+ "reject_unauth_destination"
+ ];
+ };
# Importante: existe submissionOptions por aparte, no son iguales
- submissionsOptions = {
+ submissionsOptions = optionalAttrs isPrimary {
smtpd_client_restrictions = "$local_submission_client_restrictions";
smtpd_sasl_auth_enable = "yes";
smtpd_tls_ask_ccert = "yes";
@@ -183,15 +218,18 @@ in
};
};
- networking.firewall.allowedTCPPorts = [ 25 465 ];
+ #TODO: solo para las destination addresses necesarias
+ networking.firewall.allowedTCPPorts = optionals isPrimary [ 25 465 ];
local = {
boot.impermanence.directories = [
- { directory = "/var/lib/opendkim"; user = "opendkim"; group = "postfix"; mode = "u=rwx,g=,o="; }
{ directory = "/var/lib/postfix"; user = "root"; group = "root"; mode = "u=rwx,g=rx,o=rx"; }
+ ] ++ optionals isPrimary [
+ { directory = "/var/lib/opendkim"; user = "opendkim"; group = "postfix"; mode = "u=rwx,g=,o="; }
];
- certs.smtp.enable = true;
+ certs.smtp.enable = isPrimary;
+ certs.smtp-backup.enable = isBackup;
};
};
}