@cryptotaxi247 / infra-1 / commits / 8de80a51

fix(mailserver): enable Sender Rewriting Scheme (SRS) on umbriel

We had deliverability issues when forwarding mail to other domains (if the domain of the email we were forwarding had a strict SPF policy, the receiving mailserver would drop it due to SPF fail). See https://github.com/NixOS/infra/issues/485#issuecomment-2787490679 for details.

Jeremy Fleischman committed Apr 9, 2025 at 03:21 UTC 8de80a51c6b9bff9b632916d32b4b54b75035f75
3 files changed +69
non-critical-infra/modules/mailserver/default.nix
+1
@@ -3,6 +3,7 @@
3 {
4 imports = [
5 ./mailing-lists.nix
6 + ./postsrsd.nix
7 ];
8
9 mailserver = {
non-critical-infra/modules/mailserver/postsrsd.nix new
+40
@@ -0,0 +1,40 @@
1 +{ config, ... }:
2 +# We use `postsrsd` to enable Sender Rewriting Scheme (SRS) so mail we forward
3 +# to another domain does not fail SPF. See
4 +# https://github.com/NixOS/infra/issues/485#issuecomment-2787490679 for
5 +# details.
6 +{
7 + services.postsrsd = {
8 + enable = true;
9 + domain = "nixos.org";
10 + secretsFile = config.sops.secrets.postsrsd-secret.path;
11 + };
12 +
13 + # Configure postfix as per
14 + # https://github.com/roehling/postsrsd?tab=readme-ov-file#postfix-setup
15 + services.postfix.config = {
16 + # TODO: switch to "socketmap:unix:/run/postsrsd/socket:forward" once
17 + # postsrsd 2 is available: https://github.com/NixOS/nixpkgs/pull/397316
18 + sender_canonical_maps = "tcp:127.0.0.1:${builtins.toString config.services.postsrsd.forwardPort}";
19 + sender_canonical_classes = "envelope_sender";
20 +
21 + # TODO: switch to "socketmap:unix:/run/postsrsd/socket:forward" once
22 + # postsrsd 2 is available: https://github.com/NixOS/nixpkgs/pull/397316
23 + recipient_canonical_maps = "tcp:127.0.0.1:${builtins.toString config.services.postsrsd.reversePort}";
24 + recipient_canonical_classes = "envelope_recipient, header_recipient";
25 + };
26 +
27 + # ```
28 + # How to generate:
29 + #
30 + # ```console
31 + # cd non-critical-infra
32 + # SECRET_PATH=secrets/postsrsd-secret.umbriel
33 + # dd if=/dev/random bs=18 count=1 status=none | base64 > "$SECRET_PATH"
34 + # sops encrypt --in-place "$SECRET_PATH"
35 + # ```
36 + sops.secrets.postsrsd-secret = {
37 + format = "binary";
38 + sopsFile = ../../secrets/postsrsd-secret.umbriel;
39 + };
40 +}
non-critical-infra/secrets/postsrsd-secret.umbriel new
+28
@@ -0,0 +1,28 @@
1 +{
2 + "data": "ENC[AES256_GCM,data:Oy/Lqq1DTXVX0SK0pJOa6fJhf9H3Qi2G3w==,iv:JG2o4C9EjBbt4PqrE3kHPNabFbk2Ar3IHseQyrQxnP0=,tag:IRG+EYLebBDf99svFmcHWw==,type:str]",
3 + "sops": {
4 + "kms": null,
5 + "gcp_kms": null,
6 + "azure_kv": null,
7 + "hc_vault": null,
8 + "age": [
9 + {
10 + "recipient": "age15vcp7875xwtf64j4yshyld0a3hpgzv6n2kxky493s3q0swr9hdaqxugpv6",
11 + "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSArTmVPZGo0aXlsbklBZlEy\naXZ3SmcxNlN1WkowQUFuSkdSVGo0Q3BneGhZClliMnIvbUVnb1FyMWJEcXFxOTh5\neDNHMFN3NUw5bGMxcm5EUWpncnkxNnMKLS0tIDNVaXFJOGxQa2FUVUhYbVkrQ0Rp\nS3RmbElCUlUxdkNXblY1S2VSQnkrc2sKusUip4Vnr56lfiEAHRPqQiZjb91rovLA\nQhPCz/LwTyxDDMTsq1dNbasniqeErmUfUfK792HqigBo2qXbsk4bjw==\n-----END AGE ENCRYPTED FILE-----\n"
12 + },
13 + {
14 + "recipient": "age1j3mkgedmeru63vwww6m44zfw09tg8yw6xdzstaq7ejfkvgcau40qwakm8x",
15 + "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBBY3gzUU1WSk92QTBFNlFU\nbVhLamEybkZUYWs4U3FPYWJFSTQybXlkK2pRCjhBdUlOVEVsMkhlbUJFbEVnbS9u\nN1VuV0xpTzdQVk1zMURyb0VQTHVMWVUKLS0tIFkzdmNtMmgxajVRQlNiTTFzTnY4\nMGdZcVpGRkRLQVVSMHJ1QlZjUm9halkKnTU4dXWpYOj4GLuyoNvz90uarPbn5CBR\nfiIXd7QPQl2+3SstC8KrxXSvRx2DmxR+imtPRvqGEf7EaspXpfy1UQ==\n-----END AGE ENCRYPTED FILE-----\n"
16 + },
17 + {
18 + "recipient": "age1jrh8yyq3swjru09s75s4mspu0mphh7h6z54z946raa9wx3pcdegq0x8t4h",
19 + "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBSRUY3M0haTkV1RTlUbnpi\nNk9WNU5OTkR6dVozUTJKbzhmVXJRSlJxMG1FCmUwWTJmbm12UDNmSG0rdThVekRw\nWk1sOUFLUFlzMW0vKy9IWW5HNmtDd2cKLS0tIFc3cjVLTEF3QVdaeG1Kck9KMm13\nS2pWZEpkUU5OaTJIYmNpZzIrRHdReGsKN15CghVCZmL5irAOuhewFIR1hL8YkT27\nwahQun20ahRiIkQRZxGWi1C9HJ/v4IVjwsTRYbM9BwIuopDQkofosw==\n-----END AGE ENCRYPTED FILE-----\n"
20 + }
21 + ],
22 + "lastmodified": "2025-04-09T10:20:42Z",
23 + "mac": "ENC[AES256_GCM,data:QhBJD/BaFKX16orijmxl/Oi/50d8iqBKR90QPOHgWSp+MYXfzArS/OLu8ZtZ/xwucW7pNh1oC+CGmMHTW1xrBpuMg6MQ5qyhedKjlINptYG/IIcqIkakulppOxw9LMuUWznXcDApd3w5SkMux63tO7vti0kWQ3Zv4A9XpmOXRCM=,iv:85o1/ucnYoKBc/2cCCr+TgrXCQinzX3vGYv5xzEaJmQ=,tag:dokOTNpd0aQMsvVX4MOxFg==,type:str]",
24 + "pgp": null,
25 + "unencrypted_suffix": "_unencrypted",
26 + "version": "3.9.4"
27 + }
28 +}
\ No newline at end of file