diff options
Diffstat (limited to 'modules/postsrsd.nix')
-rw-r--r-- | modules/postsrsd.nix | 157 |
1 files changed, 157 insertions, 0 deletions
diff --git a/modules/postsrsd.nix b/modules/postsrsd.nix new file mode 100644 index 00000000..205e669d --- /dev/null +++ b/modules/postsrsd.nix | |||
@@ -0,0 +1,157 @@ | |||
1 | { | ||
2 | config, | ||
3 | lib, | ||
4 | pkgs, | ||
5 | ... | ||
6 | }: | ||
7 | let | ||
8 | |||
9 | cfg = config.services.postsrsd; | ||
10 | runtimeDirectoryName = "postsrsd"; | ||
11 | runtimeDirectory = "/run/${runtimeDirectoryName}"; | ||
12 | # TODO: follow RFC 42, but we need a libconfuse format first: | ||
13 | # https://github.com/NixOS/nixpkgs/issues/401565 | ||
14 | # Arrays in `libconfuse` look like this: {"Life", "Universe", "Everything"} | ||
15 | # See https://www.nongnu.org/confuse/tutorial-html/ar01s03.html. | ||
16 | # | ||
17 | # Note: We're using `builtins.toJSON` to escape strings, but JSON strings | ||
18 | # don't have exactly the same semantics as libconfuse strings. For example, | ||
19 | # "${F}" gets treated as an env var reference, see above issue for details. | ||
20 | libconfuseDomains = "{ " + lib.concatMapStringsSep ", " builtins.toJSON cfg.domains + " }"; | ||
21 | configFile = pkgs.writeText "postsrsd.conf" '' | ||
22 | secrets-file = "''${CREDENTIALS_DIRECTORY}/secrets-file" | ||
23 | domains = ${libconfuseDomains} | ||
24 | separator = "${cfg.separator}" | ||
25 | |||
26 | # Disable postsrsd's jailing in favor of confinement with systemd. | ||
27 | unprivileged-user = "" | ||
28 | chroot-dir = "" | ||
29 | |||
30 | ${cfg.extraConfig} | ||
31 | ''; | ||
32 | |||
33 | in | ||
34 | { | ||
35 | imports = | ||
36 | map | ||
37 | ( | ||
38 | name: | ||
39 | lib.mkRemovedOptionModule [ "services" "postsrsd" name ] '' | ||
40 | `postsrsd` was upgraded to `>= 2.0.0`, with some different behaviors and configuration settings: | ||
41 | - NixOS Release Notes: https://nixos.org/manual/nixos/unstable/release-notes#sec-nixpkgs-release-25.05-incompatibilities | ||
42 | - NixOS Options Reference: https://nixos.org/manual/nixos/unstable/options#opt-services.postsrsd.enable | ||
43 | - Migration instructions: https://github.com/roehling/postsrsd/blob/2.0.10/README.rst#migrating-from-version-1x | ||
44 | - Postfix Setup: https://github.com/roehling/postsrsd/blob/2.0.10/README.rst#postfix-setup | ||
45 | '' | ||
46 | ) | ||
47 | [ | ||
48 | "domain" | ||
49 | "forwardPort" | ||
50 | "reversePort" | ||
51 | "timeout" | ||
52 | "excludeDomains" | ||
53 | ]; | ||
54 | |||
55 | disabledModules = [ "services/mail/postsrsd.nix" ]; | ||
56 | |||
57 | options = { | ||
58 | services.postsrsd = { | ||
59 | enable = lib.mkOption { | ||
60 | type = lib.types.bool; | ||
61 | default = false; | ||
62 | description = "Whether to enable the postsrsd SRS server for Postfix."; | ||
63 | }; | ||
64 | |||
65 | secretsFile = lib.mkOption { | ||
66 | type = lib.types.path; | ||
67 | default = "/var/lib/postsrsd/postsrsd.secret"; | ||
68 | description = "Secret keys used for signing and verification"; | ||
69 | }; | ||
70 | |||
71 | domains = lib.mkOption { | ||
72 | type = lib.types.listOf lib.types.str; | ||
73 | description = "Domain names for rewrite"; | ||
74 | default = [ config.networking.hostName ]; | ||
75 | defaultText = lib.literalExpression "[ config.networking.hostName ]"; | ||
76 | }; | ||
77 | |||
78 | separator = lib.mkOption { | ||
79 | type = lib.types.enum [ | ||
80 | "-" | ||
81 | "=" | ||
82 | "+" | ||
83 | ]; | ||
84 | default = "="; | ||
85 | description = "First separator character in generated addresses"; | ||
86 | }; | ||
87 | |||
88 | user = lib.mkOption { | ||
89 | type = lib.types.str; | ||
90 | default = "postsrsd"; | ||
91 | description = "User for the daemon"; | ||
92 | }; | ||
93 | |||
94 | group = lib.mkOption { | ||
95 | type = lib.types.str; | ||
96 | default = "postsrsd"; | ||
97 | description = "Group for the daemon"; | ||
98 | }; | ||
99 | |||
100 | extraConfig = lib.mkOption { | ||
101 | type = lib.types.lines; | ||
102 | default = ""; | ||
103 | }; | ||
104 | }; | ||
105 | }; | ||
106 | |||
107 | config = lib.mkIf cfg.enable { | ||
108 | users.users = lib.optionalAttrs (cfg.user == "postsrsd") { | ||
109 | postsrsd = { | ||
110 | group = cfg.group; | ||
111 | uid = config.ids.uids.postsrsd; | ||
112 | }; | ||
113 | }; | ||
114 | |||
115 | users.groups = lib.optionalAttrs (cfg.group == "postsrsd") { | ||
116 | postsrsd.gid = config.ids.gids.postsrsd; | ||
117 | }; | ||
118 | |||
119 | systemd.services.postsrsd-generate-secrets = { | ||
120 | path = [ pkgs.coreutils ]; | ||
121 | script = '' | ||
122 | if [ -e "${cfg.secretsFile}" ]; then | ||
123 | echo "Secrets file exists. Nothing to do!" | ||
124 | else | ||
125 | echo "WARNING: secrets file not found, autogenerating!" | ||
126 | DIR="$(dirname "${cfg.secretsFile}")" | ||
127 | install -m 750 -o ${cfg.user} -g ${cfg.group} -d "$DIR" | ||
128 | install -m 600 -o ${cfg.user} -g ${cfg.group} <(dd if=/dev/random bs=18 count=1 | base64) "${cfg.secretsFile}" | ||
129 | fi | ||
130 | ''; | ||
131 | serviceConfig = { | ||
132 | Type = "oneshot"; | ||
133 | }; | ||
134 | }; | ||
135 | |||
136 | systemd.services.postsrsd = { | ||
137 | description = "PostSRSd SRS rewriting server"; | ||
138 | after = [ | ||
139 | "network.target" | ||
140 | "postsrsd-generate-secrets.service" | ||
141 | ]; | ||
142 | before = [ "postfix.service" ]; | ||
143 | wantedBy = [ "multi-user.target" ]; | ||
144 | requires = [ "postsrsd-generate-secrets.service" ]; | ||
145 | confinement.enable = true; | ||
146 | |||
147 | serviceConfig = { | ||
148 | ExecStart = "${lib.getExe pkgs.postsrsd} -C ${configFile}"; | ||
149 | User = cfg.user; | ||
150 | Group = cfg.group; | ||
151 | PermissionsStartOnly = true; | ||
152 | RuntimeDirectory = runtimeDirectoryName; | ||
153 | LoadCredential = "secrets-file:${cfg.secretsFile}"; | ||
154 | }; | ||
155 | }; | ||
156 | }; | ||
157 | } | ||