diff --git a/hosts/unstable/exodus/default.nix b/hosts/unstable/exodus/default.nix index 81da8e4..84b6c00 100644 --- a/hosts/unstable/exodus/default.nix +++ b/hosts/unstable/exodus/default.nix @@ -30,6 +30,9 @@ greg = { home = true; gnome.enable = true; + nebula = { + enable = true; + }; podman.enable = true; print.enable = true; tailscale = { diff --git a/hosts/unstable/genesis/default.nix b/hosts/unstable/genesis/default.nix index ee7d8a6..767d156 100644 --- a/hosts/unstable/genesis/default.nix +++ b/hosts/unstable/genesis/default.nix @@ -35,6 +35,15 @@ in greg = { home = true; 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"; + }; proxies = { }; }; diff --git a/hosts/unstable/hosea/default.nix b/hosts/unstable/hosea/default.nix index a9a06a5..537be9c 100644 --- a/hosts/unstable/hosea/default.nix +++ b/hosts/unstable/hosea/default.nix @@ -49,6 +49,7 @@ in greg = { home = true; + 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 8e52f61..c50e64d 100644 --- a/hosts/unstable/isaiah/default.nix +++ b/hosts/unstable/isaiah/default.nix @@ -42,6 +42,7 @@ vip = metadata.hosts.${config.networking.hostName}.ip; priority = 255; }; + nebula.enable = true; podman.enable = true; tailscale = { enable = true; diff --git a/hosts/unstable/jeremiah/default.nix b/hosts/unstable/jeremiah/default.nix index 90a3cd1..48d79fe 100644 --- a/hosts/unstable/jeremiah/default.nix +++ b/hosts/unstable/jeremiah/default.nix @@ -85,6 +85,7 @@ in vip = ip; priority = 254; }; + nebula.enable = true; 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..0ecfa6f 100644 --- a/hosts/unstable/zeke/default.nix +++ b/hosts/unstable/zeke/default.nix @@ -26,6 +26,7 @@ vipInterface = "enp12s0"; priority = 253; }; + nebula.enable = true; 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..46f0467 --- /dev/null +++ b/modules/nixos/nebula.nix @@ -0,0 +1,229 @@ +{ + 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: route the home LAN through genesis (the home router node). + # Hosts that ARE genesis (or any other routing node) should override this to []. + 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). + Override to [] on hosts that are themselves a routing node (e.g. genesis). + ''; + }; + + # 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; + owner = config.systemd.services."nebula@${nebulaDomain}".serviceConfig.User; + 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"; + # 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 ]; + + relays = lib.optionals (!cfg.isLighthouse && !cfg.isRelay) [ cfg.lighthouseNebulaIp ]; + + tun = { + # Interface name + device = "nebula0"; + }; + + settings.tun.unsafe_routes = 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/.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/.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/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 0000000..0b1c099 Binary files /dev/null and b/secrets/nebula/exodus.key.age differ diff --git a/secrets/nebula/genesis.crt b/secrets/nebula/genesis.crt new file mode 100644 index 0000000..e3b16fb --- /dev/null +++ b/secrets/nebula/genesis.crt @@ -0,0 +1,6 @@ +-----BEGIN NEBULA CERTIFICATE V2----- +MIGvoEmAB2dlbmVzaXOhBwQFCp0AAhCiBwQFCioAABCFBGnNjNCGBGuuvKWHIIOJ +TGBgdlWpERTumyvbx0i842abqoQVUOzEXjsFB0CsgiAgHipBP9jhM6AtUoB6/NLR +6Ijhq9VYjlJqJcu02sDseYNAxzppNhLFQ8Q8aZiYDe8Tt8U9HbBZERXS80hmia8a +6nUcpsL6tgc7n1hq/a4CxsSWoz8desGBF/BZKq4qEzwwBQ== +-----END NEBULA CERTIFICATE V2----- diff --git a/secrets/nebula/genesis.key.age b/secrets/nebula/genesis.key.age new file mode 100644 index 0000000..f879a96 --- /dev/null +++ b/secrets/nebula/genesis.key.age @@ -0,0 +1,38 @@ +age-encryption.org/v1 +-> 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 0000000..0a8b0b2 Binary files /dev/null and b/secrets/nebula/isaiah.key.age differ 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/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 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 0000000..261c25f Binary files /dev/null and b/secrets/nebula/zeke.key.age differ 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; }