From 2575562c74591e3ac6819db6defea5070b266ccc Mon Sep 17 00:00:00 2001 From: min Date: Sat, 14 Dec 2024 18:15:55 -0500 Subject: [PATCH] Make a module for Nebula mesh (and fix hardening module) --- flake.lock | 154 ++----------------------- flake.nix | 11 -- nixos/hosts/eidola/nebula.nix | 51 +------- nixos/hosts/silver/disk-config.nix | 2 +- nixos/hosts/silver/secrets.nix | 2 +- nixos/hosts/silver/services/nebula.nix | 53 ++------- nixos/modules/boot/luks-ssh.nix | 15 +-- nixos/modules/default.nix | 1 + nixos/modules/hardening.nix | 32 ++--- nixos/modules/nebula/default.nix | 107 +++++++++++++++++ nixos/modules/nebula/shared.nix | 8 ++ 11 files changed, 164 insertions(+), 272 deletions(-) create mode 100644 nixos/modules/nebula/default.nix create mode 100644 nixos/modules/nebula/shared.nix diff --git a/flake.lock b/flake.lock index b334229..4d30514 100644 --- a/flake.lock +++ b/flake.lock @@ -37,25 +37,6 @@ "type": "github" } }, - "crane_2": { - "inputs": { - "nixpkgs": "nixpkgs_2" - }, - "locked": { - "lastModified": 1717383740, - "narHash": "sha256-559HbY4uhNeoYvK3H6AMZAtVfmR3y8plXZ1x6ON/cWU=", - "owner": "ipetkov", - "repo": "crane", - "rev": "b65673fce97d277934488a451724be94cc62499a", - "type": "github" - }, - "original": { - "owner": "ipetkov", - "ref": "v0.17.3", - "repo": "crane", - "type": "github" - } - }, "deploy-rs": { "inputs": { "flake-compat": "flake-compat", @@ -85,11 +66,11 @@ ] }, "locked": { - "lastModified": 1734011192, - "narHash": "sha256-NghuiWXx6Q3gwLiudiNwDpYQ1CPEUK7J+f9dWREN8KA=", + "lastModified": 1734088167, + "narHash": "sha256-OIitVU+IstPbX/NWn2jLF+/sT9dVKcO2FKeRAzlyX6c=", "owner": "nix-community", "repo": "disko", - "rev": "0f31ad735e784315a22d9899d3ba24340ce64220", + "rev": "d32f2d1750d61a476a236526b725ec5a32e16342", "type": "github" }, "original": { @@ -114,21 +95,6 @@ "type": "github" } }, - "flake-compat_2": { - "locked": { - "lastModified": 1696426674, - "narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=", - "owner": "edolstra", - "repo": "flake-compat", - "rev": "0f9255e01c2351cc7d116c072cb317785dd33b33", - "type": "github" - }, - "original": { - "owner": "edolstra", - "repo": "flake-compat", - "type": "github" - } - }, "flake-parts": { "inputs": { "nixpkgs-lib": "nixpkgs-lib" @@ -167,11 +133,11 @@ }, "impermanence": { "locked": { - "lastModified": 1731242966, - "narHash": "sha256-B3C3JLbGw0FtLSWCjBxU961gLNv+BOOBC6WvstKLYMw=", + "lastModified": 1734200366, + "narHash": "sha256-0NursoP4BUdnc+wy+Mq3icHkXu/RgP1Sjo0MJxV2+Dw=", "owner": "nix-community", "repo": "impermanence", - "rev": "3ed3f0eaae9fcc0a8331e77e9319c8a4abd8a71a", + "rev": "c6323585fa0035d780e3d8906eb1b24b65d19a48", "type": "github" }, "original": { @@ -198,11 +164,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1733730953, - "narHash": "sha256-dlK7n82FEyZlHH7BFHQAM5tua+lQO1Iv7aAtglc1O5s=", + "lastModified": 1734017764, + "narHash": "sha256-msOfmyJSjAHgIygI/JD0Ae3JsDv4rT54Nlfr5t6MQMQ=", "owner": "nixos", "repo": "nixpkgs", - "rev": "7109b680d161993918b0a126f38bc39763e5a709", + "rev": "64e9404f308e0f0a0d8cdd7c358f74e34802494b", "type": "github" }, "original": { @@ -224,74 +190,6 @@ "url": "https://github.com/NixOS/nixpkgs/archive/5487e69da40cbd611ab2cadee0b4637225f7cfae.tar.gz" } }, - "nixpkgs-stable": { - "locked": { - "lastModified": 1723556749, - "narHash": "sha256-+CHVZnTnIYRLYsARInHYoWkujzcRkLY/gXm3s5bE52o=", - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "4a92571f9207810b559c9eac203d1f4d79830073", - "type": "github" - }, - "original": { - "id": "nixpkgs", - "ref": "nixos-24.05", - "type": "indirect" - } - }, - "nixpkgs-unstable": { - "locked": { - "lastModified": 1723637854, - "narHash": "sha256-med8+5DSWa2UnOqtdICndjDAEjxr5D7zaIiK4pn0Q7c=", - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "c3aa7b8938b17aebd2deecf7be0636000d62a2b9", - "type": "github" - }, - "original": { - "id": "nixpkgs", - "ref": "nixos-unstable", - "type": "indirect" - } - }, - "nixpkgs_2": { - "locked": { - "lastModified": 1714656196, - "narHash": "sha256-kjQkA98lMcsom6Gbhw8SYzmwrSo+2nruiTcTZp5jK7o=", - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "94035b482d181af0a0f8f77823a790b256b7c3cc", - "type": "github" - }, - "original": { - "owner": "NixOS", - "ref": "nixpkgs-unstable", - "repo": "nixpkgs", - "type": "github" - } - }, - "proxmox-nixos": { - "inputs": { - "crane": "crane_2", - "flake-compat": "flake-compat_2", - "nixpkgs-stable": "nixpkgs-stable", - "nixpkgs-unstable": "nixpkgs-unstable", - "utils": "utils_2" - }, - "locked": { - "lastModified": 1732473775, - "narHash": "sha256-WnckT473A+DcYYdzLFWgP4RSAvBNaSRw7fJuKySX+Og=", - "owner": "SaumonNet", - "repo": "proxmox-nixos", - "rev": "06fbc351ff461d26a8276f44088450c965195e10", - "type": "github" - }, - "original": { - "owner": "SaumonNet", - "repo": "proxmox-nixos", - "type": "github" - } - }, "root": { "inputs": { "breeze": "breeze", @@ -301,7 +199,6 @@ "impermanence": "impermanence", "min-rip": "min-rip", "nixpkgs": "nixpkgs", - "proxmox-nixos": "proxmox-nixos", "sops-nix": "sops-nix" } }, @@ -355,21 +252,6 @@ "type": "github" } }, - "systems_3": { - "locked": { - "lastModified": 1681028828, - "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", - "owner": "nix-systems", - "repo": "default", - "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", - "type": "github" - }, - "original": { - "owner": "nix-systems", - "repo": "default", - "type": "github" - } - }, "utils": { "inputs": { "systems": "systems_2" @@ -387,24 +269,6 @@ "repo": "flake-utils", "type": "github" } - }, - "utils_2": { - "inputs": { - "systems": "systems_3" - }, - "locked": { - "lastModified": 1710146030, - "narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=", - "owner": "numtide", - "repo": "flake-utils", - "rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a", - "type": "github" - }, - "original": { - "owner": "numtide", - "repo": "flake-utils", - "type": "github" - } } }, "root": "root", diff --git a/flake.nix b/flake.nix index 828ebd4..ec81ee9 100644 --- a/flake.nix +++ b/flake.nix @@ -17,8 +17,6 @@ impermanence.url = "github:nix-community/impermanence"; - proxmox-nixos.url = "github:SaumonNet/proxmox-nixos"; - min-rip.url = "git+ssh://git@git.min.rip/min/min.rip.git"; min-rip.flake = false; @@ -26,15 +24,6 @@ breeze.inputs.nixpkgs.follows = "nixpkgs"; }; - nixConfig = { - extra-substituters = [ - "https://cache.saumon.network/proxmox-nixos" - ]; - extra-trusted-public-keys = [ - "proxmox-nixos:nveXDuVVhFDRFx8Dn19f1WDEaNRJjPrF2CPD2D+m1ys=" - ]; - }; - outputs = inputs @ {self, ...}: inputs.flake-parts.lib.mkFlake {inherit inputs;} { flake = let diff --git a/nixos/hosts/eidola/nebula.nix b/nixos/hosts/eidola/nebula.nix index 2cced08..70118b5 100644 --- a/nixos/hosts/eidola/nebula.nix +++ b/nixos/hosts/eidola/nebula.nix @@ -1,11 +1,5 @@ {config, ...}: let - netName = "m-infra"; - # https://github.com/NixOS/nixpkgs/blob/nixos-24.05/nixos/modules/services/networking/nebula.nix#L12 - userGroup = "nebula-${netName}"; - interface = "nebula.${netName}"; - service = "nebula@${netName}.service"; - lhs = {"10.13.0.1" = ["min.rip:4242"];}; # TODO: hardcoding - lhsInt = builtins.attrNames lhs; + inherit (import ../../modules/nebula/shared.nix) userGroup; in { sops.secrets."nebula-key" = { mode = "0440"; @@ -13,49 +7,14 @@ in { group = userGroup; }; - networking.firewall.trustedInterfaces = [interface]; + gen.nebula = { + enable = true; + enableLighthouse = false; - # Make sure sshd starts after nebula - systemd.services.sshd.after = [service]; - - services.nebula.networks.${netName} = { - ca = ../../keys/ca.crt; cert = ../../keys/n-srv-eidola.crt; key = config.sops.secrets."nebula-key".path; - lighthouses = lhsInt; - relays = lhsInt; - staticHostMap = lhs; - - settings.punchy.punch = true; - - firewall.outbound = [ - { - port = "any"; - proto = "any"; - host = "any"; - } - ]; - - firewall.inbound = [ - # Allow pings from anyone - { - port = "any"; - proto = "icmp"; - host = "any"; - } - # Allow anything from `internal` group - { - port = "any"; - proto = "any"; - groups = ["internal"]; - } - # Allow SSH from anyone - { - port = 22; - proto = "tcp"; - host = "any"; - } + extraInbound = [ # Allow iperf3 from anyone { port = 5201; diff --git a/nixos/hosts/silver/disk-config.nix b/nixos/hosts/silver/disk-config.nix index be6f6eb..e33e7d7 100644 --- a/nixos/hosts/silver/disk-config.nix +++ b/nixos/hosts/silver/disk-config.nix @@ -3,7 +3,7 @@ disk = { main = { type = "disk"; - device = "/dev/vda"; # TODO: hardcoding (not sure if fixable) + device = "/dev/vda"; content = { type = "gpt"; diff --git a/nixos/hosts/silver/secrets.nix b/nixos/hosts/silver/secrets.nix index 285c1f8..0e29d19 100644 --- a/nixos/hosts/silver/secrets.nix +++ b/nixos/hosts/silver/secrets.nix @@ -1,5 +1,5 @@ {...}: { - sops = { # TODO: hardcoding + sops = { defaultSopsFile = ../../../secrets/silver.yaml; age.sshKeyPaths = ["/persist/etc/ssh/ssh_host_ed25519_key"]; diff --git a/nixos/hosts/silver/services/nebula.nix b/nixos/hosts/silver/services/nebula.nix index a1d2b78..0ecb745 100644 --- a/nixos/hosts/silver/services/nebula.nix +++ b/nixos/hosts/silver/services/nebula.nix @@ -1,8 +1,5 @@ {config, ...}: let - netName = "m-infra"; # TODO: hardcoding - # https://github.com/NixOS/nixpkgs/blob/nixos-24.05/nixos/modules/services/networking/nebula.nix#L12 - userGroup = "nebula-${netName}"; - interface = "nebula.${netName}"; + inherit (import ../../../modules/nebula/shared.nix) userGroup; in { sops.secrets."svc-nebula-key" = { mode = "0440"; @@ -10,51 +7,15 @@ in { group = userGroup; }; - networking.firewall = { - trustedInterfaces = [interface]; - allowedUDPPorts = [4242]; - }; + networking.firewall.allowedUDPPorts = [4242]; + + gen.nebula = { + enable = true; + enableLighthouse = true; - services.nebula.networks.${netName} = { - ca = ../../../keys/ca.crt; cert = ../../../keys/lh-silver.crt; key = config.sops.secrets."svc-nebula-key".path; - isLighthouse = true; - isRelay = true; - - listen = { - host = "0.0.0.0"; - port = 4242; - }; - - firewall.outbound = [ - { - port = "any"; - proto = "any"; - host = "any"; - } - ]; - - firewall.inbound = [ - # Allow pings from anyone - { - port = "any"; - proto = "icmp"; - host = "any"; - } - # Allow anything from `internal` group - { - port = "any"; - proto = "any"; - groups = ["internal"]; - } - # Allow SSH from anyone - { - port = 22; - proto = "tcp"; - host = "any"; - } - ]; + extraInbound = []; }; } diff --git a/nixos/modules/boot/luks-ssh.nix b/nixos/modules/boot/luks-ssh.nix index 670996d..2f1cc83 100644 --- a/nixos/modules/boot/luks-ssh.nix +++ b/nixos/modules/boot/luks-ssh.nix @@ -2,23 +2,24 @@ config, lib, ... -}: let +}: +with lib; let baseCfg = config.gen.bootloader; cfg = baseCfg.luksSsh; in { options.gen.bootloader.luksSsh = { - enable = lib.mkEnableOption "use boot process with luks unlock over ssh"; - port = lib.mkOption { - type = lib.types.port; + enable = mkEnableOption "use boot process with luks unlock over ssh"; + port = mkOption { + type = types.port; description = "port for ssh server to listen on"; }; - hostKeys = lib.mkOption { - type = lib.types.listOf lib.types.path; + hostKeys = mkOption { + type = types.listOf types.path; description = "paths of host keys for the ssh server to use"; }; }; - config = lib.mkIf cfg.enable { + config = mkIf cfg.enable { # ### Use systemd-boot ### # boot.loader = { # efi.canTouchEfiVariables = true; diff --git a/nixos/modules/default.nix b/nixos/modules/default.nix index a7d0324..7d83a7d 100644 --- a/nixos/modules/default.nix +++ b/nixos/modules/default.nix @@ -5,6 +5,7 @@ }: { imports = [ ./boot + ./nebula ./hardening.nix ./limits.nix diff --git a/nixos/modules/hardening.nix b/nixos/modules/hardening.nix index 657a1a2..671a7b4 100644 --- a/nixos/modules/hardening.nix +++ b/nixos/modules/hardening.nix @@ -2,20 +2,21 @@ config, lib, ... -}: let +}: +with lib; let cfg = config.gen.hardening; in { options.gen.hardening = { - hardenBpf = lib.mkEnableOption "place heavier restrictions on BPF"; - fullRpFilter = lib.mkEnableOption "enable full reverse path filtering. breaks dynamic routing, probably"; - ignoreIcmpEcho = lib.mkEnableOption "ignore icmp echos. obviously, this makes pings unresponsive"; - disableSack = lib.mkEnableOption "disable tcp sack"; - disableConsole = lib.mkEnableOption "disable console. not recommended for test machines"; + hardenBpf = mkEnableOption "place heavier restrictions on BPF"; + fullRpFilter = mkEnableOption "full reverse path filtering. (breaks dynamic routing, probably)"; + ignoreIcmpEcho = mkEnableOption "ignore icmp echos. (obviously, this makes pings unresponsive)"; + disableSack = mkEnableOption "disable tcp sack"; + disableConsole = mkEnableOption "disable console. (not recommended for test machines)"; }; config = { ### Sysctls ### - boot.kernel.sysctl = + boot.kernel.sysctl = mkMerge [ { "kernel.kptr_restrict" = 1; "kernel.dmesg_restrict" = 1; @@ -27,22 +28,23 @@ in { "kernel.perf_event_paranoid" = 3; "net.ipv4.tcp_rfc1337" = 1; # drop RSTs during time-wait state } - // lib.mkIf cfg.ignoreIcmpEcho { + (mkIf cfg.ignoreIcmpEcho { "net.ipv4.icmp_echo_ignore_all" = 1; - } - // lib.mkIf cfg.hardenBpf { + }) + (mkIf cfg.hardenBpf { "kernel.unprivileged_bpf_disabled" = 1; "net.core.bpf_jit_harden" = 2; - } - // lib.mkIf cfg.fullRpFilter { + }) + (mkIf cfg.fullRpFilter { "net.ipv4.conf.all.rp_filter" = 1; "net.ipv4.conf.default.rp_filter" = 1; - } - // lib.mkIf cfg.disableSack { + }) + (mkIf cfg.disableSack { "net.ipv4.tcp_sack" = 0; "net.ipv4.tcp_dsack" = 0; "net.ipv4.tcp_fack" = 0; - }; + }) + ]; ### Security options ### security.protectKernelImage = true; diff --git a/nixos/modules/nebula/default.nix b/nixos/modules/nebula/default.nix new file mode 100644 index 0000000..b537aa4 --- /dev/null +++ b/nixos/modules/nebula/default.nix @@ -0,0 +1,107 @@ +{ + config, + lib, + ... +}: +with lib; let + inherit (import ./shared.nix) netName interface service; + + ca = ../../keys/ca.crt; + + baseFirewall = { + outbound = [ + # Allow all outbound traffic + { + port = "any"; + proto = "any"; + host = "any"; + } + ]; + inbound = [ + # Allow pings from anyone + { + port = "any"; + proto = "icmp"; + host = "any"; + } + # Allow anything from `internal` group + { + port = "any"; + proto = "any"; + groups = ["internal"]; + } + # Allow SSH from anyone + { + port = 22; + proto = "tcp"; + host = "any"; + } + ]; + }; + + baseServer = { + isLighthouse = true; + isRelay = true; + + listen = { + host = "0.0.0.0"; + port = 4242; + }; + }; + baseClient = let + lhs = {"10.13.0.1" = ["min.rip:4242"];}; + lhsInternal = attrNames lhs; + in { + lighthouses = lhsInternal; + relays = lhsInternal; + staticHostMap = lhs; + + settings.punchy.punch = true; + }; + + cfg = config.gen.nebula; +in { + options.gen.nebula = { + enable = mkEnableOption "nebula mesh vpn"; + enableLighthouse = mkEnableOption "lighthouse functionality"; + + cert = mkOption { + type = types.path; + description = "nebula node cert path"; + }; + key = mkOption { + type = types.path; + description = "nebula node key path"; + }; + + extraInbound = mkOption { + type = types.listOf types.attrs; + description = "extra inbound firewall rules"; + }; + }; + + config = mkMerge [ + (mkIf cfg.enable { + networking.firewall.trustedInterfaces = [interface]; + + services.nebula.networks.${netName} = mkMerge [ + { + inherit ca; + inherit (cfg) cert key; + + firewall = { + inherit (baseFirewall) outbound; + inbound = baseFirewall.inbound ++ cfg.extraInbound; + }; + } + (mkIf cfg.enableLighthouse baseServer) + (mkIf (!cfg.enableLighthouse) baseClient) + ]; + }) + (mkIf config.services.openssh.enable { + # Make sure sshd starts after nebula + # TODO: is this necessary? + systemd.services.sshd.after = [service]; + }) + ]; +} diff --git a/nixos/modules/nebula/shared.nix b/nixos/modules/nebula/shared.nix new file mode 100644 index 0000000..34d0b55 --- /dev/null +++ b/nixos/modules/nebula/shared.nix @@ -0,0 +1,8 @@ +rec { + netName = "m-infra"; + + # https://github.com/NixOS/nixpkgs/blob/nixos-24.05/nixos/modules/services/networking/nebula.nix + interface = "nebula.${netName}"; + userGroup = "nebula-${netName}"; + service = "nebula@${netName}.service"; +}