From 792217f64011a90fc94552de8e83c8249d907998 Mon Sep 17 00:00:00 2001 From: root Date: Sat, 28 Mar 2026 23:24:52 -0500 Subject: [PATCH 1/8] feat: add Nebula mesh network overlay Introduces a greg.nebula NixOS module and enables it across all managed hosts for the nebula.thehellings.com overlay (CIDR: 10.157.0.0/16). Architecture: - linode: lighthouse + relay (public internet, UDP 4242) - genesis: regular node + unsafe_routes router for 10.42.0.0/16 (home LAN) - hosea, isaiah, jeremiah, zeke, exodus: regular nodes with unsafe_routes pointing to genesis to reach the home LAN Changes: - modules/nixos/nebula.nix: new greg.nebula module - isLighthouse / isRelay options - unsafeRoutes option (tun.unsafe_routes) - routesSubnet option: enables IP forwarding + nftables masquerade NAT on the gateway host (genesis) so Nebula peers reach 10.42.0.0/16 - agenix secret reference per-host (secrets/nebula/.key.age) - opens UDP/4242 in the firewall - modules/nixos/default.nix: import nebula.nix - hosts/unstable/linode/default.nix: greg.nebula.isLighthouse = true - hosts/unstable/genesis/default.nix: greg.nebula.routesSubnet = "10.42.0.0/16" - hosts/unstable/{hosea,isaiah,jeremiah,zeke,exodus}/default.nix: greg.nebula.enable = true with unsafeRoutes via genesis - network.json: add nebulaIp field for each managed host - secrets/secrets.nix: declare nebula/.key.age entries - secrets/nebula/README.md: full PKI bootstrap guide (CA, certs, agenix) --- hosts/unstable/exodus/default.nix | 9 ++ hosts/unstable/genesis/default.nix | 6 + hosts/unstable/hosea/default.nix | 9 ++ hosts/unstable/isaiah/default.nix | 9 ++ hosts/unstable/jeremiah/default.nix | 9 ++ hosts/unstable/linode/default.nix | 4 + hosts/unstable/zeke/default.nix | 9 ++ modules/nixos/default.nix | 1 + modules/nixos/nebula.nix | 222 ++++++++++++++++++++++++++++ network.json | 56 +++++-- secrets/nebula/.gitkeep | 8 + secrets/nebula/README.md | 109 ++++++++++++++ secrets/secrets.nix | 10 ++ 13 files changed, 451 insertions(+), 10 deletions(-) create mode 100644 modules/nixos/nebula.nix create mode 100644 secrets/nebula/.gitkeep create mode 100644 secrets/nebula/README.md diff --git a/hosts/unstable/exodus/default.nix b/hosts/unstable/exodus/default.nix index 81da8e4..900e6d4 100644 --- a/hosts/unstable/exodus/default.nix +++ b/hosts/unstable/exodus/default.nix @@ -30,6 +30,15 @@ greg = { home = true; gnome.enable = true; + nebula = { + enable = true; + unsafeRoutes = [ + { + route = "10.42.0.0/16"; + via = "10.157.0.2"; # genesis + } + ]; + }; podman.enable = true; print.enable = true; tailscale = { diff --git a/hosts/unstable/genesis/default.nix b/hosts/unstable/genesis/default.nix index 4b45663..58d0e2a 100644 --- a/hosts/unstable/genesis/default.nix +++ b/hosts/unstable/genesis/default.nix @@ -35,6 +35,12 @@ in greg = { home = true; gnome.enable = false; + nebula = { + enable = true; + # genesis routes the home LAN (10.42.0.0/16) into the Nebula overlay. + # Sign genesis's cert with -subnets '10.42.0.0/16' (see secrets/nebula/README.md). + routesSubnet = "10.42.0.0/16"; + }; proxies = { }; }; diff --git a/hosts/unstable/hosea/default.nix b/hosts/unstable/hosea/default.nix index a9a06a5..9cf088f 100644 --- a/hosts/unstable/hosea/default.nix +++ b/hosts/unstable/hosea/default.nix @@ -49,6 +49,15 @@ in greg = { home = true; + nebula = { + enable = true; + unsafeRoutes = [ + { + route = "10.42.0.0/16"; + via = "10.157.0.2"; # genesis + } + ]; + }; proxies = { "jellyfin.home".target = "http://localhost:8096/"; "jellyfin.thehellings.lan".target = "http://localhost:8096/"; diff --git a/hosts/unstable/isaiah/default.nix b/hosts/unstable/isaiah/default.nix index 8e52f61..29ac835 100644 --- a/hosts/unstable/isaiah/default.nix +++ b/hosts/unstable/isaiah/default.nix @@ -42,6 +42,15 @@ vip = metadata.hosts.${config.networking.hostName}.ip; priority = 255; }; + nebula = { + enable = true; + unsafeRoutes = [ + { + route = "10.42.0.0/16"; + via = "10.157.0.2"; # genesis + } + ]; + }; podman.enable = true; tailscale = { enable = true; diff --git a/hosts/unstable/jeremiah/default.nix b/hosts/unstable/jeremiah/default.nix index 90a3cd1..a2380a3 100644 --- a/hosts/unstable/jeremiah/default.nix +++ b/hosts/unstable/jeremiah/default.nix @@ -85,6 +85,15 @@ in vip = ip; priority = 254; }; + nebula = { + enable = true; + unsafeRoutes = [ + { + route = "10.42.0.0/16"; + via = "10.157.0.2"; # genesis + } + ]; + }; tailscale = { enable = true; tags = [ "home" ]; diff --git a/hosts/unstable/linode/default.nix b/hosts/unstable/linode/default.nix index 3c9cb84..b25127b 100644 --- a/hosts/unstable/linode/default.nix +++ b/hosts/unstable/linode/default.nix @@ -26,6 +26,10 @@ greg = { home = false; linode.enable = true; + nebula = { + enable = true; + isLighthouse = true; + }; proxies."immich.thehellings.com" = { genAliases = false; target = "http://localhost:${builtins.toString config.services.immich-public-proxy.port}"; diff --git a/hosts/unstable/zeke/default.nix b/hosts/unstable/zeke/default.nix index 37fae9e..5b94e3c 100644 --- a/hosts/unstable/zeke/default.nix +++ b/hosts/unstable/zeke/default.nix @@ -26,6 +26,15 @@ vipInterface = "enp12s0"; priority = 253; }; + nebula = { + enable = true; + unsafeRoutes = [ + { + route = "10.42.0.0/16"; + via = "10.157.0.2"; # genesis + } + ]; + }; remote-builder.enable = true; runner = { enable = true; diff --git a/modules/nixos/default.nix b/modules/nixos/default.nix index ed4359a..9296ee6 100644 --- a/modules/nixos/default.nix +++ b/modules/nixos/default.nix @@ -22,6 +22,7 @@ ./router.nix ./rpi4.nix ./syncthing.nix + ./nebula.nix ./tailscale.nix ./vmdev.nix ]; diff --git a/modules/nixos/nebula.nix b/modules/nixos/nebula.nix new file mode 100644 index 0000000..45fcd67 --- /dev/null +++ b/modules/nixos/nebula.nix @@ -0,0 +1,222 @@ +{ + config, + lib, + metadata, + ... +}: + +# Nebula overlay mesh network module (greg namespace) +# +# This module configures a Nebula node for the nebula.thehellings.com overlay. +# CIDR: 10.157.0.0/16 +# Lighthouse: linode (public internet, acts as relay too) +# +# Each host requires: +# secrets/nebula/.key.age - encrypted private key +# secrets/nebula/.crt - certificate (public, unencrypted in repo) +# secrets/nebula/ca.crt - CA certificate (public, unencrypted in repo) +# +# The nebula IP for each host must be set in network.json under +# hosts..nebulaIp (e.g. "10.157.0.1") +# +# Lighthouse address is the public IP/DNS of linode. Update the +# `lighthouseAddrs` option below or override per-host if it changes. + +let + cfg = config.greg.nebula; + nebulaDomain = "nebula.thehellings.com"; + # Linode's public address — used by all non-lighthouse hosts to reach it. + # Override with greg.nebula.lighthouseAddr if the public IP ever changes. + defaultLighthouseAddr = "linode.${nebulaDomain}"; +in +{ + options.greg.nebula = { + enable = lib.mkEnableOption "Nebula overlay mesh network"; + + isLighthouse = lib.mkOption { + type = lib.types.bool; + default = false; + description = "Whether this host is a Nebula lighthouse/relay node"; + }; + + isRelay = lib.mkOption { + type = lib.types.bool; + default = cfg.isLighthouse; + description = "Whether this host acts as a relay (am_relay). Defaults to true when isLighthouse is true."; + }; + + nebulaIp = lib.mkOption { + type = lib.types.str; + description = "This host's Nebula overlay IP (e.g. 10.157.0.1)"; + default = + let + hostData = metadata.hosts.${config.networking.hostName} or { }; + in + hostData.nebulaIp or (throw "greg.nebula.nebulaIp must be set for host ${config.networking.hostName}"); + }; + + lighthouseAddr = lib.mkOption { + type = lib.types.str; + default = defaultLighthouseAddr; + description = "Public address (host:port) used to reach the lighthouse from non-lighthouse hosts"; + }; + + lighthouseNebulaIp = lib.mkOption { + type = lib.types.str; + default = + let + linodeData = metadata.hosts.linode or { }; + in + linodeData.nebulaIp or "10.157.0.1"; + description = "Nebula overlay IP of the lighthouse host"; + }; + + port = lib.mkOption { + type = lib.types.port; + default = 4242; + description = "UDP port Nebula listens on"; + }; + + # unsafe_routes: allow non-Nebula subnets to be routed through this host. + # Used on genesis to expose 10.42.0.0/16 (the home LAN) to the overlay. + unsafeRoutes = lib.mkOption { + type = lib.types.listOf ( + lib.types.submodule { + options = { + route = lib.mkOption { + type = lib.types.str; + description = "CIDR to route through this host (e.g. 10.42.0.0/16)"; + }; + via = lib.mkOption { + type = lib.types.str; + description = "Nebula overlay IP of the host that provides the route"; + }; + }; + } + ); + default = [ ]; + description = "List of unsafe_routes to configure on this host (for reaching non-Nebula subnets)"; + }; + + # Whether this host IS the router for an unsafe subnet + # (enables IP forwarding + nftables masquerade for the home LAN) + routesSubnet = lib.mkOption { + type = lib.types.nullOr lib.types.str; + default = null; + description = '' + When set, this host will route traffic from the Nebula overlay + to this subnet. Enables IP forwarding and nftables masquerade. + Example: "10.42.0.0/16" + ''; + }; + }; + + config = lib.mkIf cfg.enable { + # agenix: decrypt this host's Nebula private key at boot + age.secrets."nebula-${config.networking.hostName}-key" = { + file = ../../secrets/nebula/${config.networking.hostName}.key.age; + # nebula service runs as root, key owned by root is fine + mode = "0400"; + }; + + services.nebula.networks.${nebulaDomain} = { + enable = true; + + # CA certificate (public — lives unencrypted in the repo) + ca = ../../secrets/nebula/ca.crt; + + # Host certificate (public — lives unencrypted in the repo) + cert = ../../secrets/nebula/${config.networking.hostName}.crt; + + # Private key (agenix-decrypted at runtime) + key = config.age.secrets."nebula-${config.networking.hostName}-key".path; + + # Static host map: tell every node where the lighthouse lives + staticHostMap = { + "${cfg.lighthouseNebulaIp}" = [ "${cfg.lighthouseAddr}:${toString cfg.port}" ]; + }; + + isLighthouse = cfg.isLighthouse; + isRelay = cfg.isRelay; + + listen = { + host = "0.0.0.0"; + port = cfg.port; + }; + + lighthouses = lib.optionals (!cfg.isLighthouse) [ cfg.lighthouseNebulaIp ]; + + relays = lib.optionals (!cfg.isLighthouse && !cfg.isRelay) [ cfg.lighthouseNebulaIp ]; + + tun = { + # Interface name: nebula. + dev = "nebula0"; + # unsafe_routes for hosts that need access to a non-Nebula subnet + unsafeRoutes = cfg.unsafeRoutes; + }; + + # Firewall: permissive defaults — tighten per-host as desired + firewall = { + outbound = [ + { + port = "any"; + proto = "any"; + host = "any"; + } + ]; + inbound = + [ + # Allow ICMP (ping) from any Nebula peer + { + port = "any"; + proto = "icmp"; + host = "any"; + } + # Allow all traffic from within the Nebula overlay + { + port = "any"; + proto = "any"; + host = "any"; + } + ] + # When routing an unsafe subnet, allow inbound traffic destined + # for that subnet from any Nebula peer (local_cidr scopes it) + ++ lib.optionals (cfg.routesSubnet != null) [ + { + port = "any"; + proto = "any"; + host = "any"; + local_cidr = cfg.routesSubnet; + } + ]; + }; + }; + + # Open the Nebula UDP port in the firewall + networking.firewall.allowedUDPPorts = [ cfg.port ]; + + # When this host routes traffic to a non-Nebula subnet, enable IP + # forwarding and add nftables masquerade rules (see unsafe_routes guide). + boot.kernel.sysctl = lib.mkIf (cfg.routesSubnet != null) { + "net.ipv4.ip_forward" = lib.mkDefault "1"; + }; + + networking.nftables.tables = lib.mkIf (cfg.routesSubnet != null) { + nebula_routing = { + family = "ip"; + content = '' + chain postrouting { + type nat hook postrouting priority srcnat; policy accept; + ip saddr 10.157.0.0/16 ip daddr ${cfg.routesSubnet} counter masquerade + } + + chain forward { + type filter hook forward priority filter; policy accept; + ct state related,established counter accept + iifname "nebula0" ip saddr 10.157.0.0/16 ip daddr ${cfg.routesSubnet} counter accept + } + ''; + }; + }; + }; +} diff --git a/network.json b/network.json index d61870c..fd75de4 100644 --- a/network.json +++ b/network.json @@ -16,21 +16,29 @@ "ip": null, "pubkey": "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFxmnCj2E9DxcnefPW+n4yCuLShxqr0p024riogdeXA3", "ts": "100.70.99.91", - "system": "x86_64-linux" + "system": "x86_64-linux", + "nebulaIp": "10.157.0.7" }, "genesis": { "ip": "10.42.1.5", "pubkey": "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIO/CGE2rqlL2Qr0TJkwQMsHFSDkhGWlrUlvfcvcylO1n", "ts": "100.96.198.104", "system": "x86_64-linux", - "tags": ["router", "server"] + "tags": [ + "router", + "server" + ], + "nebulaIp": "10.157.0.2" }, "hosea": { "ip": "10.42.1.7", "pubkey": "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKLIwkTTXA56sUlUjEulXXZRvZy5H4a5ZwgKWLlpkQDz", "ts": "100.68.203.1", "system": "x86_64-linux", - "tags": ["server"] + "tags": [ + "server" + ], + "nebulaIp": "10.157.0.3" }, "icdm-root": { "external": true, @@ -42,8 +50,16 @@ "pubkey": "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIHleYKtfV4W1Z63Ysu9w5Rbglqlz4F92YcZoMkucoTNf", "ts": "100.84.183.79", "system": "x86_64-linux", - "systems": ["x86_64-linux", "aarch64-linux"], - "tags": ["builder", "kube", "server"] + "systems": [ + "x86_64-linux", + "aarch64-linux" + ], + "tags": [ + "builder", + "kube", + "server" + ], + "nebulaIp": "10.157.0.4" }, "iso": { "external": true, @@ -59,8 +75,16 @@ "pubkey": "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOjQjXq9WYU2Ki27BR9WwJ4ZruS/lJXbjC1b0Q42Adi0", "ts": "100.102.186.39", "system": "x86_64-linux", - "systems": ["x86_64-linux", "aarch64-linux"], - "tags": ["builder", "kube", "server"] + "systems": [ + "x86_64-linux", + "aarch64-linux" + ], + "tags": [ + "builder", + "kube", + "server" + ], + "nebulaIp": "10.157.0.5" }, "joel": { "external": true, @@ -72,7 +96,11 @@ "pubkey": "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMv9Zud3kZOl86gtmkn+uj3D4kiXWDPtyUL02VVLNR4Q", "ts": "100.109.86.8", "system": "x86_64-linux", - "tags": ["public", "server"] + "tags": [ + "public", + "server" + ], + "nebulaIp": "10.157.0.1" }, "MacBook-Pro.local": { "external": true, @@ -108,8 +136,16 @@ "pubkey": "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOos0zQePsa+T6Z2dsKbPOvEdrBQ8a6mx3s7pN6ysCI0", "ts": "100.90.74.19", "system": "x86_64-linux", - "systems": ["x86_64-linux", "aarch64-linux"], - "tags": ["builder", "kube", "server"] + "systems": [ + "x86_64-linux", + "aarch64-linux" + ], + "tags": [ + "builder", + "kube", + "server" + ], + "nebulaIp": "10.157.0.6" } } } diff --git a/secrets/nebula/.gitkeep b/secrets/nebula/.gitkeep new file mode 100644 index 0000000..67ef0e0 --- /dev/null +++ b/secrets/nebula/.gitkeep @@ -0,0 +1,8 @@ +# Files that belong here (committed to repo): +# ca.crt — Nebula CA certificate (public) +# *.crt — per-host certificates (public) +# *.key.age — agenix-encrypted private keys (safe to commit) +# +# Files that must NEVER be committed: +# ca.key — CA private key (keep offline!) +# *.key — plaintext host private keys (encrypt with agenix first) diff --git a/secrets/nebula/README.md b/secrets/nebula/README.md new file mode 100644 index 0000000..abdf6a4 --- /dev/null +++ b/secrets/nebula/README.md @@ -0,0 +1,109 @@ +# Nebula PKI Bootstrap Guide + +This directory holds the Nebula CA certificate, host certificates, and +agenix-encrypted private keys for the `nebula.thehellings.com` overlay network. + +## CIDR +`10.157.0.0/16` + +## Host IP Assignments + +| Host | Nebula IP | Role | +|-----------|-------------|----------------------| +| linode | 10.157.0.1 | Lighthouse + relay | +| genesis | 10.157.0.2 | LAN router (unsafe) | +| hosea | 10.157.0.3 | Regular node | +| isaiah | 10.157.0.4 | Regular node | +| jeremiah | 10.157.0.5 | Regular node | +| zeke | 10.157.0.6 | Regular node | +| exodus | 10.157.0.7 | Regular node (laptop) | + +--- + +## Step 1 — Install nebula-cert + +```bash +nix shell nixpkgs#nebula +``` + +## Step 2 — Create the CA + +Run once; keep `ca.key` offline/safe (do NOT commit it): + +```bash +nebula-cert ca -name "thehellings.com" -out-crt ca.crt -out-key ca.key +``` + +Commit `ca.crt` (public) to the repo at `secrets/nebula/ca.crt`. +Store `ca.key` securely (password manager / offline). + +## Step 3 — Sign host certificates + +For most hosts (no subnet routing): +```bash +nebula-cert sign -ca-crt ca.crt -ca-key ca.key \ + -name \ + -ip /16 \ + -out-crt secrets/nebula/.crt \ + -out-key secrets/nebula/.key +``` + +For **genesis** (routes the home LAN `10.42.0.0/16`), add `-subnets`: +```bash +nebula-cert sign -ca-crt ca.crt -ca-key ca.key \ + -name genesis \ + -ip 10.157.0.2/16 \ + -subnets '10.42.0.0/16' \ + -out-crt secrets/nebula/genesis.crt \ + -out-key secrets/nebula/genesis.key +``` + +Commit `*.crt` files (public) to the repo. +Do NOT commit raw `*.key` files — encrypt them first (Step 4). + +## Step 4 — Encrypt private keys with agenix + +From the repo root: +```bash +cd nixos +for host in linode genesis hosea isaiah jeremiah zeke exodus; do + agenix -e secrets/nebula/${host}.key.age < secrets/nebula/${host}.key + rm secrets/nebula/${host}.key # remove plaintext key +done +``` + +The `secrets/secrets.nix` file already declares the `.key.age` recipients. + +## Step 5 — Configure linode's public DNS / firewall + +- Add a DNS A record: `linode.nebula.thehellings.com` → linode's public IP +- Open UDP port `4242` in linode's firewall / Linode Cloud Firewall rules + +## Step 6 — Deploy + +```bash +colmena apply --on linode # lighthouse first +colmena apply # rest of the fleet +``` + +## Verifying + +```bash +# From any host, ping another by Nebula IP +ping 10.157.0.2 # genesis + +# From any host, reach home LAN via unsafe_routes +ping 10.42.1.1 # UDM Pro (via genesis) +``` + +## Notes + +- `ca.crt` is public and lives in the repo unencrypted. +- `*.crt` (host certs) are public and live in the repo unencrypted. +- `*.key.age` are agenix-encrypted private keys (in `secrets/nebula/`). +- The NixOS module (`modules/nixos/nebula.nix`) references these paths directly. +- The lighthouse (`linode`) has `isLighthouse = true` and `isRelay = true`. +- `genesis` has `routesSubnet = "10.42.0.0/16"` which enables IP forwarding + and nftables masquerade so Nebula peers can reach the home LAN. +- All other hosts have `unsafeRoutes` pointing to genesis (10.157.0.2) for + the 10.42.0.0/16 subnet. diff --git a/secrets/secrets.nix b/secrets/secrets.nix index cffce51..bba6700 100644 --- a/secrets/secrets.nix +++ b/secrets/secrets.nix @@ -137,4 +137,14 @@ in "compose/attic.env.age".publicKeys = everyone; "grafana-api-token.age".publicKeys = everyone; + + # Nebula mesh network — one private key per host, encrypted to that host's + # system key + all user keys so Greg can (re)encrypt them from any machine. + "nebula/genesis.key.age".publicKeys = everyone; + "nebula/hosea.key.age".publicKeys = everyone; + "nebula/isaiah.key.age".publicKeys = everyone; + "nebula/jeremiah.key.age".publicKeys = everyone; + "nebula/linode.key.age".publicKeys = everyone; + "nebula/zeke.key.age".publicKeys = everyone; + "nebula/exodus.key.age".publicKeys = everyone; } -- 2.54.0 From 2bb0177ffa33679a2a306c5eb2c2af0905fc3f14 Mon Sep 17 00:00:00 2001 From: Greg Hellings Date: Wed, 1 Apr 2026 16:33:59 -0500 Subject: [PATCH 2/8] chore: add encrypted keys and unencrypted certs --- secrets/nebula/.gitignore | 2 ++ secrets/nebula/ca.crt | 5 +++++ secrets/nebula/exodus.crt | 6 +++++ secrets/nebula/exodus.key.age | Bin 0 -> 2099 bytes secrets/nebula/genesis.crt | 6 +++++ secrets/nebula/genesis.key.age | 38 ++++++++++++++++++++++++++++++++ secrets/nebula/hosea.crt | 6 +++++ secrets/nebula/hosea.key.age | 37 +++++++++++++++++++++++++++++++ secrets/nebula/isaiah.crt | 6 +++++ secrets/nebula/isaiah.key.age | Bin 0 -> 2099 bytes secrets/nebula/jeremiah.crt | 6 +++++ secrets/nebula/jeremiah.key.age | 38 ++++++++++++++++++++++++++++++++ secrets/nebula/zeke.crt | 6 +++++ secrets/nebula/zeke.key.age | Bin 0 -> 2099 bytes 14 files changed, 156 insertions(+) create mode 100644 secrets/nebula/.gitignore create mode 100644 secrets/nebula/ca.crt create mode 100644 secrets/nebula/exodus.crt create mode 100644 secrets/nebula/exodus.key.age create mode 100644 secrets/nebula/genesis.crt create mode 100644 secrets/nebula/genesis.key.age create mode 100644 secrets/nebula/hosea.crt create mode 100644 secrets/nebula/hosea.key.age create mode 100644 secrets/nebula/isaiah.crt create mode 100644 secrets/nebula/isaiah.key.age create mode 100644 secrets/nebula/jeremiah.crt create mode 100644 secrets/nebula/jeremiah.key.age create mode 100644 secrets/nebula/zeke.crt create mode 100644 secrets/nebula/zeke.key.age diff --git a/secrets/nebula/.gitignore b/secrets/nebula/.gitignore new file mode 100644 index 0000000..17f3e06 --- /dev/null +++ b/secrets/nebula/.gitignore @@ -0,0 +1,2 @@ +# Ensure that this doesn't accidentally get committed +*.key diff --git a/secrets/nebula/ca.crt b/secrets/nebula/ca.crt new file mode 100644 index 0000000..98a0461 --- /dev/null +++ b/secrets/nebula/ca.crt @@ -0,0 +1,5 @@ +-----BEGIN NEBULA CERTIFICATE V2----- +MIGGoCCAD3RoZWhlbGxpbmdzLmNvbYQB/4UEac2JJoYEa668poIgUABA1IfasOIr +5hw9rQQIMzYwszJHtYp9ugmJcLLunqaDQHcumg7wvHWfQtm9ONu136FMxdSeXPvx +3QO+IOTHxm/8nuCyYUuegR6edKdxVxUPWGFkVq8M5ExxgxqsD2u2AgQ= +-----END NEBULA CERTIFICATE V2----- diff --git a/secrets/nebula/exodus.crt b/secrets/nebula/exodus.crt new file mode 100644 index 0000000..bdedc67 --- /dev/null +++ b/secrets/nebula/exodus.crt @@ -0,0 +1,6 @@ +-----BEGIN NEBULA CERTIFICATE V2----- +MIGloD+ABmV4b2R1c6EHBAUKnQAHEIUEac2MaYYEa668pYcgg4lMYGB2VakRFO6b +K9vHSLzjZpuqhBVQ7MReOwUHQKyCIJs1EbYsPKmY0efr23jfpyncEByAqEuDvKMz +2+fUUzoRg0DsosJ26LJhHe1MBvQbKx//ZwJ1iTEWmkGJnAfdglLpcf6RWtSOQaEL +UXpSV2MK3IbgSpP26zRI8mpp9OW9ApQM +-----END NEBULA CERTIFICATE V2----- diff --git a/secrets/nebula/exodus.key.age b/secrets/nebula/exodus.key.age new file mode 100644 index 0000000000000000000000000000000000000000..0b1c0998c83842ef866386c4027d96d877d33e47 GIT binary patch literal 2099 zcmZXU%ggI{9mbE#Q;@?f2HjbdVbJiJG-=XQP*2h{mp1n{&1Ivx{*p9lbH5>HU>tO# zqa!GTpw31FVbFyew>l`yVuV3lcmrK1Du@Uo-oSU=_aFFv_&i^p#|7bCc=4;TXp-yY zqt^<+-C}n4iFsYecVU3y_+mXLS8-c{dB0o7cwmh=dA1llFZG|ttpzIZ&^_FI^(J=?}5^p*s&AOCLS{e%Tz>D`)&j$EOFjrDSQR`Nx`C8^jVP>6l zgM$%GM-o#{{nWoS*`b1QSP!6+pjVc+Z{cfhMr-4iHptE8O3e|&*t_wTE~1#k4@(_g zLEr#(5ms*3cGYA_%Xd=*6n#U^R>#Znus?-^<3qFw36R8>UaV$h0vZZeo2;$RG;u&Z zxxS^jHcDC497JGIXSuLCrKZ)_v6@y;Vf!g`+777I7bA$>H9?Hi7R*LZ4~EPo6%&Uq zxIh^;!POBQr3SO20OS{DbXa$5LZR$i8l}b20?gr^+4sBUFcrBDEd&FV4KdPue?48$ zgRmKujjJ!G)pXt1vprfkKA|qm@+=DQl%QCD%JJNk1`kWtSAMTv85)VVY($8DF2F`G4-Wn75eXgVZu z+%DTOJ`M7A@|np+Xg^YR+O3?_=}-HmdufrFtJiciX^(ewhsy=n%vai(h%6J_h3%YsR?vo z>yc@J1FXp%V(rRCx11$Hw9-mKFsL@CgaQ4m2t9n?)B3bm!=6qeYoVkG8bO^SL-h(Z z;ar1{Sf9E0g9gYMjE~e@7Ktku4xFcL4%Uz~7^;`OJB;DVS)hi);SSleKv-6^Hf#8U zXqj+g#A(Hdkt`#Z1R647C>%oNEmpQlIyS7Gm!EIlxIhFOZ7yAF+KA=QC0Hqxww!A& zP;9-qT#5D?GdahpBns9_e(IbOXh(aTTES~&2yHmTz{l&)kF7$=`vhw~GMUYac8aYVq3arN-TN6uZj(F*YBytb2p}#Q3AeT8*qmJmsNo#9IW41g`UVSFfKqQKNUqBLmcC(G&Uo{h;ynLq8igoU!TS79(qAK(7p@1VwkL$j0!I-WxW9 zT$otTFPUZr#tPquqP$wuFzQXRm@RMS=||(bz*0-?#hjZeA&|i&n~!-%_neBDIC`YL>cT z%Ab8>-^!_Duen&;(qljS?IZjTpZVQe{+Iatr`h8l|K}HPzy9BMk`KK0*MI%+@r#eD z4}GWm?E35S)2BasFaMx4ejR4X^FO!C7v2}W3g9nJ<41l&{mFgu@pr|?=o^1| z|M!faeC%^CKl#U-+#4@_`d4rL{_exye9tdG75(wsU;E^9?YDmPm4AQrh3|g<-Lv}o ud$+H=^X0$2`sWu? ssh-ed25519 87huqg WXMqashYNOR9yEbdbSUDmDzoMoqgcoMsT2MH2S0GKmg +2HtruRcG98iQuf4qmfrqSAm87HkejgmQdVJHJyOOwOI +-> ssh-ed25519 8UnW5Q v29MY1lo+DDut1YuTfRWN3zQADxQHJXbIIUPuUJ3sAM +qtZyn+8TGe9+bJwwvjyR76k6K9ZqGyKhQGTQKLnylZk +-> ssh-ed25519 UFfTmg 9q7zsYWj8q5DpPoRxJgUeRMgxDPTE8q6pfHW3Qgh9hA +dDfyqKQmFS17v7j2u7VoGUteG9hvAxEmopgIaIK/Y+k +-> ssh-ed25519 xNtnoA fT16NQwHegZ8NID1mdIJMu3UrSD2+9t7lq8+np+HGi4 +Wv5wIZK3ET0QHeHD2QcNYAe6uPB0lwFw7gy96EwV98s +-> ssh-ed25519 aY2AXA h93ygtkSRcDpVHy1ZhFWxLbOU0rdH1zGeZNP9Y1lbH4 +z0HjGZenKe9cQTBUAgufIUgElSqrKQAcdcPAXE6MtFI +-> ssh-ed25519 AQhf1g C+o3QKZbh85eO25aYtcjPOSp3PINPkOCsc+4GHkq+Qs +q2A7PK6zxcGiMwv3pdpd37xkQ4VWbZvUM49WaULuYzw +-> ssh-ed25519 mOmPfg if1IROrr9joSCWV/DdtF5mydOKabZkXmsdAwiCErWls +vykl/npqwKDP3a+n57Ala6QaPX/+izTputvkLsdOdWs +-> ssh-ed25519 YJiRbw te0RkrNjbL1J76T59XWnZuDTUuGsXIaqgAcrPV9CUgo +TpAV/oTT6MI1LgWhhgFZr0El92HQpowHhg5nGRjzs10 +-> ssh-ed25519 0/WsKg IlmjW0LvTTimuyX7pZsFjlACBJe0niM9kM/7kdJH8Tk +NYERifDZzpmvhzn2Rf0YPviJHfGwlXGaut8Iz1JewUE +-> ssh-ed25519 Nl/5yA kP9Lys5bCdpDDPFmeWvpzUqQe5WQBvSvYuWB+mhdVWM +YHoc8vhAW/t+USrTNKbUR5IWdMqr2Ks4dA0Bamp52S4 +-> ssh-ed25519 GdLgCQ D4/qiTTvYk8jxewNQCVfoBQYXu+oV7q3tT3a89kG2gk +YkzdAgpG2WsQDVpmou7fZDx6BP/SWvQPHrqXVsYMMAY +-> ssh-ed25519 tOH/HQ vgvAN0DO1T8crhQ+hcKUx7ddHXGi2rH05Bpz1rjBU2A +2qGje0ciWf25ZCKQ4R2mcox2nCLr10YQjU8wEyYyOSg +-> ssh-ed25519 FpzvfQ Z7u0rxi2n3iDSiosLHR8JMahjVITwHi45I/e2kG7xz8 +7boIDstWnjmhs4JIZcC9Oe9TVerRwCpMw6KO9pd+mJg +-> ssh-ed25519 kdPvzQ Ts1NyubR5GHNQMouf2g+CB66tP30eBgMRPY+JI4hdUI +oVYtbwVaPAI58OLFp2ZiPq25jlPPzmhnhtFeJIaLaAg +-> ssh-ed25519 onmXpg yIecAxAGjIc3MM9Jj2isTAeRdnw3yu2Z0V9h+9LN6AU +7O1kkpjssbiMzl4urn2abrV7m7+zUFs8NRbpmh/2TbE +-> ssh-ed25519 CnhD0g BUYpZVebroM2eA7jGqczpC7vlsDcdRkU2hrSUZTZ2gE +Jbumonfp1U8URoTNkNP+d3Kyvor1jm9L1PDVUwtZgUg +-> ssh-ed25519 4ep2UA SnRm7O7Lu9ljkA9FrJn+S90TGrE+aXK+WbKAQqJRzVw +VpqLszwhrXDGdJuv//jrkTXfnqzMbliEEYm3HDCQ+8o +--- yBFC+vpdV8kCw3toDhSLnWbBdZGWB3E/Ja2N0LwQ7Ws +"n4csǸuy}Cxr d^JEcC5 'z̒őѻn@&u + {(pkؑ nL[ Ac^s ȤvLA r4-D}vy٠aQ \ No newline at end of file diff --git a/secrets/nebula/hosea.crt b/secrets/nebula/hosea.crt new file mode 100644 index 0000000..dbdff19 --- /dev/null +++ b/secrets/nebula/hosea.crt @@ -0,0 +1,6 @@ +-----BEGIN NEBULA CERTIFICATE V2----- +MIGkoD6ABWhvc2VhoQcEBQqdAAMQhQRpzYxphgRrrrylhyCDiUxgYHZVqREU7psr +28dIvONmm6qEFVDsxF47BQdArIIgsu+XmvDcRq7CtqiLC2sSK1eCcZ8XtMSpb1Vh +64R7NgWDQJYr4aQrWlhuDLZR0ZkRoFYXzj34OpeXDUCFOaTAVoRRHvIvge2umpMa +YwgjY9reccBqdFRAoAkaJBt6wixrGgs= +-----END NEBULA CERTIFICATE V2----- diff --git a/secrets/nebula/hosea.key.age b/secrets/nebula/hosea.key.age new file mode 100644 index 0000000..4267246 --- /dev/null +++ b/secrets/nebula/hosea.key.age @@ -0,0 +1,37 @@ +age-encryption.org/v1 +-> ssh-ed25519 87huqg btSjOfzdV07UqZLYHUneGnFJowu4FHz9RrJ7+7ddJXs +58MQvGqjYEnyIh1IVhOv3KmGXXdtJfeehcDYEaLgDso +-> ssh-ed25519 8UnW5Q zH+7egFzPKq4936zmLu30rDmcKhobhNeDii9KyVBrhQ +EAktJPVzwbtZW+13QgnTieT5byTAjR9LUHjlJS6qfRg +-> ssh-ed25519 UFfTmg fdJBTqLeTyz7Xq4zLoGFzkCFpvQ3LwcqfEOMbYrXfGA +6RMYkDlEKbK7R2/gi/aBv92qZQti4LQxLE5Rkp8QXmQ +-> ssh-ed25519 xNtnoA qIHYXNrH6/1uW4VhSXc3S3KN0pZnpC5VOlbk8Jcb7F0 +8h/o26hN98uf9kPbupzSX8V+3y163MlZQEi4vZbwDGg +-> ssh-ed25519 aY2AXA +s/czaDMCl/6RTQSdaOwn4fka9dTTuPppqA3+WDTzD8 +Z6iKe15fqSNMOCku684M9dn1aKKIUzKfLzq/NiF+L7A +-> ssh-ed25519 AQhf1g 5M4AsA5NVhbBtpeCEk2txeFKq6YvX1R3qiv0Fu5U5XY +3jrHOW5pKckBvO9IMnNeq1xVWxpdcsZhyzruJZA6m4w +-> ssh-ed25519 mOmPfg /Ho4F8SLEnZS7XE7L0y0ife5DOLf0QfJCi+alwMDCy8 +vef+X+2AfGZTFY7ktmUhqmRV/RF/XoAfWNIQMUP9KUc +-> ssh-ed25519 YJiRbw Hmx9RE09dq57CE6av0FA3iDDzFMpQLKLEUpkVymXnTw +gqniOzWFXAglRhe3oLp2SmtYujUZXwAOa9SsvFTBFEM +-> ssh-ed25519 0/WsKg EianWFyBA57VdsfY3fTvMCZ7DIvm3t+BhwBtx/qXOzs +qFxbQsfWbZJQ2vVnVxSdX1hw/MBS0JL44tVKDax4v/8 +-> ssh-ed25519 Nl/5yA OxFWVZhphi0JMr+nco6rEIsOvM4wE0N1tq33V1PODRc +hb5JOjYomRkz+ERyYeBOmX/ZMW3q8usNvB8yZE8AIpk +-> ssh-ed25519 GdLgCQ aO0zk3ruD2oBnEJ6fMUv1JmIYWpoo2DgEqC0NpA2fmc +6PctZY6vS3FnLVW/HbQXLEVKQHN2YGlunexHYTX0Tl0 +-> ssh-ed25519 tOH/HQ Vw8Uv0unsRMzgPE6NZhB1OcnU8C65uer5fJejQH9KzQ +MpaE+W/Hpm59LYwvGESKn6Bz+236x1pbMup8uZ4z6nc +-> ssh-ed25519 FpzvfQ 8Q7j/490GgZJf7mc8lsydYOKpyjLSKEXQHqqz+31T0c +iNlRFeNjVSmsTLEwnuQhKypCOiZ3SCWJXTtz34tPgsg +-> ssh-ed25519 kdPvzQ AOhJrxYuhkqDVbkhlpGhA925tInO5YfnTCh337LPcms +kv/RBK7BD/g6mnsGY8jHeXwAM6Pj3PMQ9lx2MOIn1Pg +-> ssh-ed25519 onmXpg dWB5HHlKL9MqP1a0gnpSSDAOOwLdkdqS92X69ZoYry0 +7W6QYnIGu8iUqGMzUKWOr3AzVjSNegt7BL17ZkP6Z44 +-> ssh-ed25519 CnhD0g 1xYVgHZJImVsk30tT4hC+Wfla0xssBcYS70mAG91h0g +pSCVA/tSP17FSBqmSx+mQjwwv9SrHgIZiI5g5E9Rkao +-> ssh-ed25519 4ep2UA 8P+sxx5e/JhdlGQ26EzavfRst+i79kAvAV0iZBRfsCQ +O2OqHFbZmj1A8Wvj7p66YhpIuPHxFsnnyUt3xLJ6HRQ +--- Tex+YxBloLbsHGMdMhvYly7XwY8wmSZ2sP3R3J5a0Jw +m+ nyj.m'1;]&}2LňZlɮ|jO=dEm>܉)䩸Tu`rb:!Zh6G ׃?OyG _ܭlQfٔn"nsmrDUr})Exjh eit \ No newline at end of file diff --git a/secrets/nebula/isaiah.crt b/secrets/nebula/isaiah.crt new file mode 100644 index 0000000..7c843f5 --- /dev/null +++ b/secrets/nebula/isaiah.crt @@ -0,0 +1,6 @@ +-----BEGIN NEBULA CERTIFICATE V2----- +MIGloD+ABmlzYWlhaKEHBAUKnQAEEIUEac2MaYYEa668pYcgg4lMYGB2VakRFO6b +K9vHSLzjZpuqhBVQ7MReOwUHQKyCIBv+1Lr/E3Q6d99laLGdXRTss2SIL4OGBp8z +qqfEsAMpg0CyDSEYuL8GaHQq708GbCxhxFifCZaRTB+ReGBScmhT9XhIwSLHRRZJ +1TmoY4QvrdPOS3NAWvlawk/JUqN7SWQL +-----END NEBULA CERTIFICATE V2----- diff --git a/secrets/nebula/isaiah.key.age b/secrets/nebula/isaiah.key.age new file mode 100644 index 0000000000000000000000000000000000000000..0a8b0b2348cb1f8404ddfcc619739a5c51dd9c7e GIT binary patch literal 2099 zcmZXV$*b%L6^9+5X^TeiL8BX=B~MT&ZfB^ZlHdTDlgdy@Dzl&@RY@w9v657#)q@5V z1Vu!#5f|;k-Zf}1+^8Fo)|DuNh)s*WCyFAp;Din0UEli`e4O+9e&+;9bQ6__W~#fi zDqpCY1n8l~&8L=ad%B5^Fp5IN630&0OR}61K{!z%74f8CR`E=^C~vF@s@Wdg(PBv4 z+&XK*h3GT6sM~E>ah^!+CT3WXrzTT*R}r!#D+|q&=%X6a3F$*UUfrWvrGx6r)&@3= z5^O4K$F55{<#o6+Y1Xd6_7bkSA>9vM<{wm~#21p$AhKHfI>O**7h_3c4JAE%L2#8( zb0xoYxLsfJ2^RFbG>ePPB3Yv4Cba{052`yIL5`AH3~?`vwr=3pwCJy>3^wcC4(m;D zAu_Y;cw6`gK%l&evGeR)!;Qy@39NPFcBiZ2!J5VBgd%roquP}fxx5C4NM}}%rIV5e z`Ll$;t4ypxByVi+A0)?l@eZIqA{k&zVL(zCUC7Ht|Q^?l=OE5D15rdMAm zhHSg)9xd=-(j}K8)e8h$wAZkjI7xNb4TFdry_I=ObB(cglp4$S;-28}MT}qOJtx_# z4nL|s(rk_r07VEd9$2V3j>pDYgPZGB9a!b=Y@~jQp=2qZxgmh4qrzUOTAfOZx`tSz z=4!#kfxq1pYOpHk+zFClu``FjTq~k~g+dGSOAW3(7TT){*x}-+$_lRY8Ox0jDc+?O zyF!bTr9{^!k`!w!Y1fkM5;W%Q%v&2N29_!J(v(lHGot{JK{xlhACTc z8>+9;B6GK85T$+5h#;0>G!laVIi&%0vWUbtVL@}fyPM>Xazg9N23GSJ6TwZw(R9~u zpowfYA}HRvj!7`z95lD4Tc)sFb|H`;L~>iP?2^ok-5IK?Gpe%-ce(^ZJ`cS= z1#{MeW^;0DpU-q6qU90L$l-!1@>#a;JIU2^AL~n3f}zwqXpjhpaWsHhCaEZy60=?$ zz%i{Y#Dk8WZ8T%HXmqltThi{D6$6K`nqA=rR+>0C-Ae5M2`E#Yv|}PSyw`y2sP(hH zB*3Xy-cx;zD6)6=xhSw3EG8ik%B!>49)9 zWfiW%qz8hb$B`Jp=knfFuFAr#lVvxhIBV)HNYkR;#u{=Kxa@Rkd5lv%07?$PWKM~c z`xChEcp(hY-hgl!U|7H%B?b3NBMlNt!3mdbQD#S^lMhCRyOz-9i2-jLK+Mg|bU1X} zc4X?WX`ehE+#oRw8#OIY6sLXM=X!TtBMWISr^dlq0Va&QwlF!Nfp-8Cs1`CISJ?uA z6pi8aWZiE4&VNIq8n(z~NsU%(f%Wb>MgDDu_fgcA2risP*VqujSujk(d!-RjyjzzZf{QIlt{?NYsx5wbCKmE?5zkcn-kNx-f^a1@_a!LNo+u!}gOMC41&wl08|9tqlAALc7&!dk#ssHorpFa7*b8jdg_&-nx BuMYqK literal 0 HcmV?d00001 diff --git a/secrets/nebula/jeremiah.crt b/secrets/nebula/jeremiah.crt new file mode 100644 index 0000000..69b457b --- /dev/null +++ b/secrets/nebula/jeremiah.crt @@ -0,0 +1,6 @@ +-----BEGIN NEBULA CERTIFICATE V2----- +MIGnoEGACGplcmVtaWFooQcEBQqdAAUQhQRpzYxphgRrrrylhyCDiUxgYHZVqREU +7psr28dIvONmm6qEFVDsxF47BQdArIIgHXr6BLGmqfF92GXiN6MBj3ac0p/EtNYf +xR3/EdI5GnGDQIFxfV5fVwi26+IRk9QIFxyyFBtmsZyPbdxL8ca1WUPm3lCNA4BT +Knd9Y3Zlp6L35L4/dzSqAVoXu2nlHF6SOAA= +-----END NEBULA CERTIFICATE V2----- diff --git a/secrets/nebula/jeremiah.key.age b/secrets/nebula/jeremiah.key.age new file mode 100644 index 0000000..908c54f --- /dev/null +++ b/secrets/nebula/jeremiah.key.age @@ -0,0 +1,38 @@ +age-encryption.org/v1 +-> ssh-ed25519 87huqg oq74sKlsXTuQiPF3vIpfFbXh4fLRWoEprZ1h5MFiyWQ +58TOYaLR4Afm2ZSpWOHbr5ZWhzT08VSP+v9U0/lAXfs +-> ssh-ed25519 8UnW5Q TBEe5WrfKcXulpJo6yKUdQJHwuSyJiXQRfcwL43V0mo +dTYL5omLZDCmbExfcTwfENbh0/U3h651V8f6pHkSyw8 +-> ssh-ed25519 UFfTmg wmSLwX0Wi3z2pT1Ag5QzalAFmFnPTBH1kXBsfg+98m4 +V3unDcMC3pPlFJpG5yFi+wdCUzJEcXcxEUPOtug8v10 +-> ssh-ed25519 xNtnoA P/DzjGiesuoFbsUHf2hrtm1hYn7QDlHEM4Pn+HPp51I +EwByGfMGGByPJeP+fC1fXtXwjtH81NSjcmBkR1Yspzo +-> ssh-ed25519 aY2AXA Ffs4EXgQ+3UknIyTWZNfsDJY/uwM2JGMKYgoZq4SQ3Q +ZwVfFdBdEtswaNMNcmX1sCJrEOHt10M17AFH08kKNpQ +-> ssh-ed25519 AQhf1g FBnnAMCfUus06OPeLIhoV4yeSXdY8DGz3w9PCOuHYEY +OmqAuVpc6UnvShK8wMbHboAlDq/TlNQkEnUX36duOWk +-> ssh-ed25519 mOmPfg /HHd/eEJjAlj83IwGtE+Hsk5dVjWYYoChFrm+Tb2g3E +f+S6iK6fNcKoCMDnH7HLC3LrZk/jwpfxCi6DFgFuW5Q +-> ssh-ed25519 YJiRbw 3iblt4OCf+OOgriTYMWDDI9FhFCQQwR19pWpgyfh+Gk +RaIjKHzOoiEdpedS3GBeBrq9M3OZs8CHPuMdzph9Gj8 +-> ssh-ed25519 0/WsKg hLS/sxN+t8LdaTLp5qIRodex6Qc2DhE3ljL65cHbUDA +X6S4fFz6v70UC8BpXCnFvvHpsKpGett2s5wthsCjBJ4 +-> ssh-ed25519 Nl/5yA rJF2bbel2dZhH7CuC99TnG281c+9cUPF7+u0QmJ5oBU +Pqr5fWB94NJHM4Py8sqleDgE6A26PGCTmjVv2e+t2EM +-> ssh-ed25519 GdLgCQ wqdRmufRVW/GKqAl0UqPBUQXVUHRD1wC8dJVlcKS4kA +MdsqIGyyMiEcF1lwnlv2JACQaoT0ryepkGYb80odJBI +-> ssh-ed25519 tOH/HQ zFxCw9h85aJj81i07vWMsOR1VQdwebrNutvpftfobl4 +kJHWriqUGEYtWIAye6S5hLiuMnYybMmM/eI2X88WAbI +-> ssh-ed25519 FpzvfQ +iEyOgAINtNgxctHfMt+Fj/4eGZVjsTB4godZj2UMlE +sMrf5bW23oTEo9kQVuCmJGsMrzAFB/C3S+tEMf2sDSw +-> ssh-ed25519 kdPvzQ 8aLywX0Y8/UbEwrH90/Y5/6bwKpkY3sEP9xcn7YAuk0 +jkXdLMmD5Xm+0Sl7nCrxcrHTG7/QD1Su0ODvna5mHN0 +-> ssh-ed25519 onmXpg qAUGZKgUjAAdlaqcOrl8TSZVUlPaECW5DDrkdWZjAUo ++PfGPASqJ84Czlco8ZUuE/wyE+rl9ww2iep9zs/9LwU +-> ssh-ed25519 CnhD0g oVxR+8Xe9qQY8y6sCFWbqHxGPj1ECqISXMU7KAw6nUQ +tU4/lvxoK/KV7R+3L9IiJTidodtAySAzkIXTc33vyaA +-> ssh-ed25519 4ep2UA m+GmFvXANTiMr6U02p3GWDLr4Alk78Ae6+ePkk2qCVY +gzufOMJbBdhqb8/VIHyLVwDfShMkYZm3Y2wbPlC4GA8 +--- 4papXHguyw6dkzGpQOp1G0uK/ztnh8vxaYzJGaDlVmE +47 ~MÙ8&'Xbe_ s8xKg|qMZ>մ c^1,EnH˝]LŌ{IEɫjYЯ q 2IFY|% + Imxh@xz .jKS V.-%;~ɖ1 \ No newline at end of file diff --git a/secrets/nebula/zeke.crt b/secrets/nebula/zeke.crt new file mode 100644 index 0000000..92d15ef --- /dev/null +++ b/secrets/nebula/zeke.crt @@ -0,0 +1,6 @@ +-----BEGIN NEBULA CERTIFICATE V2----- +MIGjoD2ABHpla2WhBwQFCp0ABhCFBGnNjGmGBGuuvKWHIIOJTGBgdlWpERTumyvb +x0i842abqoQVUOzEXjsFB0CsgiCirKKbej7yAALn41C+MYmertD9LOv09gZ61ODF +wEcnB4NAfix/r3q+XLYe3egKUoqJUW2i11x0ST0hxqhJUd8LjHKirRyHsvUraMbG +c8x+CXsCPLgheGt548PpmrObQWtrBA== +-----END NEBULA CERTIFICATE V2----- diff --git a/secrets/nebula/zeke.key.age b/secrets/nebula/zeke.key.age new file mode 100644 index 0000000000000000000000000000000000000000..261c25f80f4230cdf4875a8dc9d2d335f3336d66 GIT binary patch literal 2099 zcmZXU%ggKr8OEy%(GjH-^q?CDTxdzZlgmsplZBPsGr1=-$s_|6bI;^{pG=^Na8yLF z6~P-SVzJsq!MgFNxGEH(DCkCt*mXg$E9uJ1xBkAr;K%QMp67Mr@Fpz%_FDJns(e_r zF*w4Dn`f6@m)wK_f}$|K+-{PgiI-votev#&K-J1@!HSLup)*ulBBKJtjU=o9LaGo* zn=N87#_cSX5vSP>wZU!E@Ff$z&aHFIFAA+)a1CM4#GtMK=pM~1kEp(68kn(i$4Qcm z;l#)gZJ=+t-qg1IIUR){8$(HmJ+3oX z)ZWXD8&-E|CL0}!csT}0M;`{hH^e&Z!oi_MqFdX&>8V5sig9-;Rw{9sUHGyXF-Yuo zmL^bkk~q$5-YbNh&btG99rc(a?$RcuFDqiX3mjOm)7&{WUWY@ZmJn+) z*!okTQ&8pU##N(MIJqtDZo$f^@AxF60FgS6KnnDj(>OCV*SuHCg^wg>X?-+$0X6T^ zTn8a+Vu>Hjv7u^>m}*1A`xC8PO4cxOla|GvxVq{#$OppSYrow&iet9dkMz0`}1fidmvL{e{`gy>7~+eL;2$7(Z711w)#%K;FhA_$)i~CIdUG zH4^4za>`D`tb&Rz-E(t*Kn zhZfPT)SfH&@{-d)k9VWzp0?%I#Uv!Fv+SrhxW}fg2b0^oZV-6v#CTZ%jA~>QNw5?v zpEdako$gQC zlcxA3;m3DrN)Dn|VyQ6XFxhb;T2zDiXqPHLCP_0<)Dh6=myojZtwf5>K4unEwSiWr zX>4x0N(iSC8{t&kNwUmt%w65@QEu2qky@MOy}faP6jS{4i%e8j*es2)!JdeHOKVUaTbWb^-lXw?Gl#A$9UkXopjn z;}3GG3$uk6XtEZ9VcgoZ!E(F1mt^aCjP#|wvz5sV6a#j3wGJ<5EP?VQVIWdsajgoB zE9(Wh;&HLFa5~lzd}hPDJ&>Cn6@o3~(P#*CVj2jC>%mD3F(@$m%G{-8fi}+ilJm67 z+8Br1)X5cpj&?Q|h&D1cT-+UdOxxw{8Z3fjmB$M(uCQcv0s|>J0S;%wh|#!}Fe__* zV!Wz9qH(MaVgY9N_EwdJUEg+6PtG&7-nR_ib+pJ>AYicyAqv$QvTgaYI`5cW5e&P6 zS)BGoSF;#a5`9@C4#T;2W_M?968E#S<)-->(OHCEB>i4Xs4}6Uc*&3s4ws-?5V28h z4!c?GXC*JpIpQ17m{~@pfD9-g&CnNOXgEA{W-u9n))!NRX)7Hv$TBGrnaCm>6~#6H zUdlxM?j_e@jhMue+Zwdfhe@}G(>mRdLIE_a8Bixe^X7Ej?O-zM^$Tbmb_>!rDl%ke zHEJ%owddkdQDJr$*#*~LOTLlmJ;(A=pwhR$sNj`edMYC w`A_ukz5L3*-+A(5-~Z#QKm77f|N9~3&&Tz5zV_y)zWp3dK7R1@Cti5#|7xMOxc~qF literal 0 HcmV?d00001 -- 2.54.0 From 84e4c68f0e96115ba9bc36999071d468d04c7d51 Mon Sep 17 00:00:00 2001 From: root Date: Wed, 1 Apr 2026 16:45:59 -0500 Subject: [PATCH 3/8] fix: move unsafeRoutes to module default, genesis overrides to [] Per review feedback: - nebula module now defaults unsafeRoutes to [{route=10.42.0.0/16 via=10.157.0.2}] so all regular nodes get home LAN routing automatically - genesis overrides unsafeRoutes=[] since it IS the routing node (avoids loop) - exodus and all k3s nodes (hosea, isaiah, jeremiah, zeke) simplified to nebula.enable = true only, relying on the new default --- hosts/unstable/exodus/default.nix | 6 ------ hosts/unstable/genesis/default.nix | 3 +++ hosts/unstable/hosea/default.nix | 10 +--------- hosts/unstable/isaiah/default.nix | 10 +--------- hosts/unstable/jeremiah/default.nix | 10 +--------- hosts/unstable/zeke/default.nix | 10 +--------- modules/nixos/nebula.nix | 15 +++++++++++++-- 7 files changed, 20 insertions(+), 44 deletions(-) diff --git a/hosts/unstable/exodus/default.nix b/hosts/unstable/exodus/default.nix index 900e6d4..84b6c00 100644 --- a/hosts/unstable/exodus/default.nix +++ b/hosts/unstable/exodus/default.nix @@ -32,12 +32,6 @@ gnome.enable = true; nebula = { enable = true; - unsafeRoutes = [ - { - route = "10.42.0.0/16"; - via = "10.157.0.2"; # genesis - } - ]; }; podman.enable = true; print.enable = true; diff --git a/hosts/unstable/genesis/default.nix b/hosts/unstable/genesis/default.nix index dc3d9fb..767d156 100644 --- a/hosts/unstable/genesis/default.nix +++ b/hosts/unstable/genesis/default.nix @@ -37,6 +37,9 @@ in gnome.enable = false; nebula = { enable = true; + # genesis IS the routing node for the home LAN — it does not route through itself. + # Override the module default (which points at genesis) to avoid a routing loop. + unsafeRoutes = [ ]; # genesis routes the home LAN (10.42.0.0/16) into the Nebula overlay. # Sign genesis's cert with -subnets '10.42.0.0/16' (see secrets/nebula/README.md). routesSubnet = "10.42.0.0/16"; diff --git a/hosts/unstable/hosea/default.nix b/hosts/unstable/hosea/default.nix index 9cf088f..537be9c 100644 --- a/hosts/unstable/hosea/default.nix +++ b/hosts/unstable/hosea/default.nix @@ -49,15 +49,7 @@ in greg = { home = true; - nebula = { - enable = true; - unsafeRoutes = [ - { - route = "10.42.0.0/16"; - via = "10.157.0.2"; # genesis - } - ]; - }; + nebula.enable = true; proxies = { "jellyfin.home".target = "http://localhost:8096/"; "jellyfin.thehellings.lan".target = "http://localhost:8096/"; diff --git a/hosts/unstable/isaiah/default.nix b/hosts/unstable/isaiah/default.nix index 29ac835..c50e64d 100644 --- a/hosts/unstable/isaiah/default.nix +++ b/hosts/unstable/isaiah/default.nix @@ -42,15 +42,7 @@ vip = metadata.hosts.${config.networking.hostName}.ip; priority = 255; }; - nebula = { - enable = true; - unsafeRoutes = [ - { - route = "10.42.0.0/16"; - via = "10.157.0.2"; # genesis - } - ]; - }; + nebula.enable = true; podman.enable = true; tailscale = { enable = true; diff --git a/hosts/unstable/jeremiah/default.nix b/hosts/unstable/jeremiah/default.nix index a2380a3..48d79fe 100644 --- a/hosts/unstable/jeremiah/default.nix +++ b/hosts/unstable/jeremiah/default.nix @@ -85,15 +85,7 @@ in vip = ip; priority = 254; }; - nebula = { - enable = true; - unsafeRoutes = [ - { - route = "10.42.0.0/16"; - via = "10.157.0.2"; # genesis - } - ]; - }; + nebula.enable = true; tailscale = { enable = true; tags = [ "home" ]; diff --git a/hosts/unstable/zeke/default.nix b/hosts/unstable/zeke/default.nix index 5b94e3c..0ecfa6f 100644 --- a/hosts/unstable/zeke/default.nix +++ b/hosts/unstable/zeke/default.nix @@ -26,15 +26,7 @@ vipInterface = "enp12s0"; priority = 253; }; - nebula = { - enable = true; - unsafeRoutes = [ - { - route = "10.42.0.0/16"; - via = "10.157.0.2"; # genesis - } - ]; - }; + nebula.enable = true; remote-builder.enable = true; runner = { enable = true; diff --git a/modules/nixos/nebula.nix b/modules/nixos/nebula.nix index 45fcd67..0c3e460 100644 --- a/modules/nixos/nebula.nix +++ b/modules/nixos/nebula.nix @@ -94,8 +94,19 @@ in }; } ); - default = [ ]; - description = "List of unsafe_routes to configure on this host (for reaching non-Nebula subnets)"; + # Default: route the home LAN through genesis (the home router node). + # Hosts that ARE genesis (or any other routing node) should override this to []. + default = [ + { + route = "10.42.0.0/16"; + via = "10.157.0.2"; # genesis's Nebula IP + } + ]; + description = '' + List of unsafe_routes to configure on this host (for reaching non-Nebula subnets). + Defaults to routing the home LAN (10.42.0.0/16) through genesis (10.157.0.2). + Override to [] on hosts that are themselves a routing node (e.g. genesis). + ''; }; # Whether this host IS the router for an unsafe subnet -- 2.54.0 From 0e61efe5b5ef7364b717c1139fcd29d06bff1a67 Mon Sep 17 00:00:00 2001 From: root Date: Wed, 1 Apr 2026 17:07:47 -0500 Subject: [PATCH 4/8] fix: rename tun.dev to tun.device (correct NixOS option name) --- modules/nixos/nebula.nix | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/nixos/nebula.nix b/modules/nixos/nebula.nix index 0c3e460..5b398d2 100644 --- a/modules/nixos/nebula.nix +++ b/modules/nixos/nebula.nix @@ -160,8 +160,8 @@ in relays = lib.optionals (!cfg.isLighthouse && !cfg.isRelay) [ cfg.lighthouseNebulaIp ]; tun = { - # Interface name: nebula. - dev = "nebula0"; + # Interface name + device = "nebula0"; # unsafe_routes for hosts that need access to a non-Nebula subnet unsafeRoutes = cfg.unsafeRoutes; }; -- 2.54.0 From 71ae25a58cb12cb28d8a41ea9972b03d617dbce7 Mon Sep 17 00:00:00 2001 From: root Date: Wed, 1 Apr 2026 17:13:37 -0500 Subject: [PATCH 5/8] fix: move unsafe_routes to settings.tun.unsafe_routes (correct NixOS nebula option path) --- modules/nixos/nebula.nix | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/nixos/nebula.nix b/modules/nixos/nebula.nix index 5b398d2..135c517 100644 --- a/modules/nixos/nebula.nix +++ b/modules/nixos/nebula.nix @@ -162,10 +162,10 @@ in tun = { # Interface name device = "nebula0"; - # unsafe_routes for hosts that need access to a non-Nebula subnet - unsafeRoutes = cfg.unsafeRoutes; }; + settings.tun.unsafe_routes = map (r: { route = r.route; via = r.via; }) cfg.unsafeRoutes; + # Firewall: permissive defaults — tighten per-host as desired firewall = { outbound = [ -- 2.54.0 From f35e8c755c97dcea38c321d9eae334eb4d654ff0 Mon Sep 17 00:00:00 2001 From: root Date: Wed, 1 Apr 2026 17:14:12 -0500 Subject: [PATCH 6/8] fix: only set listen.port on lighthouse/relay nodes (regular nodes use OS-assigned port 0) --- modules/nixos/nebula.nix | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/modules/nixos/nebula.nix b/modules/nixos/nebula.nix index 135c517..517ce4b 100644 --- a/modules/nixos/nebula.nix +++ b/modules/nixos/nebula.nix @@ -152,7 +152,8 @@ in listen = { host = "0.0.0.0"; - port = cfg.port; + # Lighthouses and relays need a fixed port; regular nodes use 0 (OS-assigned) + port = if (cfg.isLighthouse || cfg.isRelay) then cfg.port else null; }; lighthouses = lib.optionals (!cfg.isLighthouse) [ cfg.lighthouseNebulaIp ]; -- 2.54.0 From a1bef073cf387fcfa51afd1f8986fda7cda74f08 Mon Sep 17 00:00:00 2001 From: Greg Hellings Date: Wed, 1 Apr 2026 17:20:46 -0500 Subject: [PATCH 7/8] fix: generate linode certs --- secrets/nebula/linode.crt | 6 ++++++ secrets/nebula/linode.key.age | 38 +++++++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+) create mode 100644 secrets/nebula/linode.crt create mode 100644 secrets/nebula/linode.key.age diff --git a/secrets/nebula/linode.crt b/secrets/nebula/linode.crt new file mode 100644 index 0000000..d053da7 --- /dev/null +++ b/secrets/nebula/linode.crt @@ -0,0 +1,6 @@ +-----BEGIN NEBULA CERTIFICATE V2----- +MIGloD+ABmxpbm9kZaEHBAUKnQABEIUEac2aEoYEa668pYcgg4lMYGB2VakRFO6b +K9vHSLzjZpuqhBVQ7MReOwUHQKyCIEFgo5SZK7RybOKbcnXELxD4/L6k6y/YWOoJ +gGfhTdE0g0BeK8VBDuyxp+5rBUWhJaYMBfWJ2qidGwpeGQ+KgVew5auaf+wv4vek +LopzejwCv7rKAIKoB7fNO1HDbYw2WXYG +-----END NEBULA CERTIFICATE V2----- diff --git a/secrets/nebula/linode.key.age b/secrets/nebula/linode.key.age new file mode 100644 index 0000000..3c97e78 --- /dev/null +++ b/secrets/nebula/linode.key.age @@ -0,0 +1,38 @@ +age-encryption.org/v1 +-> ssh-ed25519 87huqg DhN/+7v38sO9JrmbpYWtu324Giuair8QxWiDQCSt5gk +Waw20Mw9N+8HVLfpmAb6bxtwNTOJKIQNF9RAt2CizaM +-> ssh-ed25519 8UnW5Q 7xjuMFRQnDI0EVMIG3r+lBQ/iQp+5cuP/e8Hd1Z6yl8 +7YKREAZx2VSXr1SdiVuSbi8zzsbgWo7oXhwQmTCxC00 +-> ssh-ed25519 UFfTmg ZYevBcuVZGZM/00QmV5exil67o6Dvu51PS8d5LDSmWE +ddT6lI7aWXeefOuUoU3YdNBY/ZTqwVmAAtJY2FPUYRY +-> ssh-ed25519 xNtnoA TE1vwgCi+E3yTyIdLlC6Yj9ZsNDKqwN/bqwtB2SZXnI +tle+S8sDQQcADhsiwmHCZpgu3WxfVujDeZeaie3wIi0 +-> ssh-ed25519 aY2AXA Mgq42aCTJTM5wTrsBB/WiX8oA9cQZkeTNg2e/jkqSX4 +Ken49j/VMBWMr9jmwEi1RjiDThmUR9rUhVqyiMTrhNc +-> ssh-ed25519 AQhf1g /6VEx46A9pI/UZnu25SOnSND+weefGyjbX63WclcgBo +MI7RqhtaEd4FWjIrZNYRiGU9ukiRMfFYW73NC9Pn0n4 +-> ssh-ed25519 mOmPfg rQC30TaeT1LvDO1AsjfLrGRLpolDPoCAjtjvk5jpM3A +Mtvq40Vkdy8GlYYRADERH7R7TrOrMmgc4L53a2S53X0 +-> ssh-ed25519 YJiRbw pjzxg4h4RsReraBckNC4lrou7mrcLrFMKBQFelVZIS8 +nSp+SiiR28F2qEyQOmtkyjLI8me5soL99ZfX2CyCtOQ +-> ssh-ed25519 0/WsKg gJDZIO6jB2X7JcxvBQoKUjs+CmC3dM7/o86ayxuzDAM +J1GJ8QCsdm+MV5vLKy0lDEZphcqtncdHA3Uhswtbjfk +-> ssh-ed25519 Nl/5yA k+mNdOtNlcUtvijYanWqE6Jqx3BtssT9WlgrII53JFY +qMFDbWsK7oqkn3+n29pupruUH1aL1GJTPdnHcd/saaU +-> ssh-ed25519 GdLgCQ s1oCQaEMJamaGiUNwRJYGDmcnmjMs/pSUDp8MW0biy4 +ckhFXcx1t18WjY/W1urrNmZ9qab3dIlEqs5e1AaJrjE +-> ssh-ed25519 tOH/HQ EDPn55ZqtWAphmJJw+zW7RowoLyZ5Vo5Rn6LcmtHGxA ++HSdz8oRjjr+2oXPcce5u72z7iN5LmFRULxVhCsFenY +-> ssh-ed25519 FpzvfQ tJYYwIiFw+kdI6LHBd1QSh3eRprF9pTubyLfUN+JsXQ +zSR6ptxNZNLuktnRdw6wzf2TwRh5sBncJgZfqSBGMc8 +-> ssh-ed25519 kdPvzQ WiR1O62lBJQCzQF021arLQuEKJOQm3mqa5dy927IFlE +asbdcEecJRVTaasDhtAb2mB6p8gELA53nHG0bhp9j4w +-> ssh-ed25519 onmXpg IlP7xoTg6qbCbeg4c7jGtUTueI2q5OWT8ot/tBZW0HY +kHNPz3hUsQZuwsJRol6BwvExp8keJzcl0K4G9VELcBk +-> ssh-ed25519 CnhD0g wVmnrThi15hQJ1JIiazwo9Tk8Hns9ALkG1Aps8gcYz4 +sSy1EVAvdZAWyDI6WJfs+UQ3E8SCGq+qVQzVhrd/GXw +-> ssh-ed25519 4ep2UA nUckpcS8Sa5+RF7/Z5nexV7S5h9hFoj+UAfFzq7lQwk +hrZPftJLld4FvSDnsQC7zb/yLJujY7Jm4wki1qHunoY +--- o/cAY7EryjxlJn9BxuyQQE1s1Bwj8AIupTBMEAz+CLo +_PLҋ"oĨ0N%kfύ.[ZUtI,f驱 +ϙzgQ]LYr Bq-RїsyLfY*IifV') jV8 h0}f [ӣR!{ՇTMth \ No newline at end of file -- 2.54.0 From 88d9234332f123547cbefbcd9ad6e079a2f4b50c Mon Sep 17 00:00:00 2001 From: Greg Hellings Date: Thu, 2 Apr 2026 08:11:32 -0500 Subject: [PATCH 8/8] fix: no default routes --- modules/nixos/nebula.nix | 63 ++++++++++++++++++---------------------- 1 file changed, 29 insertions(+), 34 deletions(-) diff --git a/modules/nixos/nebula.nix b/modules/nixos/nebula.nix index 517ce4b..46f0467 100644 --- a/modules/nixos/nebula.nix +++ b/modules/nixos/nebula.nix @@ -52,7 +52,8 @@ in let hostData = metadata.hosts.${config.networking.hostName} or { }; in - hostData.nebulaIp or (throw "greg.nebula.nebulaIp must be set for host ${config.networking.hostName}"); + hostData.nebulaIp + or (throw "greg.nebula.nebulaIp must be set for host ${config.networking.hostName}"); }; lighthouseAddr = lib.mkOption { @@ -96,12 +97,7 @@ in ); # Default: route the home LAN through genesis (the home router node). # Hosts that ARE genesis (or any other routing node) should override this to []. - default = [ - { - route = "10.42.0.0/16"; - via = "10.157.0.2"; # genesis's Nebula IP - } - ]; + default = [ ]; description = '' List of unsafe_routes to configure on this host (for reaching non-Nebula subnets). Defaults to routing the home LAN (10.42.0.0/16) through genesis (10.157.0.2). @@ -126,7 +122,7 @@ in # agenix: decrypt this host's Nebula private key at boot age.secrets."nebula-${config.networking.hostName}-key" = { file = ../../secrets/nebula/${config.networking.hostName}.key.age; - # nebula service runs as root, key owned by root is fine + owner = config.systemd.services."nebula@${nebulaDomain}".serviceConfig.User; mode = "0400"; }; @@ -165,7 +161,7 @@ in device = "nebula0"; }; - settings.tun.unsafe_routes = map (r: { route = r.route; via = r.via; }) cfg.unsafeRoutes; + settings.tun.unsafe_routes = cfg.unsafeRoutes; # Firewall: permissive defaults — tighten per-host as desired firewall = { @@ -176,31 +172,30 @@ in host = "any"; } ]; - inbound = - [ - # Allow ICMP (ping) from any Nebula peer - { - port = "any"; - proto = "icmp"; - host = "any"; - } - # Allow all traffic from within the Nebula overlay - { - port = "any"; - proto = "any"; - host = "any"; - } - ] - # When routing an unsafe subnet, allow inbound traffic destined - # for that subnet from any Nebula peer (local_cidr scopes it) - ++ lib.optionals (cfg.routesSubnet != null) [ - { - port = "any"; - proto = "any"; - host = "any"; - local_cidr = cfg.routesSubnet; - } - ]; + inbound = [ + # Allow ICMP (ping) from any Nebula peer + { + port = "any"; + proto = "icmp"; + host = "any"; + } + # Allow all traffic from within the Nebula overlay + { + port = "any"; + proto = "any"; + host = "any"; + } + ] + # When routing an unsafe subnet, allow inbound traffic destined + # for that subnet from any Nebula peer (local_cidr scopes it) + ++ lib.optionals (cfg.routesSubnet != null) [ + { + port = "any"; + proto = "any"; + host = "any"; + local_cidr = cfg.routesSubnet; + } + ]; }; }; -- 2.54.0