From 24a3b1a96e167b809d634878d016a729969278c0 Mon Sep 17 00:00:00 2001
From: Martin Fischer <martin@push-f.com>
Date: Fri, 27 Dec 2024 17:55:29 +0100
Subject: feat(shared): add vpn

---
 nixos/hosts/hamac/default.nix          |  1 +
 nixos/lib.nix                          | 12 +++++++++
 nixos/npins/sources.json               | 15 +++++++++++
 nixos/profiles/common/default.nix      |  4 +++
 nixos/profiles/workstation/default.nix | 12 +++++++--
 nixos/secrets/secrets.nix              | 10 ++++++++
 nixos/secrets/vpn-se-presharedKey.age  | 14 +++++++++++
 nixos/secrets/vpn-se-privKey.age       | 11 ++++++++
 nixos/shared/vpn.nix                   | 46 ++++++++++++++++++++++++++++++++++
 9 files changed, 123 insertions(+), 2 deletions(-)
 create mode 100644 nixos/lib.nix
 create mode 100644 nixos/secrets/secrets.nix
 create mode 100644 nixos/secrets/vpn-se-presharedKey.age
 create mode 100644 nixos/secrets/vpn-se-privKey.age
 create mode 100644 nixos/shared/vpn.nix

(limited to 'nixos')

diff --git a/nixos/hosts/hamac/default.nix b/nixos/hosts/hamac/default.nix
index 594d70c..d17b155 100644
--- a/nixos/hosts/hamac/default.nix
+++ b/nixos/hosts/hamac/default.nix
@@ -8,6 +8,7 @@
     ./hardware-configuration.nix
     <top/profiles/workstation>
     <top/shared/tailscale.nix>
+    <top/shared/vpn.nix>
   ];
 
   # Bootloader.
diff --git a/nixos/lib.nix b/nixos/lib.nix
new file mode 100644
index 0000000..a2d8193
--- /dev/null
+++ b/nixos/lib.nix
@@ -0,0 +1,12 @@
+let
+  nixpkgs = import <nixpkgs> {};
+in
+{
+  joinWgNamespace = ns: cfg:
+   nixpkgs.lib.attrsets.recursiveUpdate cfg {
+    bindsTo = ["netns@${ns}.service"];
+    after = ["wireguard-wg-${ns}.service"];
+    unitConfig.JoinsNamespaceOf = "netns@${ns}.service";
+    serviceConfig.NetworkNamespacePath = "/var/run/netns/${ns}";
+  };
+}
diff --git a/nixos/npins/sources.json b/nixos/npins/sources.json
index 11b78b9..1f29f63 100644
--- a/nixos/npins/sources.json
+++ b/nixos/npins/sources.json
@@ -11,6 +11,21 @@
       "name": "nixos-24.11-small",
       "url": "https://releases.nixos.org/nixos/24.11-small/nixos-24.11.710985.7db18b8ec24f/nixexprs.tar.xz",
       "hash": "1lf8xglp739v2r6kzjd1b3gjk9vx3r8ah05v38fcr5hqqwnk6423"
+    },
+    "agenix": {
+      "type": "GitRelease",
+      "repository": {
+        "type": "GitHub",
+        "owner": "ryantm",
+        "repo": "agenix"
+      },
+      "pre_releases": false,
+      "version_upper_bound": null,
+      "release_prefix": null,
+      "version": "0.15.0",
+      "revision": "564595d0ad4be7277e07fa63b5a991b3c645655d",
+      "url": "https://api.github.com/repos/ryantm/agenix/tarball/0.15.0",
+      "hash": "01dhrghwa7zw93cybvx4gnrskqk97b004nfxgsys0736823956la"
     }
   },
   "version": 3
diff --git a/nixos/profiles/common/default.nix b/nixos/profiles/common/default.nix
index de4499a..d1fe93e 100644
--- a/nixos/profiles/common/default.nix
+++ b/nixos/profiles/common/default.nix
@@ -1,8 +1,12 @@
 { config, pkgs, ... }:
 
+let
+  npins = import ../../npins;
+in
 {
   imports = [
     ./sanix.nix
     ./basics.nix
+    "${npins.agenix}/modules/age.nix"
   ];
 }
diff --git a/nixos/profiles/workstation/default.nix b/nixos/profiles/workstation/default.nix
index ddc9a8c..3be5c6c 100644
--- a/nixos/profiles/workstation/default.nix
+++ b/nixos/profiles/workstation/default.nix
@@ -1,5 +1,8 @@
 { config, pkgs, ... }:
 
