]> git.immae.eu Git - perso/Immae/Config/Nix.git/blobdiff - modules/private/mail/postfix.nix
Postfix common aliases
[perso/Immae/Config/Nix.git] / modules / private / mail / postfix.nix
index 0c95df57eb68e826aff10f2dd8d0f4af85de2191..7e06c452c9ca2f6e87e2832cb78ede804cfc8a56 100644 (file)
@@ -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,9 +61,8 @@
               FROM forwardings_blacklisted
               WHERE source = '%s'
           '';
-      }
-      {
-        dest = "postfix/ldap_mailboxes";
+      };
+      "postfix/ldap_mailboxes" = {
         user = config.services.postfix.user;
         group = config.services.postfix.group;
         permissions = "0440";
@@ -48,9 +76,8 @@
           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";
@@ -72,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";
               ((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";
               ((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";
               ((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";
           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;
           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}
           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));
+            (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;
         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 = [
           "ldap:${config.secrets.fullPaths."postfix/ldap_mailboxes"}"
         ];
         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
             # 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}"
           ];
         };
       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" ];
           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";
   };
 }