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.nix320
1 files changed, 320 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..ef657f4
--- /dev/null
+++ b/tests/by-name/em/email-dns/nodes/name_server.nix
@@ -0,0 +1,320 @@
+{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 = "quarantine";
+        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
+      ./acme/client.nix
+    ];
+
+  networking.nameservers = lib.mkForce [
+    nodes.name_server.networking.primaryIPAddress
+    nodes.name_server.networking.primaryIPv6Address
+  ];
+
+  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 = {
+      enable = true;
+      openFirewall = true;
+      interfaces = [
+        nodes.name_server.networking.primaryIPAddress
+        nodes.name_server.networking.primaryIPv6Address
+      ];
+
+      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
+          ];
+        };
+        "acme.test" = {
+          SOA = {
+            nameServer = "ns";
+            adminEmail = "admin@server.com";
+            serial = 2025012301;
+          };
+          useOrigin = false;
+
+          A = [
+            nodes.acme.networking.primaryIPAddress
+          ];
+          AAAA = [
+            nodes.acme.networking.primaryIPv6Address
+          ];
+        };
+        "server.com" = {
+          SOA = {
+            nameServer = "ns";
+            adminEmail = "admin@server.com";
+            serial = 2025012301;
+          };
+
+          useOrigin = false;
+          NS = [
+            "ns.server.com."
+          ];
+        };
+      };
+    };
+  };
+}