summary refs log tree commit diff
path: root/modules
diff options
context:
space:
mode:
authorMel <mel@rnrd.eu>2026-05-01 18:40:37 +0200
committerMel <mel@rnrd.eu>2026-05-01 18:40:37 +0200
commita4ab740d07706d86503b84d36addcbbbf7a4944b (patch)
tree24c52a29b9a3182149db37e332bee3af9b9f6014 /modules
parentc9f2260dc0414d451d551f8ffdf1f573e7be41ff (diff)
downloadnetwork-a4ab740d07706d86503b84d36addcbbbf7a4944b.tar.zst
network-a4ab740d07706d86503b84d36addcbbbf7a4944b.zip
Re-add simple VPN and simplify module with shared users with tunnel
Signed-off-by: Mel <mel@rnrd.eu>
Diffstat (limited to 'modules')
-rw-r--r--modules/foundation/default.nix1
-rw-r--r--modules/foundation/vpn.nix90
-rw-r--r--modules/tunnel/definition.nix31
-rw-r--r--modules/tunnel/ingress.nix6
4 files changed, 95 insertions, 33 deletions
diff --git a/modules/foundation/default.nix b/modules/foundation/default.nix
index 3905eb8..fa84750 100644
--- a/modules/foundation/default.nix
+++ b/modules/foundation/default.nix
@@ -6,5 +6,6 @@
     ./services
     ./monitoring
     ./www
+    ./vpn.nix
   ];
 }
diff --git a/modules/foundation/vpn.nix b/modules/foundation/vpn.nix
new file mode 100644
index 0000000..1a7524d
--- /dev/null
+++ b/modules/foundation/vpn.nix
@@ -0,0 +1,90 @@
+{
+  config,
+  lib,
+  ...
+}:
+
+let
+  inherit (lib)
+    mkEnableOption
+    mkOption
+    types
+    mkIf
+    attrValues
+    replaceString
+    ;
+
+  cfg = config.foundation.vpn;
+
+  inherit (import ../../assets/vpn.nix) users;
+
+  interface = "vpn0";
+  port = 51820;
+
+  # while the tunnel uses the lower subnets for the paths,
+  # the vpn always uses subnet number 10.
+  subnetIndex = 10;
+
+  addressFromTemplate =
+    template: prefix: "${replaceString "X" (toString subnetIndex) template}/${toString prefix}";
+in
+{
+  options.foundation.vpn = {
+    enable = mkEnableOption "WireGuard VPN server";
+
+    externalInterface = mkOption {
+      type = types.str;
+      description = "External network interface";
+    };
+  };
+
+  config = mkIf cfg.enable {
+    age.secrets.wg-private-key = {
+      file = ../../secrets/wg-private-key.age;
+      owner = "systemd-network";
+    };
+
+    networking.firewall.allowedUDPPorts = [ port ];
+
+    systemd.network = {
+      netdevs."30-${interface}" = {
+        netdevConfig = {
+          Kind = "wireguard";
+          Name = interface;
+        };
+        wireguardConfig = {
+          PrivateKeyFile = config.age.secrets.wg-private-key.path;
+          ListenPort = port;
+        };
+        wireguardPeers = map (user: {
+          PublicKey = user.key;
+          AllowedIPs = [ (addressFromTemplate user.ip 32) ];
+        }) (attrValues users);
+      };
+
+      networks."30-${interface}" = {
+        name = interface;
+        address = [ (addressFromTemplate "10.123.X.1" 24) ];
+        linkConfig = {
+          RequiredForOnline = "no";
+        };
+      };
+    };
+
+    networking.nftables.tables.vpn-nat = {
+      family = "ip";
+      content = ''
+        chain postrouting {
+          type nat hook postrouting priority srcnat; policy accept;
+          iifname "${interface}" oifname "${cfg.externalInterface}" masquerade
+        }
+
+        chain forward {
+          type filter hook forward priority 0; policy accept;
+          iifname "${interface}" oifname "${cfg.externalInterface}" accept
+          iifname "${cfg.externalInterface}" oifname "${interface}" ct state established,related accept
+        }
+      '';
+    };
+  };
+}
diff --git a/modules/tunnel/definition.nix b/modules/tunnel/definition.nix
index 74ae268..82534bf 100644
--- a/modules/tunnel/definition.nix
+++ b/modules/tunnel/definition.nix
@@ -36,40 +36,11 @@
     }
   ];
 
-  # there are our users who are allowed to connect to any of our "paths".
-  # their ip is always a template, with 'X' representing the path index.
-  users = {
-    mel = {
-      key = "vnZoHXapCLLUhZ8A8R5W0iJ8LpWVLve29z41kkoT0BU=";
-      ip = "10.123.X.101";
-    };
-
-    andrei = {
-      key = "qqU4uYImLfUohIwl4KBshPtTINFcs0JVALjbmwpfxRg=";
-      ip = "10.123.X.102";
-    };
-
-    sergo = {
-      key = "qbZGMNIDZFCJC6SHtlyNIlIdGWHELceXClJCcagrj2Y=";
-      ip = "10.123.X.103";
-    };
-
-    fedor = {
-      key = "tEO9r8+jTpu8TBRmZ+/v087IgD/QfmofLUKs249i/F0=";
-      ip = "10.123.X.104";
-    };
-  };
+  inherit (import ../../assets/vpn.nix) users;
 
   # we use a website as a "mask" for vless/reality, which will tell our peers
   # to pretend as if they're a user and a well-known website communicating with
   # each other, even though they know that the keys don't actually match up,
   # it's not possible to see that on the outside.
   mask = "microsoft.com";
-
-  # we don't actually need this to configure the tunnel, but this is
-  # the public key of the ingress interface.
-  # when creating wireguard vpn configurations for the users, this
-  # is the public key of the server peer at `tunnel.rnrd.eu`.
-  # the matching private key of the pair is the secret `tunnel/ingress-key`.
-  ingress.public = "s5yyPCJiN0uqW0jzKIbYCF7I9TthymiRzpNt466XeWk=";
 }
diff --git a/modules/tunnel/ingress.nix b/modules/tunnel/ingress.nix
index 1ea1613..f609f3d 100644
--- a/modules/tunnel/ingress.nix
+++ b/modules/tunnel/ingress.nix
@@ -38,8 +38,8 @@ in
     checkReversePath = "loose";
   };
 
-  age.secrets.ingress-key = {
-    file = ../../secrets/tunnel/ingress-key.age;
+  age.secrets.wg-private-key = {
+    file = ../../secrets/wg-private-key.age;
     owner = "systemd-network";
   };
 
@@ -52,7 +52,7 @@ in
             Name = ingressName index;
           };
           wireguardConfig = {
-            PrivateKeyFile = config.age.secrets.ingress-key.path;
+            PrivateKeyFile = config.age.secrets.wg-private-key.path;
             ListenPort = path.port;
           };
           wireguardPeers = map (user: {