From 75695d3e42bfe15483cefa43f316a4ae11a3bcca Mon Sep 17 00:00:00 2001 From: Gregor Kleen Date: Wed, 21 May 2025 09:24:30 +0200 Subject: ... --- hosts/surtr/email/default.nix | 105 ++++++++++++++++++++++++++++++++++-------- 1 file changed, 85 insertions(+), 20 deletions(-) (limited to 'hosts/surtr/email/default.nix') diff --git a/hosts/surtr/email/default.nix b/hosts/surtr/email/default.nix index 845f6455..c6253e4c 100644 --- a/hosts/surtr/email/default.nix +++ b/hosts/surtr/email/default.nix @@ -1,4 +1,4 @@ -{ config, pkgs, lib, flakeInputs, ... }: +{ config, pkgs, lib, flake, flakeInputs, ... }: with lib; @@ -15,7 +15,7 @@ let for file in $out/pipe/bin/*; do wrapProgram $file \ - --set PATH "${pkgs.coreutils}/bin:${pkgs.rspamd}/bin" + --set PATH "${makeBinPath (with pkgs; [coreutils rspamd])}" done ''; }; @@ -33,12 +33,28 @@ let }); }); }; + internal-policy-server = + let + workspace = flakeInputs.uv2nix.lib.workspace.loadWorkspace { workspaceRoot = ./internal-policy-server; }; + pythonSet = flake.lib.pythonSet { + inherit pkgs; + python = pkgs.python312; + overlay = workspace.mkPyprojectOverlay { + sourcePreference = "wheel"; + }; + }; + virtualEnv = pythonSet.mkVirtualEnv "internal-policy-server-env" workspace.deps.default; + in virtualEnv.overrideAttrs (oldAttrs: { + meta = (oldAttrs.meta or {}) // { + mainProgram = "internal-policy-server"; + }; + }); - nftables-nologin-script = pkgs.writeScript "nftables-mail-nologin" '' - #!${pkgs.zsh}/bin/zsh - + nftables-nologin-script = pkgs.resholve.writeScript "nftables-mail-nologin" { + inputs = with pkgs; [inetutils nftables gnugrep findutils]; + interpreter = lib.getExe pkgs.zsh; + } '' set -e - export PATH="${lib.makeBinPath (with pkgs; [inetutils nftables])}:$PATH" typeset -a as_sets mnt_bys route route6 as_sets=(${lib.escapeShellArgs config.services.email.nologin.ASSets}) @@ -51,7 +67,7 @@ let elif [[ "''${line}" =~ "^route6:\s+(.+)$" ]]; then route6+=($match[1]) fi - done < <(whois -h whois.radb.net "!i''${as_set},1" | egrep -o 'AS[0-9]+' | xargs -- whois -h whois.radb.net -- -i origin) + done < <(whois -h whois.radb.net "!i''${as_set},1" | grep -Eo 'AS[0-9]+' | xargs whois -h whois.radb.net -- -i origin) done for mnt_by in $mnt_bys; do while IFS=$'\n' read line; do @@ -190,6 +206,7 @@ in { "reject_unauth_destination" "reject_unknown_recipient_domain" "reject_unverified_recipient" + "check_policy_service unix:/run/postfix-internal-policy.sock" ]; unverified_recipient_reject_code = "550"; unverified_recipient_reject_reason = "Recipient address lookup failed"; @@ -251,7 +268,7 @@ in { virtual_transport = "dvlmtp:unix:/run/dovecot-lmtp"; smtputf8_enable = false; - authorized_submit_users = "inline:{ root= postfwd= }"; + authorized_submit_users = "inline:{ root= postfwd= dovecot2= }"; postscreen_access_list = ""; postscreen_denylist_action = "drop"; @@ -280,7 +297,7 @@ in { hosts = postgresql:///email dbname = email query = SELECT action FROM virtual_mailbox_access WHERE lookup = '%s' OR (lookup = regexp_replace('%s', '\+[^@]*@', '@') AND NOT EXISTS (SELECT 1 FROM virtual_mailbox_access WHERE lookup = '%s')) - ''},permit_tls_all_clientcerts,reject}'' + ''},check_policy_service unix:/run/postfix-internal-policy.sock,permit_tls_all_clientcerts,reject}'' "-o" "smtpd_relay_restrictions=permit_tls_all_clientcerts,reject" "-o" "{smtpd_data_restrictions = check_policy_service unix:/run/postfwd3/postfwd3.sock}" "-o" "unverified_sender_reject_code=550" @@ -310,7 +327,7 @@ in { hosts = postgresql:///email dbname = email query = SELECT action FROM virtual_mailbox_access WHERE lookup = '%s' OR (lookup = regexp_replace('%s', '\+[^@]*@', '@') AND NOT EXISTS (SELECT 1 FROM virtual_mailbox_access WHERE lookup = '%s')) - ''},permit_sasl_authenticated,reject}'' + ''},check_policy_service unix:/run/postfix-internal-policy.sock,permit_sasl_authenticated,reject}'' "-o" "smtpd_relay_restrictions=permit_sasl_authenticated,reject" "-o" "{smtpd_data_restrictions = check_policy_service unix:/run/postfwd3/postfwd3.sock}" "-o" "unverified_sender_reject_code=550" @@ -672,7 +689,7 @@ in { plugin { plugin = fts fts_xapian fts = xapian - fts_xapian = partial=2 full=20 attachments=1 verbose=1 + fts_xapian = partial=3 full=20 attachments=1 verbose=1 fts_autoindex = yes @@ -692,7 +709,7 @@ in { startAt = "*-*-* 22:00:00 Europe/Berlin"; serviceConfig = { Type = "oneshot"; - ExecStart = "${pkgs.dovecot}/bin/doveadm fts optimize -A"; + ExecStart = "${getExe' pkgs.dovecot "doveadm"} fts optimize -A"; PrivateDevices = true; PrivateNetwork = true; ProtectKernelTunables = true; @@ -777,7 +794,7 @@ in { systemd.services.dovecot2 = { preStart = '' for f in /etc/dovecot/sieve_flag.d/*.sieve /etc/dovecot/sieve_before.d/*.sieve; do - ${pkgs.dovecot_pigeonhole}/bin/sievec $f + ${getExe' pkgs.dovecot_pigeonhole "sievec"} $f done ''; @@ -844,15 +861,16 @@ in { charset utf-8; source_charset utf-8; ''; - root = pkgs.runCommand "mta-sts.${domain}" {} '' - mkdir -p $out/.well-known - cp ${pkgs.writeText "mta-sts.${domain}.txt" '' + root = pkgs.writeTextFile { + name = "mta-sts.${domain}"; + destination = "/.well-known/mta-sts.txt"; + text = '' version: STSv1 mode: enforce max_age: 2419200 mx: mailin.${domain} - ''} $out/.well-known/mta-sts.txt - ''; + ''; + }; }; }) emailDomains); }; @@ -869,7 +887,7 @@ in { systemd.services.spm = { serviceConfig = { Type = "notify"; - ExecStart = "${pkgs.spm}/bin/spm-server"; + ExecStart = getExe' pkgs.spm "spm-server"; User = "spm"; Group = "spm"; @@ -927,7 +945,7 @@ in { serviceConfig = { Type = "notify"; - ExecStart = "${ccert-policy-server}/bin/ccert-policy-server"; + ExecStart = getExe' ccert-policy-server "ccert-policy-server"; Environment = [ "PGDATABASE=email" @@ -960,6 +978,53 @@ in { }; users.groups."postfix-ccert-sender-policy" = {}; + systemd.sockets."postfix-internal-policy" = { + requiredBy = ["postfix.service"]; + wants = ["postfix-internal-policy.service"]; + socketConfig = { + ListenStream = "/run/postfix-internal-policy.sock"; + }; + }; + systemd.services."postfix-internal-policy" = { + after = [ "postgresql.service" ]; + bindsTo = [ "postgresql.service" ]; + + serviceConfig = { + Type = "notify"; + + ExecStart = lib.getExe internal-policy-server; + + Environment = [ + "PGDATABASE=email" + ]; + + DynamicUser = false; + User = "postfix-internal-policy"; + Group = "postfix-internal-policy"; + ProtectSystem = "strict"; + SystemCallFilter = "@system-service"; + NoNewPrivileges = true; + ProtectKernelTunables = true; + ProtectKernelModules = true; + ProtectKernelLogs = true; + ProtectControlGroups = true; + MemoryDenyWriteExecute = true; + RestrictSUIDSGID = true; + KeyringMode = "private"; + ProtectClock = true; + RestrictRealtime = true; + PrivateDevices = true; + PrivateTmp = true; + ProtectHostname = true; + ReadWritePaths = ["/run/postgresql"]; + }; + }; + users.users."postfix-internal-policy" = { + isSystemUser = true; + group = "postfix-internal-policy"; + }; + users.groups."postfix-internal-policy" = {}; + services.postfwd = { enable = true; cache = false; -- cgit v1.2.3