From 83af4a9aed805366fc92a249eaf6d8e6617733d5 Mon Sep 17 00:00:00 2001 From: Martin Weinelt Date: Mon, 14 Jul 2025 00:58:45 +0200 Subject: [PATCH 1/5] nixos/postsrsd: migrate to rfc42 settings Allow a freeform configuration approach to satisfy different configuration complexities. Remove confinement options and make its hardening options more explicit and removed the deprecated PermissionStartOnly= option. --- nixos/modules/services/mail/postsrsd.nix | 221 ++++++++++++++++++----- 1 file changed, 173 insertions(+), 48 deletions(-) diff --git a/nixos/modules/services/mail/postsrsd.nix b/nixos/modules/services/mail/postsrsd.nix index bc91edbbe000..2ff28f96d97b 100644 --- a/nixos/modules/services/mail/postsrsd.nix +++ b/nixos/modules/services/mail/postsrsd.nix @@ -7,32 +7,59 @@ let cfg = config.services.postsrsd; - runtimeDirectoryName = "postsrsd"; - runtimeDirectory = "/run/${runtimeDirectoryName}"; - # TODO: follow RFC 42, but we need a libconfuse format first: - # https://github.com/NixOS/nixpkgs/issues/401565 - # Arrays in `libconfuse` look like this: {"Life", "Universe", "Everything"} - # See https://www.nongnu.org/confuse/tutorial-html/ar01s03.html. - # - # Note: We're using `builtins.toJSON` to escape strings, but JSON strings - # don't have exactly the same semantics as libconfuse strings. For example, - # "${F}" gets treated as an env var reference, see above issue for details. - libconfuseDomains = "{ " + lib.concatMapStringsSep ", " builtins.toJSON cfg.domains + " }"; - configFile = pkgs.writeText "postsrsd.conf" '' - secrets-file = "''${CREDENTIALS_DIRECTORY}/secrets-file" - domains = ${libconfuseDomains} - separator = "${cfg.separator}" - socketmap = "unix:${cfg.socketPath}" - # Disable postsrsd's jailing in favor of confinement with systemd. - unprivileged-user = "" - chroot-dir = "" - ''; + inherit (lib) + concatMapStringsSep + concatMapAttrsStringSep + isBool + isFloat + isInt + isPath + isString + isList + mkRemovedOptionModule + mkRenamedOptionModule + ; + # This is a implementation of a simple libconfuse config renderer sufficient + # for the postsrsd configuration file complexity. + # TODO: Replace with pkgs.formats.libconfuse, once implemented (https://github.com/NixOS/nixpkgs/issues/401565) + renderValue = + value: + if isBool value then + if value then "true" else "false" + else if isString value || isPath value then + builtins.toJSON value # for escaping + else if isInt value || isFloat value then + toString value + else if isList value then + "{${concatMapStringsSep "," renderValue value}}" + else + throw "postsrsd: unsupported value type in settings option"; + + renderAttr = + attrs: concatMapAttrsStringSep "\n" (name: value: "${name} = ${renderValue value}") attrs; + + configFile = pkgs.writeText "postsrsd.conf" ( + renderAttr (lib.filterAttrsRecursive (_: v: v != null) cfg.settings) + ); in { imports = - map + [ + (mkRemovedOptionModule [ "services" "postsrsd" "socketPath" ] '' + Configure/reference `services.postsrsd.settings.socketmap` instead. Note that its now required to start with the `inet:` or `unix:` prefix. + '') + (mkRenamedOptionModule + [ "services" "postsrsd" "domains" ] + [ "services" "postsrsd" "settings" "domains" ] + ) + (mkRenamedOptionModule + [ "services" "postsrsd" "separator" ] + [ "services" "postsrsd" "settings" "separator" ] + ) + ] + ++ map ( name: lib.mkRemovedOptionModule [ "services" "postsrsd" name ] '' @@ -62,24 +89,125 @@ in secretsFile = lib.mkOption { type = lib.types.path; default = "/var/lib/postsrsd/postsrsd.secret"; - description = "Secret keys used for signing and verification"; + description = '' + Secret keys used for signing and verification. + + ::: {.note} + The secret will be generated, if it does not exist at the given path. + ::: + ''; }; - domains = lib.mkOption { - type = lib.types.listOf lib.types.str; - description = "Domain names for rewrite"; - default = [ config.networking.hostName ]; - defaultText = lib.literalExpression "[ config.networking.hostName ]"; - }; + settings = lib.mkOption { + type = lib.types.submodule { + freeformType = + with lib.types; + attrsOf (oneOf [ + bool + float + int + path + str + (listOf str) + ]); - separator = lib.mkOption { - type = lib.types.enum [ - "-" - "=" - "+" - ]; - default = "="; - description = "First separator character in generated addresses"; + options = { + domains = lib.mkOption { + type = with lib.types; listOf str; + default = [ ]; + example = [ "example.com" ]; + description = '' + List of local domains, that do not require rewriting. + ''; + }; + + secrets-file = lib.mkOption { + type = lib.types.str; + default = "\${CREDENTIALS_DIRECTORY}/secrets-file"; + readOnly = true; + description = '' + Path to the file containing the secret keys. + + ::: {.note} + Secrets are passed using `LoadCredential=` on the systemd unit, + so this options is read-only. + + Configure {option}`services.postsrsd.secretsFile` instead. + ''; + }; + + separator = lib.mkOption { + type = lib.types.enum [ + "-" + "=" + "+" + ]; + default = "="; + description = '' + SRS tag separator used in generated sender addresses. + + Unless you have a very good reason, you should leave this + setting at its default. + ''; + }; + + srs-domain = lib.mkOption { + type = with lib.types; nullOr str; + default = null; + example = "srs.example.com"; + description = '' + Dedicated mail domain used for ephemeral SRS envelope addresses. + + Recommended to configure, when hosting multiple unrelated mail + domains (e.g. for different customers), to prevent privacy + issues. + + Set to `null` to not configure any `srs-domain`. + ''; + }; + + socketmap = lib.mkOption { + type = lib.types.strMatching "^(unix|inet):.+"; + default = "unix:/run/postsrsd/socket"; + example = "inet:localhost:10003"; + description = '' + Listener configuration in socket map format native to Postfix configuration. + ''; + }; + + chroot-dir = lib.mkOption { + type = lib.types.str; + default = ""; + readOnly = true; + description = '' + Path to chroot into at runtime as an additional layer of protection. + + ::: {.note} + We confine the runtime environment through systemd hardening instead, so this option is read-only. + ::: + ''; + }; + + unprivileged-user = lib.mkOption { + type = lib.types.str; + default = ""; + readOnly = true; + description = '' + Unprivileged user to drop privileges to. + + ::: {.note} + Our systemd unit never runs postsrsd as a privileged process, so this option is read-only. + ::: + ''; + }; + }; + }; + default = { }; + description = '' + Configuration options for the postsrsd.conf file. + + See the [example configuration](https://github.com/roehling/postsrsd/blob/main/doc/postsrsd.conf) for possible values. + ''; }; user = lib.mkOption { @@ -93,15 +221,6 @@ in default = "postsrsd"; description = "Group for the daemon"; }; - - socketPath = lib.mkOption { - type = lib.types.path; - default = "${runtimeDirectory}/socket"; - readOnly = true; - description = '' - Path to the Unix socket for connecting to postsrsd. - Read-only, intended for usage when integrating postsrsd into other NixOS config.''; - }; }; }; @@ -143,15 +262,21 @@ in before = [ "postfix.service" ]; wantedBy = [ "multi-user.target" ]; requires = [ "postsrsd-generate-secrets.service" ]; - confinement.enable = true; serviceConfig = { ExecStart = "${lib.getExe pkgs.postsrsd} -C ${configFile}"; User = cfg.user; Group = cfg.group; - PermissionsStartOnly = true; - RuntimeDirectory = runtimeDirectoryName; + RuntimeDirectory = "postsrsd"; LoadCredential = "secrets-file:${cfg.secretsFile}"; + + PrivateDevices = true; + PrivateMounts = true; + PrivateTmp = true; + PrivateUsers = true; + ProtectControlGroups = true; + ProtectKernelModules = true; + ProtectKernelTunables = true; }; }; }; From 819c34cb7f485c4f813e0dd87f6ba842970c864b Mon Sep 17 00:00:00 2001 From: Martin Weinelt Date: Mon, 14 Jul 2025 01:21:08 +0200 Subject: [PATCH 2/5] nixos/postsrsd: harden and modernize systemd unit This replaces the previous confinement settings with a more complete and context-sensitive hardening setup. Also exposes the current config at /etc/postsrsd.conf, which makes it easily inspectable. --- nixos/modules/services/mail/postsrsd.nix | 93 +++++++++++++++++++++++- 1 file changed, 92 insertions(+), 1 deletion(-) diff --git a/nixos/modules/services/mail/postsrsd.nix b/nixos/modules/services/mail/postsrsd.nix index 2ff28f96d97b..34e7b15e2d17 100644 --- a/nixos/modules/services/mail/postsrsd.nix +++ b/nixos/modules/services/mail/postsrsd.nix @@ -2,6 +2,7 @@ config, lib, pkgs, + utils, ... }: let @@ -253,6 +254,8 @@ in }; }; + environment.etc."postsrsd.conf".source = configFile; + systemd.services.postsrsd = { description = "PostSRSd SRS rewriting server"; after = [ @@ -262,21 +265,109 @@ in before = [ "postfix.service" ]; wantedBy = [ "multi-user.target" ]; requires = [ "postsrsd-generate-secrets.service" ]; + restartTriggers = [ configFile ]; serviceConfig = { - ExecStart = "${lib.getExe pkgs.postsrsd} -C ${configFile}"; + ExecStart = toString [ + (lib.getExe pkgs.postsrsd) + "-C" + "/etc/postsrsd.conf" + ]; User = cfg.user; Group = cfg.group; RuntimeDirectory = "postsrsd"; + RuntimeDirectoryMode = "0750"; LoadCredential = "secrets-file:${cfg.secretsFile}"; + CapabilityBoundingSet = [ "" ]; + LockPersonality = true; + MemoryDenyWriteExecute = true; + NoNewPrivileges = true; PrivateDevices = true; PrivateMounts = true; + PrivateNetwork = lib.hasPrefix "unix:" cfg.settings.socketmap; PrivateTmp = true; PrivateUsers = true; ProtectControlGroups = true; + ProtectHome = true; + ProtectHostname = true; + ProtectKernelLogs = true; ProtectKernelModules = true; ProtectKernelTunables = true; + ProtectSystem = "strict"; + ProtectProc = "invisible"; + ProcSubset = "pid"; + RemoveIPC = true; + RestrictAddressFamilies = + if lib.hasPrefix "unix:" cfg.settings.socketmap then + [ "AF_UNIX" ] + else + [ + "AF_INET" + "AF_INET6" + ]; + RestrictNamespaces = true; + RestrictRealtime = true; + RestrictSUIDSGID = true; + SystemCallArchitectures = "native"; + SystemCallFilter = [ + "@system-service" + "~@privileged @resources" + ]; + UMask = "0027"; + before = [ "postfix.service" ]; + wantedBy = [ "multi-user.target" ]; + requires = [ "postsrsd-generate-secrets.service" ]; + restartTriggers = [ configFile ]; + serviceConfig = { + ExecStart = utils.escapeSystemdExecArgs [ + (lib.getExe cfg.package) + "-C" + "/etc/postsrsd.conf" + ]; + User = cfg.user; + Group = cfg.group; + RuntimeDirectory = "postsrsd"; + RuntimeDirectoryMode = "0750"; + LoadCredential = "secrets-file:${cfg.secretsFile}"; + + CapabilityBoundingSet = [ "" ]; + LockPersonality = true; + MemoryDenyWriteExecute = true; + NoNewPrivileges = true; + PrivateDevices = true; + PrivateMounts = true; + PrivateNetwork = lib.hasPrefix "unix:" cfg.settings.socketmap; + PrivateTmp = true; + PrivateUsers = true; + ProtectControlGroups = true; + ProtectHome = true; + ProtectHostname = true; + ProtectKernelLogs = true; + ProtectKernelModules = true; + ProtectKernelTunables = true; + ProtectSystem = "strict"; + ProtectProc = "invisible"; + ProcSubset = "pid"; + RemoveIPC = true; + RestrictAddressFamilies = + if lib.hasPrefix "unix:" cfg.settings.socketmap then + [ "AF_UNIX" ] + else + [ + "AF_INET" + "AF_INET6" + ]; + RestrictNamespaces = true; + RestrictRealtime = true; + RestrictSUIDSGID = true; + SystemCallArchitectures = "native"; + SystemCallFilter = [ + "@system-service" + "~@privileged @resources" + ]; + UMask = "0027"; + }; }; }; }; From 9a9073fc8971a700fb08bb105adc2100fd3fc26f Mon Sep 17 00:00:00 2001 From: Martin Weinelt Date: Mon, 14 Jul 2025 01:49:02 +0200 Subject: [PATCH 3/5] nixos/postsrsd: integrate with postfix by default --- .../manual/release-notes/rl-2511.section.md | 2 + nixos/modules/services/mail/postsrsd.nix | 150 +++++++----------- 2 files changed, 63 insertions(+), 89 deletions(-) diff --git a/nixos/doc/manual/release-notes/rl-2511.section.md b/nixos/doc/manual/release-notes/rl-2511.section.md index 4b0a2c4395d1..be57fec927a0 100644 --- a/nixos/doc/manual/release-notes/rl-2511.section.md +++ b/nixos/doc/manual/release-notes/rl-2511.section.md @@ -120,6 +120,8 @@ - `services.ntpd-rs` now performs configuration validation. +- `services.postsrsd` now automatically integrates with the local Postfix instance, when enabled. This behavior can disabled using the [services.postsrsd.configurePostfix](#opt-services.postsrsd.configurePostfix) option. + - `services.monero` now includes the `environmentFile` option for adding secrets to the Monero daemon config. - `amdgpu` kernel driver overdrive mode can now be enabled by setting [hardware.amdgpu.overdrive.enable](#opt-hardware.amdgpu.overdrive.enable) and customized through [hardware.amdgpu.overdrive.ppfeaturemask](#opt-hardware.amdgpu.overdrive.ppfeaturemask). diff --git a/nixos/modules/services/mail/postsrsd.nix b/nixos/modules/services/mail/postsrsd.nix index 34e7b15e2d17..f790403864f5 100644 --- a/nixos/modules/services/mail/postsrsd.nix +++ b/nixos/modules/services/mail/postsrsd.nix @@ -211,6 +211,14 @@ in ''; }; + configurePostfix = lib.mkOption { + type = lib.types.bool; + default = true; + description = '' + Whether to configure the required settings to use postsrsd in the local Postfix instance. + ''; + }; + user = lib.mkOption { type = lib.types.str; default = "postsrsd"; @@ -225,103 +233,67 @@ in }; }; - config = lib.mkIf cfg.enable { - users.users = lib.optionalAttrs (cfg.user == "postsrsd") { - postsrsd = { - group = cfg.group; - uid = config.ids.uids.postsrsd; - }; - }; - - users.groups = lib.optionalAttrs (cfg.group == "postsrsd") { - postsrsd.gid = config.ids.gids.postsrsd; - }; - - systemd.services.postsrsd-generate-secrets = { - path = [ pkgs.coreutils ]; - script = '' - if [ -e "${cfg.secretsFile}" ]; then - echo "Secrets file exists. Nothing to do!" - else - echo "WARNING: secrets file not found, autogenerating!" - DIR="$(dirname "${cfg.secretsFile}")" - install -m 750 -o ${cfg.user} -g ${cfg.group} -d "$DIR" - install -m 600 -o ${cfg.user} -g ${cfg.group} <(dd if=/dev/random bs=18 count=1 | base64) "${cfg.secretsFile}" - fi - ''; - serviceConfig = { - Type = "oneshot"; - }; - }; - - environment.etc."postsrsd.conf".source = configFile; - - systemd.services.postsrsd = { - description = "PostSRSd SRS rewriting server"; - after = [ - "network.target" - "postsrsd-generate-secrets.service" - ]; - before = [ "postfix.service" ]; - wantedBy = [ "multi-user.target" ]; - requires = [ "postsrsd-generate-secrets.service" ]; - restartTriggers = [ configFile ]; - - serviceConfig = { - ExecStart = toString [ - (lib.getExe pkgs.postsrsd) - "-C" - "/etc/postsrsd.conf" + config = lib.mkMerge [ + (lib.mkIf (cfg.enable && cfg.configurePostfix && config.services.postfix.enable) { + services.postfix.config = { + # https://github.com/roehling/postsrsd#configuration + sender_canonical_maps = "socketmap:${cfg.settings.socketmap}:forward"; + sender_canonical_classes = "envelope_sender"; + recipient_canonical_maps = "socketmap:${cfg.settings.socketmap}:reverse"; + recipient_canonical_classes = [ + "envelope_recipient" + "header_recipient" ]; - User = cfg.user; - Group = cfg.group; - RuntimeDirectory = "postsrsd"; - RuntimeDirectoryMode = "0750"; - LoadCredential = "secrets-file:${cfg.secretsFile}"; + }; - CapabilityBoundingSet = [ "" ]; - LockPersonality = true; - MemoryDenyWriteExecute = true; - NoNewPrivileges = true; - PrivateDevices = true; - PrivateMounts = true; - PrivateNetwork = lib.hasPrefix "unix:" cfg.settings.socketmap; - PrivateTmp = true; - PrivateUsers = true; - ProtectControlGroups = true; - ProtectHome = true; - ProtectHostname = true; - ProtectKernelLogs = true; - ProtectKernelModules = true; - ProtectKernelTunables = true; - ProtectSystem = "strict"; - ProtectProc = "invisible"; - ProcSubset = "pid"; - RemoveIPC = true; - RestrictAddressFamilies = - if lib.hasPrefix "unix:" cfg.settings.socketmap then - [ "AF_UNIX" ] + users.users.postfix.extraGroups = [ cfg.group ]; + }) + + (lib.mkIf cfg.enable { + users.users = lib.optionalAttrs (cfg.user == "postsrsd") { + postsrsd = { + group = cfg.group; + uid = config.ids.uids.postsrsd; + }; + }; + + users.groups = lib.optionalAttrs (cfg.group == "postsrsd") { + postsrsd.gid = config.ids.gids.postsrsd; + }; + + systemd.services.postsrsd-generate-secrets = { + path = [ pkgs.coreutils ]; + script = '' + if [ -e "${cfg.secretsFile}" ]; then + echo "Secrets file exists. Nothing to do!" else - [ - "AF_INET" - "AF_INET6" - ]; - RestrictNamespaces = true; - RestrictRealtime = true; - RestrictSUIDSGID = true; - SystemCallArchitectures = "native"; - SystemCallFilter = [ - "@system-service" - "~@privileged @resources" + echo "WARNING: secrets file not found, autogenerating!" + DIR="$(dirname "${cfg.secretsFile}")" + install -m 750 -o ${cfg.user} -g ${cfg.group} -d "$DIR" + install -m 600 -o ${cfg.user} -g ${cfg.group} <(dd if=/dev/random bs=18 count=1 | base64) "${cfg.secretsFile}" + fi + ''; + serviceConfig = { + Type = "oneshot"; + }; + }; + + environment.etc."postsrsd.conf".source = configFile; + + systemd.services.postsrsd = { + description = "PostSRSd SRS rewriting server"; + after = [ + "network.target" + "postsrsd-generate-secrets.service" ]; - UMask = "0027"; before = [ "postfix.service" ]; wantedBy = [ "multi-user.target" ]; requires = [ "postsrsd-generate-secrets.service" ]; restartTriggers = [ configFile ]; + serviceConfig = { ExecStart = utils.escapeSystemdExecArgs [ - (lib.getExe cfg.package) + (lib.getExe pkgs.postsrsd) "-C" "/etc/postsrsd.conf" ]; @@ -369,6 +341,6 @@ in UMask = "0027"; }; }; - }; - }; + }) + ]; } From c915f104b0c8f231855a451d71678085ca9eab01 Mon Sep 17 00:00:00 2001 From: Martin Weinelt Date: Tue, 15 Jul 2025 00:08:08 +0200 Subject: [PATCH 4/5] nixos/postsrsd: add package option, migrate enable option --- nixos/modules/services/mail/postsrsd.nix | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/nixos/modules/services/mail/postsrsd.nix b/nixos/modules/services/mail/postsrsd.nix index f790403864f5..b264d17a1911 100644 --- a/nixos/modules/services/mail/postsrsd.nix +++ b/nixos/modules/services/mail/postsrsd.nix @@ -18,6 +18,8 @@ let isPath isString isList + mkEnableOption + mkPackageOption mkRemovedOptionModule mkRenamedOptionModule ; @@ -81,11 +83,9 @@ in options = { services.postsrsd = { - enable = lib.mkOption { - type = lib.types.bool; - default = false; - description = "Whether to enable the postsrsd SRS server for Postfix."; - }; + enable = mkEnableOption "the postsrsd SRS server for Postfix."; + + package = mkPackageOption pkgs "postsrsd" { }; secretsFile = lib.mkOption { type = lib.types.path; @@ -207,7 +207,7 @@ in description = '' Configuration options for the postsrsd.conf file. - See the [example configuration](https://github.com/roehling/postsrsd/blob/main/doc/postsrsd.conf) for possible values. + See the [example configuration](https://github.com/roehling/postsrsd/blob/${cfg.package.version}/doc/postsrsd.conf) for possible values. ''; }; @@ -293,7 +293,7 @@ in serviceConfig = { ExecStart = utils.escapeSystemdExecArgs [ - (lib.getExe pkgs.postsrsd) + (lib.getExe cfg.package) "-C" "/etc/postsrsd.conf" ]; @@ -343,4 +343,7 @@ in }; }) ]; + + # package version referenced in option documentation + meta.buildDocsInSandbox = false; } From fbc56958afdf83f0b1bc3be6d9540bcc0deb0971 Mon Sep 17 00:00:00 2001 From: Martin Weinelt Date: Tue, 15 Jul 2025 20:08:24 +0200 Subject: [PATCH 5/5] nixos/pfix-srsd: migrate postfix integration from postfix module The postfix module is too big to host every individual integration option and moving it here has no downside. --- .../manual/release-notes/rl-2511.section.md | 2 + nixos/modules/services/mail/pfix-srsd.nix | 57 +++++++++++++------ nixos/modules/services/mail/postfix.nix | 15 +---- 3 files changed, 43 insertions(+), 31 deletions(-) diff --git a/nixos/doc/manual/release-notes/rl-2511.section.md b/nixos/doc/manual/release-notes/rl-2511.section.md index be57fec927a0..683724e11fc7 100644 --- a/nixos/doc/manual/release-notes/rl-2511.section.md +++ b/nixos/doc/manual/release-notes/rl-2511.section.md @@ -122,6 +122,8 @@ - `services.postsrsd` now automatically integrates with the local Postfix instance, when enabled. This behavior can disabled using the [services.postsrsd.configurePostfix](#opt-services.postsrsd.configurePostfix) option. +- `services.pfix-srsd` now automatically integrates with the local Postfix instance, when enabled. This behavior can disabled using the [services.pfix-srsd.configurePostfix](#opt-services.pfix-srsd.configurePostfix) option. + - `services.monero` now includes the `environmentFile` option for adding secrets to the Monero daemon config. - `amdgpu` kernel driver overdrive mode can now be enabled by setting [hardware.amdgpu.overdrive.enable](#opt-hardware.amdgpu.overdrive.enable) and customized through [hardware.amdgpu.overdrive.ppfeaturemask](#opt-hardware.amdgpu.overdrive.ppfeaturemask). diff --git a/nixos/modules/services/mail/pfix-srsd.nix b/nixos/modules/services/mail/pfix-srsd.nix index fb6a395e3ab8..035f331dcf6d 100644 --- a/nixos/modules/services/mail/pfix-srsd.nix +++ b/nixos/modules/services/mail/pfix-srsd.nix @@ -4,6 +4,10 @@ pkgs, ... }: + +let + cfg = config.services.pfix-srsd; +in { ###### interface @@ -32,27 +36,46 @@ type = lib.types.path; default = "/var/lib/pfix-srsd/secrets"; }; + + configurePostfix = lib.mkOption { + type = lib.types.bool; + default = true; + description = '' + Whether to configure the required settings to use pfix-srsd in the local Postfix instance. + ''; + }; }; }; ###### implementation - config = lib.mkIf config.services.pfix-srsd.enable { - environment = { - systemPackages = [ pkgs.pfixtools ]; - }; - - systemd.services.pfix-srsd = { - description = "Postfix sender rewriting scheme daemon"; - before = [ "postfix.service" ]; - #note that we use requires rather than wants because postfix - #is unable to process (almost) all mail without srsd - requiredBy = [ "postfix.service" ]; - serviceConfig = { - Type = "forking"; - PIDFile = "/run/pfix-srsd.pid"; - ExecStart = "${pkgs.pfixtools}/bin/pfix-srsd -p /run/pfix-srsd.pid -I ${config.services.pfix-srsd.domain} ${config.services.pfix-srsd.secretsFile}"; + config = lib.mkMerge [ + (lib.mkIf (cfg.enable && cfg.configurePostfix && config.services.postfix.enable) { + services.postfix.config = { + sender_canonical_maps = [ "tcp:127.0.0.1:10001" ]; + sender_canonical_classes = [ "envelope_sender" ]; + recipient_canonical_maps = [ "tcp:127.0.0.1:10002" ]; + recipient_canonical_classes = [ "envelope_recipient" ]; }; - }; - }; + }) + + (lib.mkIf cfg.enable { + environment = { + systemPackages = [ pkgs.pfixtools ]; + }; + + systemd.services.pfix-srsd = { + description = "Postfix sender rewriting scheme daemon"; + before = [ "postfix.service" ]; + #note that we use requires rather than wants because postfix + #is unable to process (almost) all mail without srsd + requiredBy = [ "postfix.service" ]; + serviceConfig = { + Type = "forking"; + PIDFile = "/run/pfix-srsd.pid"; + ExecStart = "${pkgs.pfixtools}/bin/pfix-srsd -p /run/pfix-srsd.pid -I ${config.services.pfix-srsd.domain} ${config.services.pfix-srsd.secretsFile}"; + }; + }; + }) + ]; } diff --git a/nixos/modules/services/mail/postfix.nix b/nixos/modules/services/mail/postfix.nix index 7b2d62e1fc97..710f2d381e6a 100644 --- a/nixos/modules/services/mail/postfix.nix +++ b/nixos/modules/services/mail/postfix.nix @@ -785,12 +785,6 @@ in description = "Maps to be compiled and placed into /var/lib/postfix/conf."; }; - useSrs = lib.mkOption { - type = lib.types.bool; - default = false; - description = "Whether to enable sender rewriting scheme"; - }; - }; }; @@ -808,8 +802,6 @@ in systemPackages = [ pkgs.postfix ]; }; - services.pfix-srsd.enable = config.services.postfix.useSrs; - services.mail.sendmailSetuidWrapper = lib.mkIf config.services.postfix.setSendmail { program = "sendmail"; source = "${pkgs.postfix}/bin/sendmail"; @@ -1002,12 +994,6 @@ in ] ++ lib.optional haveAliases "$alias_maps"; } // lib.optionalAttrs (cfg.dnsBlacklists != [ ]) { smtpd_client_restrictions = clientRestrictions; } - // lib.optionalAttrs cfg.useSrs { - sender_canonical_maps = [ "tcp:127.0.0.1:10001" ]; - sender_canonical_classes = [ "envelope_sender" ]; - recipient_canonical_maps = [ "tcp:127.0.0.1:10002" ]; - recipient_canonical_classes = [ "envelope_recipient" ]; - } // lib.optionalAttrs cfg.enableHeaderChecks { header_checks = [ "regexp:/etc/postfix/header_checks" ]; } @@ -1190,5 +1176,6 @@ in [ "services" "postfix" "config" "smtp_tls_security_level" ] (config: lib.mkIf config.services.postfix.useDane "dane") ) + (lib.mkRenamedOptionModule [ "services" "postfix" "useSrs" ] [ "services" "pfix-srsd" "enable" ]) ]; }