about summary refs log tree commit diff stats
path: root/tests/by-name/em/email-dns/nodes/name_server.nix
diff options
context:
space:
mode:
Diffstat (limited to 'tests/by-name/em/email-dns/nodes/name_server.nix')
-rw-r--r--tests/by-name/em/email-dns/nodes/name_server.nix292
1 files changed, 292 insertions, 0 deletions
diff --git a/tests/by-name/em/email-dns/nodes/name_server.nix b/tests/by-name/em/email-dns/nodes/name_server.nix
new file mode 100644
index 0000000..bde1a16
--- /dev/null
+++ b/tests/by-name/em/email-dns/nodes/name_server.nix
@@ -0,0 +1,292 @@
+{extraModules}: {
+  config,
+  lib,
+  nodes,
+  pkgs,
+  ...
+}: let
+  keyAlgoToKeyType = keyAlgo:
+    if keyAlgo == "ed25519-sha256"
+    then "ed25519"
+    else if keyAlgo == "rsa-sha-256" || keyAlgo == "rsa-sha-1"
+    then "rsa"
+    else builtins.throw "Impossible";
+
+  mkZone = user: nodes: lib: cfg: {
+    SOA = {
+      nameServer = "ns.server.com";
+      adminEmail = "${user}@${user}.com";
+      serial = 2024012301;
+    };
+
+    MX = [
+      {
+        preference = 10;
+        exchange = "${cfg.fqdn}.";
+      }
+    ];
+
+    # https://www.rfc-editor.org/rfc/rfc8461.html#section-3.1
+    # Also see the policy in the hmtl part.
+    MTA-STS = [
+      {
+        id = "20250228Z";
+      }
+    ];
+
+    # https://www.rfc-editor.org/rfc/rfc7208.html
+    # https://en.wikipedia.org/wiki/Sender_Policy_Framework
+    TXT = [
+      (builtins.concatStringsSep " "
+        [
+          "v=spf1" # The version.
+          "+mx" # Allow mail from this domain MX record.
+          "-all" # Reject all other emails if the previous mechanism did not match.
+        ])
+    ];
+
+    # https://www.rfc-editor.org/rfc/rfc6376.html#section-3.6.1
+    # https://www.rfc-editor.org/rfc/rfc6376.html#section-7.5
+    DKIM = [
+      {
+        selector = "mail";
+        k = keyAlgoToKeyType cfg.security.dkimKeys."${user}.com".keyAlgorithm;
+        p = cfg.security.dkimKeys."${user}.com".dkimPublicKey;
+        s = ["email"];
+        t = ["s"];
+      }
+    ];
+
+    # https://www.rfc-editor.org/rfc/rfc7489.html#section-6.3
+    DMARC = [
+      {
+        adkim = "strict";
+        aspf = "strict";
+        fo = ["0" "1" "d" "s"];
+        p = "reject";
+        rua = cfg.admin;
+        ruf = [cfg.admin];
+      }
+    ];
+
+    A = [
+      nodes.${user}.networking.primaryIPAddress
+    ];
+    AAAA = [
+      nodes.${user}.networking.primaryIPv6Address
+    ];
+  };
+  mkServerZone = serverName: nodes: lib: let
+    cfg = nodes."${serverName}_server".vhack.stalwart-mail;
+  in {
+    SOA = {
+      nameServer = "ns.server.com";
+      adminEmail = "admin@server.com";
+      serial = 2024012301;
+    };
+    MX = [
+      {
+        preference = 10;
+        exchange = "${serverName}.server.com.";
+      }
+    ];
+
+    # https://www.rfc-editor.org/rfc/rfc6376.html#section-3.6.1
+    # https://www.rfc-editor.org/rfc/rfc6376.html#section-7.5
+    DKIM = [
+      {
+        selector = "mail";
+        k = keyAlgoToKeyType cfg.security.dkimKeys."${serverName}.server.com".keyAlgorithm;
+        p = cfg.security.dkimKeys."${serverName}.server.com".dkimPublicKey;
+        s = ["email"];
+        t = ["s"];
+      }
+    ];
+
+    # https://www.rfc-editor.org/rfc/rfc7489.html#section-6.3
+    DMARC = [
+      {
+        adkim = "strict";
+        aspf = "strict";
+        fo = ["0" "1" "d" "s"];
+        p = "quarantine";
+        rua = cfg.admin;
+        ruf = [cfg.admin];
+      }
+    ];
+
+    # https://www.rfc-editor.org/rfc/rfc7208.html
+    # NOTE(@bpeetz): This server might not be directly sending mail, but it is still required for
+    # the SMTP EHLO check. <2025-02-25>
+    TXT = [
+      (builtins.concatStringsSep " "
+        [
+          "v=spf1" # The version.
+          "+mx" # Allow mail from this domain MX record.
+          "-all" # Reject all other emails if the previous mechanism did not match.
+        ])
+    ];
+
+    A = [
+      nodes."${serverName}_server".networking.primaryIPAddress
+    ];
+    AAAA = [
+      nodes."${serverName}_server".networking.primaryIPv6Address
+    ];
+  };
+in {
+  imports =
+    extraModules
+    ++ [
+      ../../../../../modules
+      ../../../../common/acme/client.nix
+      ../../../../common/dns/server.nix
+    ];
+
+  services.nginx = {
+    logError = "stderr debug";
+    virtualHosts = let
+      mkStsHost = mx: {
+        forceSSL = true;
+        enableACME = true;
+        root = pkgs.runCommandLocal "mkPolicy" {} ''
+          mkdir --parents $out/.well-known/
+
+          # https://www.rfc-editor.org/rfc/rfc8461.html#section-3.2
+          cat << EOF > $out/.well-known/mta-sts.txt
+          version: STSv1
+          mode: enforce
+          mx: ${mx}
+          max_age: 604800
+          EOF
+        '';
+      };
+    in {
+      "mta-sts.alice.com" = mkStsHost "mail2.server.com";
+      "mta-sts.bob.com" = mkStsHost "mail1.server.com";
+    };
+  };
+
+  vhack = {
+    nginx = {
+      enable = true;
+    };
+    dns.zones = let
+      stsZone = {
+        SOA = {
+          nameServer = "ns";
+          adminEmail = "admin@server.com";
+          serial = 2025012301;
+        };
+
+        useOrigin = false;
+
+        A = [
+          nodes.name_server.networking.primaryIPAddress
+        ];
+        AAAA = [
+          nodes.name_server.networking.primaryIPv6Address
+        ];
+      };
+    in {
+      "arpa" = {
+        SOA = {
+          nameServer = "ns";
+          adminEmail = "admin@server.com";
+          serial = 2025012301;
+        };
+        useOrigin = false;
+
+        PTR = [
+          {
+            name = "acme.test";
+            ip.v4 = nodes.acme.networking.primaryIPAddress;
+          }
+          {
+            name = "acme.test";
+            ip.v6 = nodes.acme.networking.primaryIPv6Address;
+          }
+
+          {
+            name = "alice.com";
+            ip.v4 = nodes.alice.networking.primaryIPAddress;
+          }
+          {
+            name = "alice.com";
+            ip.v6 = nodes.alice.networking.primaryIPv6Address;
+          }
+
+          {
+            name = "bob";
+            ip.v4 = nodes.bob.networking.primaryIPAddress;
+          }
+          {
+            name = "bob";
+            ip.v6 = nodes.bob.networking.primaryIPv6Address;
+          }
+
+          {
+            name = "mail1.server.com";
+            ip.v4 = nodes.mail1_server.networking.primaryIPAddress;
+          }
+          {
+            name = "mail1.server.com";
+            ip.v6 = nodes.mail1_server.networking.primaryIPv6Address;
+          }
+
+          {
+            name = "mail2.server.com";
+            ip.v4 = nodes.mail2_server.networking.primaryIPAddress;
+          }
+          {
+            name = "mail2.server.com";
+            ip.v6 = nodes.mail2_server.networking.primaryIPv6Address;
+          }
+
+          {
+            name = "ns.server.com";
+            ip.v4 = nodes.name_server.networking.primaryIPAddress;
+          }
+          {
+            name = "ns.server.com";
+            ip.v6 = nodes.name_server.networking.primaryIPv6Address;
+          }
+        ];
+      };
+
+      "alice.com" = mkZone "alice" nodes lib nodes.mail2_server.vhack.stalwart-mail;
+      "mta-sts.alice.com" = stsZone;
+      "bob.com" = mkZone "bob" nodes lib nodes.mail1_server.vhack.stalwart-mail;
+      "mta-sts.bob.com" = stsZone;
+      "mail1.server.com" = mkServerZone "mail1" nodes lib;
+      "mail2.server.com" = mkServerZone "mail2" nodes lib;
+      "ns.server.com" = {
+        SOA = {
+          nameServer = "ns";
+          adminEmail = "admin@server.com";
+          serial = 2025012301;
+        };
+        useOrigin = false;
+
+        A = [
+          nodes.name_server.networking.primaryIPAddress
+        ];
+        AAAA = [
+          nodes.name_server.networking.primaryIPv6Address
+        ];
+      };
+      "server.com" = {
+        SOA = {
+          nameServer = "ns";
+          adminEmail = "admin@server.com";
+          serial = 2025012301;
+        };
+
+        useOrigin = false;
+        NS = [
+          "ns.server.com."
+        ];
+      };
+    };
+  };
+}