+let
+  npins = import ../../npins;
+in
 {
   imports = [
     ../common
@@ -9,12 +12,17 @@
     ./create.nix
   ];
 
-  environment.systemPackages = with pkgs; [
-    npins
+  environment.systemPackages = [
+    pkgs.npins
+    (pkgs.callPackage "${npins.agenix}/pkgs/agenix.nix" {})
   ];
 
   environment.sessionVariables = {
     # Tell .zshrc to source zshrc-workstation.sh.
     MYNIX_PROFILE = "workstation";
   };
+
+  # Age defaults to this anyway when openssh is enabled.
+  # We're setting this here for workstations where openssh is disabled.
+  age.identityPaths = ["/etc/ssh/ssh_host_ed25519_key"];
 }
diff --git a/nixos/secrets/secrets.nix b/nixos/secrets/secrets.nix
new file mode 100644
index 0000000..db19967
--- /dev/null
+++ b/nixos/secrets/secrets.nix
@@ -0,0 +1,10 @@
+let
+  martin = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICRBAAt77GXrDtIp6fSjeMHCV3e1ujCE0meetqX3YZpn";
+
+  hamac = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJmjbC0gk2s/qDQ+QR//GJH0ZPld99L0EtX7dPP5h2RN";
+  ev = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINCSypbTOnAYBO32vUUieOsb6ws32gCsDg8nB8JhuFuI";
+in
+{
+  "vpn-se-privKey.age".publicKeys = [ martin hamac ev ];
+  "vpn-se-presharedKey.age".publicKeys = [ martin hamac ev ];
+}
diff --git a/nixos/secrets/vpn-se-presharedKey.age b/nixos/secrets/vpn-se-presharedKey.age
new file mode 100644
index 0000000..1f56d86
--- /dev/null
+++ b/nixos/secrets/vpn-se-presharedKey.age
@@ -0,0 +1,14 @@
+age-encryption.org/v1
+-> ssh-ed25519 0iFcGg 33qVwdJ+x5d9ezpvYayjZqrwAZQDb7AxvOjQucyVYgQ
+z5/tRvXEE+xSJ4BKQORu4yI+UG2GNaKdTZe0FkN4VyY
+-> ssh-ed25519 zNg/mg 9rug5AzVUH/fIDvtSVA0SZkQ0tR+T59VY2UYPrxZfFM
+g49jKdkf+tz/sl9g/RdfkRv/CKneO04rkXPprQYv9rw
+-> ssh-ed25519 PHC5tQ H9j903SKpztlrUN/nP7Q8Io/iJLY8ka6aBlOc4d/+iA
+hfQIpLuvT2D8eo5T0MmydivcQE7DFbHhLO809YET0HI
+-> W}8>=-grease
+hy4mn+TGe6QPbZud+cppGmgzyed8SgVcaYBumJdxIRy6NQXW8PH2itg6GTIR6Npb
+Nhj9zeSsQvAq8no7z+Q5DsXI7o6iVUDgvoQ1HcUan7WYGqR5MA0
+--- WbaGYSFVrJ8+YgzYeLaLXfOsCDMMruUpmFtKvtym57E
+�I���k�"�a#L�!���1\:
+�=.�+$@���]��.Hn�d����]U�/�q-�~��-�T��������
+�
\ No newline at end of file
diff --git a/nixos/secrets/vpn-se-privKey.age b/nixos/secrets/vpn-se-privKey.age
new file mode 100644
index 0000000..93de475
--- /dev/null
+++ b/nixos/secrets/vpn-se-privKey.age
@@ -0,0 +1,11 @@
+age-encryption.org/v1
+-> ssh-ed25519 0iFcGg KyKfFePFWpX9AOPw5Sy9UQkucPsQDwrEwRL66e3wdA4
+7DNSkNroD1HaRld0M5uMWtu7dojKUB7DPU9hdTPCXZ8
+-> ssh-ed25519 zNg/mg Y0w7MCgwQKqb8FurFOyEshSmfCNoIKi0OnOJUsDeh14
+xILssj5y6XbZ10b39MqqhN42DRQt1AKIdh/Eidin8dA
+-> ssh-ed25519 PHC5tQ nfW6lDN4vrv5EOCZGmfe9LEto5FDbU9Vh1LOvrnpvR0
+KrGBpZh7+DalPFoM0rW6ylehDnrmCz2JAOKqMEN4BoQ
+-> k4]AeAV-grease pSemvkw @C;y
+vBW8ETA
+--- 8Eel9tqXmZ3s7J1CqXlCMTOPAHWD/ftxB7t2DRtHi4A
+�T›{vg�������m����W�e����	5Yxr嶘v�}	�]��MCM�b�HA��Z�?�\H�l'L,���
\ No newline at end of file
diff --git a/nixos/shared/vpn.nix b/nixos/shared/vpn.nix
new file mode 100644
index 0000000..44a4f2c
--- /dev/null
+++ b/nixos/shared/vpn.nix
@@ -0,0 +1,46 @@
+{ config, pkgs, ... }:
+
+{
+  age.secrets.vpn-se-privKey.file = ../secrets/vpn-se-privKey.age;
+  age.secrets.vpn-se-presharedKey.file = ../secrets/vpn-se-presharedKey.age;
+
+  # We're creating the wireguard interfaces in network namespaces so that
+  # we can use them on demand:
+  # * for a command by prefixing it with `sudo ip netns exec <ns>`
+  # * for a systemd service by passing its config to joinWgNamespace from lib.nix
+
+  networking.wireguard = {
+    enable = true;
+
+    interfaces.wg-se = {
+      interfaceNamespace = "se";
+      ips = ["10.148.171.71/32"];
+      privateKeyFile = config.age.secrets.vpn-se-privKey.path;
+
+      peers = [
+        {
+          publicKey = "PyLCXAQT8KkM4T+dUsOQfn+Ub3pGxfGlxkIApuig+hk=";
+          presharedKeyFile = config.age.secrets.vpn-se-presharedKey.path;
+          allowedIPs = ["0.0.0.0/0"];
+          endpoint = "se3.vpn.airdns.org:1637";
+        }
+      ];
+    };
+  };
+
+  systemd.services = {
+    # The interfaceNamespace configured for the wireguard interface needs to already exist.
+    # So we define a service to create it and add a `wants` dependency.
+    "netns@" = {
+      description = "%I network namespace";
+      before = ["network.target"];
+      serviceConfig = {
+        Type = "oneshot";
+        RemainAfterExit = true;
+        ExecStart = "${pkgs.iproute2}/bin/ip netns add %I";
+        ExecStop = "${pkgs.iproute2}/bin/ip netns del %I";
+      };
+    };
+    wireguard-wg-se.wants = ["netns@se.service"];
+  };
+}
-- 
cgit v1.2.3