From d1e920fc3778706599e32e80069a536f59a9e0d8 Mon Sep 17 00:00:00 2001 From: Jeremy Fleischman Date: Wed, 9 Apr 2025 02:27:08 -0700 Subject: [PATCH] services/postsrsd: updates for postsrsd 2 postsrsd 2 expects a config file, and has some breaking changes that make it incompatible with some of our old options. --- doc/release-notes/rl-2505.section.md | 4 + nixos/modules/services/mail/postsrsd.nix | 133 +++++++++++++---------- 2 files changed, 77 insertions(+), 60 deletions(-) diff --git a/doc/release-notes/rl-2505.section.md b/doc/release-notes/rl-2505.section.md index 233af95efc83..75caac36d82c 100644 --- a/doc/release-notes/rl-2505.section.md +++ b/doc/release-notes/rl-2505.section.md @@ -58,6 +58,10 @@ OpenSMTPD 7.6.0 or later. The package has been removed in favor of a set of new `opensmtpd-table-*` packages. +- `postsrsd` upgraded to `>= 2.0.0`, with some different behaviors and + configuration settings. Notably, it now defaults to listening on a socket + rather than a port. See [Migrating from version 1.x](https://github.com/roehling/postsrsd/blob/2.0.10/README.rst#migrating-from-version-1x) and [Postfix Setup](https://github.com/roehling/postsrsd?tab=readme-ov-file#postfix-setup) for details. + - The hand written `perlPackages.SearchXapian` bindings have been dropped in favor of the (mostly compatible) `perlPackages.Xapian`. diff --git a/nixos/modules/services/mail/postsrsd.nix b/nixos/modules/services/mail/postsrsd.nix index 3f0db2d91c00..e7c133bceac1 100644 --- a/nixos/modules/services/mail/postsrsd.nix +++ b/nixos/modules/services/mail/postsrsd.nix @@ -7,16 +7,52 @@ 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:${runtimeDirectory}/socket" + + # Disable postsrsd's jailing in favor of confinement with systemd. + unprivileged-user = "" + chroot-dir = "" + ''; in { - - ###### interface + imports = + map + ( + name: + lib.mkRemovedOptionModule [ "services" "postsrsd" name ] '' + `postsrsd` was upgraded to `>= 2.0.0`, with some different behaviors and configuration settings: + - NixOS Release Notes: https://nixos.org/manual/nixos/unstable/release-notes#sec-nixpkgs-release-25.05-incompatibilities + - NixOS Options Reference: https://nixos.org/manual/nixos/unstable/options#opt-services.postsrsd.enable + - Migration instructions: https://github.com/roehling/postsrsd/blob/2.0.10/README.rst#migrating-from-version-1x + - Postfix Setup: https://github.com/roehling/postsrsd/blob/2.0.10/README.rst#postfix-setup + '' + ) + [ + "domain" + "forwardPort" + "reversePort" + "timeout" + "excludeDomains" + ]; options = { - services.postsrsd = { - enable = lib.mkOption { type = lib.types.bool; default = false; @@ -29,9 +65,11 @@ in description = "Secret keys used for signing and verification"; }; - domain = lib.mkOption { - type = lib.types.str; - description = "Domain name for rewrite"; + 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 ]"; }; separator = lib.mkOption { @@ -44,36 +82,6 @@ in description = "First separator character in generated addresses"; }; - # bindAddress = lib.mkOption { # uncomment once 1.5 is released - # type = lib.types.str; - # default = "127.0.0.1"; - # description = "Socket listen address"; - # }; - - forwardPort = lib.mkOption { - type = lib.types.int; - default = 10001; - description = "Port for the forward SRS lookup"; - }; - - reversePort = lib.mkOption { - type = lib.types.int; - default = 10002; - description = "Port for the reverse SRS lookup"; - }; - - timeout = lib.mkOption { - type = lib.types.int; - default = 1800; - description = "Timeout for idle client connections in seconds"; - }; - - excludeDomains = lib.mkOption { - type = lib.types.listOf lib.types.str; - default = [ ]; - description = "Origin domains to exclude from rewriting in addition to primary domain"; - }; - user = lib.mkOption { type = lib.types.str; default = "postsrsd"; @@ -85,17 +93,10 @@ in default = "postsrsd"; description = "Group for the daemon"; }; - }; - }; - ###### implementation - config = lib.mkIf cfg.enable { - - services.postsrsd.domain = lib.mkDefault config.networking.hostName; - users.users = lib.optionalAttrs (cfg.user == "postsrsd") { postsrsd = { group = cfg.group; @@ -107,30 +108,42 @@ in postsrsd.gid = config.ids.gids.postsrsd; }; - systemd.services.postsrsd = { - description = "PostSRSd SRS rewriting server"; - after = [ "network.target" ]; - before = [ "postfix.service" ]; - wantedBy = [ "multi-user.target" ]; - + systemd.services.postsrsd-generate-secrets = { path = [ pkgs.coreutils ]; - - serviceConfig = { - ExecStart = ''${pkgs.postsrsd}/sbin/postsrsd "-s${cfg.secretsFile}" "-d${cfg.domain}" -a${cfg.separator} -f${toString cfg.forwardPort} -r${toString cfg.reversePort} -t${toString cfg.timeout} "-X${lib.concatStringsSep "," cfg.excludeDomains}"''; - User = cfg.user; - Group = cfg.group; - PermissionsStartOnly = true; - }; - - preStart = '' - if [ ! -e "${cfg.secretsFile}" ]; then + 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"; + }; }; + 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" ]; + confinement.enable = true; + + serviceConfig = { + ExecStart = "${lib.getExe pkgs.postsrsd} -C ${configFile}"; + User = cfg.user; + Group = cfg.group; + PermissionsStartOnly = true; + RuntimeDirectory = runtimeDirectoryName; + LoadCredential = "secrets-file:${cfg.secretsFile}"; + }; + }; }; }