X-Git-Url: https://git.immae.eu/?a=blobdiff_plain;f=modules%2Fprivate%2Fmail%2Fpostfix.nix;h=7e06c452c9ca2f6e87e2832cb78ede804cfc8a56;hb=6596ce997908aab8daaae635229e5031c83fd57c;hp=46d45c188cbc549f1199897fcc5d670147923ed2;hpb=418a4ed7da43fab53c18f99237bc296e37f47d2c;p=perso%2FImmae%2FConfig%2FNix.git diff --git a/modules/private/mail/postfix.nix b/modules/private/mail/postfix.nix index 46d45c1..7e06c45 100644 --- a/modules/private/mail/postfix.nix +++ b/modules/private/mail/postfix.nix @@ -1,12 +1,41 @@ { lib, pkgs, config, nodes, ... }: +let all_domains = config.myEnv.mail.postfix.additional_mailbox_domains + ++ lib.remove null (lib.flatten (map + (zone: map + (e: if e.receive + then "${e.domain}${lib.optionalString (e.domain != "") "."}${zone.name}" + else null + ) + (zone.withEmail or []) + ) + config.myEnv.dns.masterZones + )); +in { config = lib.mkIf config.myServices.mail.enable { - services.duplyBackup.profiles.mail.excludeFile = '' - + /var/lib/postfix - ''; - secrets.keys = [ - { - dest = "postfix/mysql_alias_maps"; + myServices.chatonsProperties.hostings.mx-backup = { + file.datetime = "2022-08-22T01:00:00"; + hosting = { + name = "MX Backup"; + description = "Serveur e-mail secondaire"; + logo = "https://www.postfix.org/favicon.ico"; + website = "https://mail.immae.eu/"; + status.level = "OK"; + status.description = "OK"; + registration.load = "OPEN"; + install.type = "PACKAGE"; + }; + software = { + name = "Postfix"; + website = "http://www.postfix.org/"; + license.url = "http://postfix.mirrors.ovh.net/postfix-release/LICENSE"; + license.name = "Eclipse Public license (EPL 2.0) and IBM Public License (IPL 1.0)"; + version = pkgs.postfix.version; + source.url = "http://www.postfix.org/download.html"; + }; + }; + secrets.keys = { + "postfix/mysql_alias_maps" = { user = config.services.postfix.user; group = config.services.postfix.group; permissions = "0440"; @@ -32,36 +61,23 @@ FROM forwardings_blacklisted WHERE source = '%s' ''; - } - { - dest = "postfix/mysql_mailbox_maps"; + }; + "postfix/ldap_mailboxes" = { user = config.services.postfix.user; group = config.services.postfix.group; permissions = "0440"; text = '' - # We need to specify that option to trigger ssl connection - tls_ciphers = TLSv1.2 - user = ${config.myEnv.mail.postfix.mysql.user} - password = ${config.myEnv.mail.postfix.mysql.password} - hosts = unix:${config.myEnv.mail.postfix.mysql.socket} - dbname = ${config.myEnv.mail.postfix.mysql.database} - result_format = /%d/%u - query = SELECT DISTINCT '%s' - FROM mailboxes - WHERE active = 1 - AND ( - (domain = '%d' AND user = '%u' AND regex = 0) - OR ( - regex = 1 - AND '%d' REGEXP CONCAT('^',domain,'$') - AND '%u' REGEXP CONCAT('^',user,'$') - ) - ) - LIMIT 1 + server_host = ldaps://${config.myEnv.mail.dovecot.ldap.host}:636 + search_base = ${config.myEnv.mail.dovecot.ldap.base} + query_filter = ${config.myEnv.mail.dovecot.ldap.postfix_mailbox_filter} + bind_dn = ${config.myEnv.mail.dovecot.ldap.dn} + bind_pw = ${config.myEnv.mail.dovecot.ldap.password} + result_attribute = immaePostfixAddress + result_format = dummy + version = 3 ''; - } - { - dest = "postfix/mysql_sender_login_maps"; + }; + "postfix/mysql_sender_login_maps" = { user = config.services.postfix.user; group = config.services.postfix.group; permissions = "0440"; @@ -83,9 +99,8 @@ AND active = 1 UNION SELECT CONCAT(SUBSTRING_INDEX('%u', '+', 1), '@%d') AS destination ''; - } - { - dest = "postfix/mysql_sender_relays_maps"; + }; + "postfix/mysql_sender_relays_maps" = { user = config.services.postfix.user; group = config.services.postfix.group; permissions = "0440"; @@ -113,9 +128,8 @@ ((regex = 1 AND '%s' REGEXP CONCAT('^',`from`,'$') ) OR (regex = 0 AND `from` = '%s')) AND active = 1 ''; - } - { - dest = "postfix/mysql_sender_relays_hosts"; + }; + "postfix/mysql_sender_relays_hosts" = { user = config.services.postfix.user; group = config.services.postfix.group; permissions = "0440"; @@ -133,9 +147,8 @@ ((regex = 1 AND '%s' REGEXP CONCAT('^',`from`,'$') ) OR (regex = 0 AND `from` = '%s')) AND active = 1 ''; - } - { - dest = "postfix/mysql_sender_relays_creds"; + }; + "postfix/mysql_sender_relays_creds" = { user = config.services.postfix.user; group = config.services.postfix.group; permissions = "0440"; @@ -153,9 +166,8 @@ ((regex = 1 AND '%s' REGEXP CONCAT('^',`from`,'$') ) OR (regex = 0 AND `from` = '%s')) AND active = 1 ''; - } - { - dest = "postfix/ldap_ejabberd_users_immae_fr"; + }; + "postfix/ldap_ejabberd_users_immae_fr" = { user = config.services.postfix.user; group = config.services.postfix.group; permissions = "0440"; @@ -170,17 +182,27 @@ result_format = ejabberd@localhost version = 3 ''; - } - ]; + }; + } // lib.mapAttrs' (name: v: lib.nameValuePair "postfix/scripts/${name}-env" { + user = "postfixscripts"; + group = "root"; + permissions = "0400"; + text = builtins.toJSON v.env; + }) config.myEnv.mail.scripts; networking.firewall.allowedTCPPorts = [ 25 465 587 ]; + users.users.postfixscripts = { + group = "keys"; + uid = config.ids.uids.postfixscripts; + description = "Postfix scripts user"; + }; users.users."${config.services.postfix.user}".extraGroups = [ "keys" ]; services.filesWatcher.postfix = { restart = true; paths = [ config.secrets.fullPaths."postfix/mysql_alias_maps" - config.secrets.fullPaths."postfix/mysql_mailbox_maps" + config.secrets.fullPaths."postfix/ldap_mailboxes" config.secrets.fullPaths."postfix/mysql_sender_login_maps" config.secrets.fullPaths."postfix/ldap_ejabberd_users_immae_fr" ]; @@ -220,7 +242,12 @@ fi ''; scripts = lib.attrsets.mapAttrs (n: v: - toScript n (pkgs.callPackage (builtins.fetchGit { url = v.src.url; ref = "master"; rev = v.src.rev; }) { scriptEnv = v.env; }) + toScript n ( + (builtins.getFlake "git+${v.src.url}?rev=${v.src.rev}" + #(builtins.fetchGit { url = v.src.url; ref = "master"; rev = v.src.rev; }) + ).outputs.envToScript.x86_64-linux + config.secrets.fullPaths."postfix/scripts/${n}-env" + ) ) config.myEnv.mail.scripts // { testmail = pkgs.writeScript "testmail" '' #! ${pkgs.stdenv.shell} @@ -256,26 +283,42 @@ virtual = let cfg = config.myEnv.monitoring.email_check.eldiron; address = "${cfg.mail_address}@${cfg.mail_domain}"; + aliases = config.myEnv.mail.postfix.common_aliases; + admins = builtins.concatStringsSep "," config.myEnv.mail.postfix.admins; in pkgs.writeText "postfix-virtual" ( builtins.concatStringsSep "\n" ( - ["${address} testmail@localhost"] ++ + [ "${address} testmail@localhost" + ] ++ + map (a: "${a} ${admins}") config.myEnv.mail.postfix.other_aliases ++ lib.attrsets.mapAttrsToList ( n: v: lib.optionalString v.external '' script_${n}@mail.immae.eu ${n}@localhost, scripts@mail.immae.eu '' ) config.myEnv.mail.scripts - ) - ); + ++ lib.lists.flatten ( + map (domain: + map (alias: "${alias}@${domain} ${admins}") aliases + ) all_domains + ) + )); }; sasl_access = { host_sender_login = with lib.attrsets; let addresses = zipAttrs (lib.flatten (mapAttrsToList (n: v: (map (e: { "${e}" = "${n}@immae.eu"; }) v.emails)) config.myEnv.servers)); + aliases = config.myEnv.mail.postfix.common_aliases; joined = builtins.concatStringsSep ","; + admins = joined config.myEnv.mail.postfix.admins; in pkgs.writeText "host-sender-login" - (builtins.concatStringsSep "\n" (mapAttrsToList (n: v: "${n} ${joined v}") addresses)); - host_dummy_mailboxes = pkgs.writeText "host-virtual-mailbox" - (builtins.concatStringsSep "\n" (["immae-eu@immae.eu dummy"] ++ lib.attrsets.mapAttrsToList (n: v: "${n}@immae.eu dummy") nodes)); + (builtins.concatStringsSep "\n" ( + mapAttrsToList (n: v: "${n} ${joined v}") addresses + ++ lib.lists.flatten ( + map (domain: + map (alias: "${alias}@${domain} ${admins}") aliases + ) all_domains + ) + ++ map (a: "${a} ${admins}") config.myEnv.mail.postfix.other_aliases + )); }; in recipient_maps // relay_restrictions // virtual_map // sasl_access; @@ -290,26 +333,18 @@ mailbox_size_limit = "1073741825"; # Workaround, local delivered mails should all go through scripts alias_database = "\$alias_maps"; + ### Aliases scripts user + default_privs = "postfixscripts"; + ### Virtual mailboxes config virtual_alias_maps = [ "hash:/etc/postfix/virtual" "mysql:${config.secrets.fullPaths."postfix/mysql_alias_maps"}" "ldap:${config.secrets.fullPaths."postfix/ldap_ejabberd_users_immae_fr"}" ]; - virtual_mailbox_domains = config.myEnv.mail.postfix.additional_mailbox_domains - ++ lib.remove null (lib.flatten (map - (zone: map - (e: if e.receive - then "${e.domain}${lib.optionalString (e.domain != "") "."}${zone.name}" - else null - ) - (zone.withEmail or []) - ) - config.myEnv.dns.masterZones - )); + virtual_mailbox_domains = all_domains; virtual_mailbox_maps = [ - "hash:/etc/postfix/host_dummy_mailboxes" - "mysql:${config.secrets.fullPaths."postfix/mysql_mailbox_maps"}" + "ldap:${config.secrets.fullPaths."postfix/ldap_mailboxes"}" ]; dovecot_destination_recipient_limit = "1"; virtual_transport = "dovecot"; @@ -336,7 +371,7 @@ smtp_tls_loglevel = "1"; ### Force ip bind for smtp - smtp_bind_address = config.hostEnv.ips.main.ip4; + smtp_bind_address = builtins.head config.hostEnv.ips.main.ip4; smtp_bind_address6 = builtins.head config.hostEnv.ips.main.ip6; # Use some relays when authorized senders are not myself @@ -426,16 +461,23 @@ # here. rspamc_dovecot = pkgs.writeScriptBin "rspamc_dovecot" '' #! ${pkgs.stdenv.shell} + set -o pipefail sender="$1" original_recipient="$2" user="$3" ${pkgs.coreutils}/bin/cat - | \ - (${pkgs.rspamd}/bin/rspamc -h ${config.myServices.mail.rspamd.sockets.worker-controller} -c bayes -d "$user" --mime || true) | \ + ${pkgs.rspamd}/bin/rspamc -h ${config.myServices.mail.rspamd.sockets.worker-controller} -c bayes -d "$user" --mime | \ ${pkgs.dovecot}/libexec/dovecot/dovecot-lda -f "$sender" -a "$original_recipient" -d "$user" + if echo ''${PIPESTATUS[@]} | ${pkgs.gnugrep}/bin/grep -qE '^[0 ]+$'; then + exit 0 + else + # src/global/sys_exits.h to retry + exit 75 + fi ''; in [ - "flags=DRhu" "user=vhost:vhost" + "flags=ODRhu" "user=vhost:vhost" "argv=${rspamc_dovecot}/bin/rspamc_dovecot \${sender} \${original_recipient} \${user}@\${nexthop}" ]; }; @@ -445,17 +487,13 @@ postRun = '' systemctl restart postfix.service ''; - extraDomains = { - "smtp.immae.eu" = null; - }; + extraDomainNames = [ "smtp.immae.eu" ]; }; security.acme.certs."mail-rsa" = { postRun = '' systemctl restart postfix.service ''; - extraDomains = { - "smtp.immae.eu" = null; - }; + extraDomainNames = [ "smtp.immae.eu" ]; }; system.activationScripts.testmail = { deps = [ "users" ]; @@ -468,14 +506,15 @@ in "${cfg'.mail_address}${sep}${host'}@${cfg'.mail_domain}"; mails_to_receive = builtins.concatStringsSep " " (map (to_email cfg) reverseTargets); in '' - install -m 0555 -o nobody -g nogroup -d /var/lib/naemon/checks/email + install -m 0555 -o postfixscripts -g keys -d /var/lib/naemon/checks/email for f in ${mails_to_receive}; do if [ ! -f /var/lib/naemon/checks/email/$f ]; then - install -m 0644 -o nobody -g nogroup /dev/null -T /var/lib/naemon/checks/email/$f + install -m 0644 -o postfixscripts -g keys /dev/null -T /var/lib/naemon/checks/email/$f touch -m -d @0 /var/lib/naemon/checks/email/$f fi done ''; }; + systemd.services.postfix.serviceConfig.Slice = "mail.slice"; }; }