diff --git a/flake-parts/hosts.nix b/flake-parts/hosts.nix index 675f99f..55592fb 100644 --- a/flake-parts/hosts.nix +++ b/flake-parts/hosts.nix @@ -22,7 +22,7 @@ let mkDeployNode = hostname: { hostname = "${hostname}.${ - self.nixosConfigurations.${hostname}.config.custom.networking.overlay.domain + self.nixosConfigurations.${hostname}.config.custom.services.nebula.network.domain }"; user = "root"; interactiveSudo = true; diff --git a/hosts/desktop/default.nix b/hosts/desktop/default.nix index 8a69df1..a06baa7 100644 --- a/hosts/desktop/default.nix +++ b/hosts/desktop/default.nix @@ -23,17 +23,14 @@ }; de.hyprland.enable = true; - networking = { - overlay.address = "10.254.250.1"; - underlay.interface = "enp6s0"; - isClient = true; - }; - services = { gc.enable = true; sound.enable = true; - nebula.enable = true; - sshd.enable = true; + nebula.node = { + enable = true; + address = "10.254.250.1"; + isClient = true; + }; syncthing = { enable = true; deviceId = "FAJS5WM-UAWGW2U-FXCGPSP-VAUOTGM-XUKSEES-D66PMCJ-WBODJLV-XTNCRA7"; diff --git a/hosts/laptop/default.nix b/hosts/laptop/default.nix index 8f4acea..0f13386 100644 --- a/hosts/laptop/default.nix +++ b/hosts/laptop/default.nix @@ -23,20 +23,17 @@ }; de.hyprland.enable = true; - networking = { - overlay.address = "10.254.250.3"; - underlay.interface = "wlan0"; - isClient = true; - }; - services = { resolved.enable = true; gc.enable = true; wlan.enable = true; bluetooth.enable = true; sound.enable = true; - nebula.enable = true; - sshd.enable = true; + nebula.node = { + enable = true; + address = "10.254.250.3"; + isClient = true; + }; syncthing = { enable = true; deviceId = "Q4YPD3V-GXZPHSN-PT5X4PU-FBG4GX2-IASBX75-7NYMG75-4EJHBMZ-4WGDDAP"; diff --git a/hosts/laptop/hardware.nix b/hosts/laptop/hardware.nix index 20515ef..211eb00 100644 --- a/hosts/laptop/hardware.nix +++ b/hosts/laptop/hardware.nix @@ -40,17 +40,4 @@ HibernateDelaySec=2h HibernateOnACPower=yes ''; - - networking.useNetworkd = true; - systemd.network = { - enable = true; - networks."10-wlan0" = { - matchConfig.Name = "wlan0"; - linkConfig.RequiredForOnline = "routable"; - networkConfig = { - DHCP = "yes"; - IgnoreCarrierLoss = "3s"; - }; - }; - }; } diff --git a/hosts/vps-monitor/default.nix b/hosts/vps-monitor/default.nix index 3b580c8..554782f 100644 --- a/hosts/vps-monitor/default.nix +++ b/hosts/vps-monitor/default.nix @@ -20,31 +20,25 @@ boot.loader.grub.enable = true; - networking = { - overlay.address = "10.254.250.5"; - underlay = { - interface = "enp1s0"; - address = "188.245.223.145"; - isPublic = true; - }; - isLighthouse = true; - isServer = true; - }; - services = { gc = { enable = true; onlyCleanRoots = true; }; - nebula.node.enable = true; - sshd.enable = true; - dns.enable = true; + nebula.node = { + enable = true; + address = "10.254.250.5"; + routableAddress = "188.245.223.145"; + isLighthouse = true; + isServer = true; + dns.enable = true; + }; }; web-services = let - privateDomain = config.custom.networking.overlay.domain; + privateDomain = config.custom.services.nebula.network.domain; in { gatus = { diff --git a/hosts/vps-private/default.nix b/hosts/vps-private/default.nix index 5888e01..0850461 100644 --- a/hosts/vps-private/default.nix +++ b/hosts/vps-private/default.nix @@ -15,7 +15,7 @@ custom = let - privateDomain = config.custom.networking.overlay.domain; + privateDomain = config.custom.services.nebula.network.domain; in { persistence.enable = true; @@ -24,26 +24,20 @@ boot.loader.systemd-boot.enable = true; - networking = { - overlay.address = "10.254.250.2"; - underlay = { - interface = "enp1s0"; - address = "49.13.231.235"; - isPublic = true; - }; - isLighthouse = true; - isServer = true; - }; - services = { gc = { enable = true; onlyCleanRoots = true; }; - nebula.node.enable = true; - sshd.enable = true; - dns.enable = true; + nebula.node = { + enable = true; + address = "10.254.250.2"; + routableAddress = "49.13.231.235"; + isLighthouse = true; + isServer = true; + dns.enable = true; + }; syncthing = { enable = true; diff --git a/hosts/vps-public/default.nix b/hosts/vps-public/default.nix index c35d0f5..7d897d5 100644 --- a/hosts/vps-public/default.nix +++ b/hosts/vps-public/default.nix @@ -20,24 +20,18 @@ boot.loader.systemd-boot.enable = true; - networking = { - overlay.address = "10.254.250.4"; - underlay = { - interface = "enp1s0"; - address = "167.235.73.246"; - isPublic = true; - }; - isServer = true; - }; - services = { gc = { enable = true; onlyCleanRoots = true; }; - nebula.node.enable = true; - sshd.enable = true; + nebula.node = { + enable = true; + address = "10.254.250.4"; + routableAddress = "167.235.73.246"; + isServer = true; + }; crowdsec = { enable = true; @@ -82,7 +76,7 @@ alloy = { enable = true; - domain = "alloy.${config.networking.hostName}.${config.custom.networking.overlay.domain}"; + domain = "alloy.${config.networking.hostName}.${config.custom.services.nebula.network.domain}"; }; }; }; diff --git a/modules/system/networking.nix b/modules/system/networking.nix deleted file mode 100644 index db3d7d6..0000000 --- a/modules/system/networking.nix +++ /dev/null @@ -1,90 +0,0 @@ -{ - config, - self, - lib, - ... -}: -let - cfg = config.custom.networking; -in -{ - options.custom.networking = { - hostname = lib.mkOption { - type = lib.types.nonEmptyStr; - default = config.networking.hostName; - readOnly = true; - }; - isLighthouse = lib.mkEnableOption ""; - isServer = lib.mkEnableOption ""; - isClient = lib.mkEnableOption ""; - - overlay = { - networkAddress = lib.mkOption { - type = lib.types.nonEmptyStr; - default = "10.254.250.0"; - readOnly = true; - }; - prefixLength = lib.mkOption { - type = lib.types.ints.between 0 32; - default = 24; - readOnly = true; - }; - domain = lib.mkOption { - type = lib.types.nonEmptyStr; - default = "splitleaf.de"; - readOnly = true; - }; - - address = lib.mkOption { - type = lib.types.nonEmptyStr; - default = ""; - }; - interface = lib.mkOption { - type = lib.types.nonEmptyStr; - default = "nebula.mesh"; - }; - systemdUnit = lib.mkOption { - type = lib.types.nonEmptyStr; - default = "nebula@mesh.service"; - }; - }; - - underlay = { - interface = lib.mkOption { - type = lib.types.nonEmptyStr; - default = ""; - }; - useDhcp = lib.mkEnableOption ""; - isPublic = lib.mkEnableOption ""; - address = lib.mkOption { - type = lib.types.nullOr lib.types.nonEmptyStr; - default = null; - }; - gateway = lib.mkOption { - type = lib.types.nullOr lib.types.nonEmptyStr; - default = null; - }; - }; - - nodes = lib.mkOption { - type = lib.types.anything; - default = - self.nixosConfigurations - |> lib.attrValues - |> lib.map (host: host.config.custom.networking) - |> lib.map ( - node: - lib.removeAttrs node [ - "nodes" - "peers" - ] - ); - readOnly = true; - }; - peers = lib.mkOption { - type = lib.types.anything; - default = cfg.nodes |> lib.filter (node: node.hostname != cfg.hostname); - readOnly = true; - }; - }; -} diff --git a/modules/system/services/caddy.nix b/modules/system/services/caddy.nix index 1bb4deb..90d242d 100644 --- a/modules/system/services/caddy.nix +++ b/modules/system/services/caddy.nix @@ -6,7 +6,6 @@ }: let cfg = config.custom.services.caddy; - netCfg = config.custom.networking; virtualHosts = cfg.virtualHosts |> lib.attrValues |> lib.filter (value: value.enable); @@ -34,7 +33,7 @@ let in '' tls ${certDir}/fullchain.pem ${certDir}/key.pem - bind ${config.custom.networking.overlay.address} + bind ${config.custom.services.nebula.node.address} '' )) (lib.optionalString (port != null) "reverse_proxy localhost:${toString port}") @@ -151,8 +150,8 @@ in ]; systemd.services.caddy = { - requires = [ netCfg.overlay.systemdUnit ]; - after = [ netCfg.overlay.systemdUnit ]; + requires = [ "nebula@mesh.service" ]; + after = [ "nebula@mesh.service" ]; }; }) ] diff --git a/modules/system/services/nebula/default.nix b/modules/system/services/nebula/default.nix index af31b6e..e6cb193 100644 --- a/modules/system/services/nebula/default.nix +++ b/modules/system/services/nebula/default.nix @@ -5,32 +5,91 @@ ... }: let - cfg = config.custom.services.nebula; - netCfg = config.custom.networking; + nebulaCfg = config.custom.services.nebula; + cfg = nebulaCfg.node; - publicPort = 47141; + hostname = config.networking.hostName; in { options.custom.services.nebula = { - enable = lib.mkEnableOption ""; - - publicKeyPath = lib.mkOption { - type = lib.types.path; - default = "${self}/hosts/${netCfg.hostname}/keys/nebula.pub"; + network = { + address = lib.mkOption { + type = lib.types.nonEmptyStr; + default = "10.254.250.0"; + readOnly = true; + }; + prefixLength = lib.mkOption { + type = lib.types.ints.between 0 32; + default = 24; + readOnly = true; + }; + domain = lib.mkOption { + type = lib.types.nonEmptyStr; + default = "splitleaf.de"; + readOnly = true; + }; }; - certificatePath = lib.mkOption { - type = lib.types.path; - default = "${self}/hosts/${netCfg.hostname}/keys/nebula.crt"; + + node = { + enable = lib.mkEnableOption ""; + name = lib.mkOption { + type = lib.types.nonEmptyStr; + default = hostname; + }; + interface = lib.mkOption { + type = lib.types.nonEmptyStr; + default = "nebula.mesh"; + }; + address = lib.mkOption { + type = lib.types.nonEmptyStr; + default = ""; + }; + isLighthouse = lib.mkEnableOption ""; + isServer = lib.mkEnableOption ""; + isClient = lib.mkEnableOption ""; + + routableAddress = lib.mkOption { + type = lib.types.nullOr lib.types.nonEmptyStr; + default = null; + }; + routablePort = lib.mkOption { + type = lib.types.nullOr lib.types.port; + default = if cfg.routableAddress != null then 47141 else null; + }; + + publicKeyPath = lib.mkOption { + type = lib.types.path; + default = "${self}/hosts/${hostname}/keys/nebula.pub"; + }; + certificatePath = lib.mkOption { + type = lib.types.path; + default = "${self}/hosts/${hostname}/keys/nebula.crt"; + }; + }; + + nodes = lib.mkOption { + type = lib.types.anything; + default = + self.nixosConfigurations + |> lib.attrValues + |> lib.map (value: value.config.custom.services.nebula.node) + |> lib.filter (node: node.enable); + readOnly = true; + }; + peers = lib.mkOption { + type = lib.types.anything; + default = nebulaCfg.nodes |> lib.filter (node: node.name != hostname); + readOnly = true; }; }; config = lib.mkIf cfg.enable { - assertions = lib.singleton { - assertion = netCfg.isLighthouse -> netCfg.underlay.isPublic; - message = "'${netCfg.hostname}' is a Nebula lighthouse, but underlay.isPublic is not set. Lighthouses must be publicly reachable."; - }; + meta.ports.udp = lib.optional (cfg.routablePort != null) cfg.routablePort; - meta.ports.udp = lib.optional (netCfg.underlay.isPublic) publicPort; + assertions = lib.singleton { + assertion = cfg.isLighthouse -> cfg.routableAddress != null; + message = "'${hostname}' is a Nebula lighthouse, but routableAddress is not set. Lighthouses must be publicly reachable."; + }; sops.secrets."nebula/host-key" = { owner = config.users.users.nebula-mesh.name; @@ -44,21 +103,19 @@ in cert = cfg.certificatePath; key = config.sops.secrets."nebula/host-key".path; - listen.port = lib.mkIf netCfg.underlay.isPublic publicPort; + listen.port = cfg.routablePort; - inherit (netCfg) isLighthouse; - lighthouses = lib.mkIf (!netCfg.isLighthouse) ( - netCfg.peers - |> lib.filter (peer: peer.isLighthouse) - |> lib.map (lighthouse: lighthouse.overlay.address) + inherit (cfg) isLighthouse; + lighthouses = lib.mkIf (!cfg.isLighthouse) ( + nebulaCfg.peers |> lib.filter (node: node.isLighthouse) |> lib.map (lighthouse: lighthouse.address) ); staticHostMap = - netCfg.peers - |> lib.filter (peer: peer.underlay.isPublic) - |> lib.map (publicPeer: { - name = publicPeer.overlay.address; - value = lib.singleton "${publicPeer.underlay.address}:${toString publicPort}"; + nebulaCfg.peers + |> lib.filter (node: node.routableAddress != null) + |> lib.map (lighthouse: { + name = lighthouse.address; + value = lib.singleton "${lighthouse.routableAddress}:${toString lighthouse.routablePort}"; }) |> lib.listToAttrs; @@ -81,17 +138,13 @@ in }; }; - networking.firewall.trustedInterfaces = [ netCfg.overlay.interface ]; + networking.firewall.trustedInterfaces = [ cfg.interface ]; systemd.network.networks."40-nebula" = { - matchConfig.Name = netCfg.overlay.interface; - address = [ "${netCfg.overlay.address}/${toString netCfg.overlay.prefixLength}" ]; - dns = - self.nixosConfigurations - |> lib.attrValues - |> lib.filter (host: host.config.custom.services.dns.enable) - |> lib.map (host: host.config.custom.networking.overlay.address); - domains = [ netCfg.overlay.domain ]; + matchConfig.Name = cfg.interface; + address = [ "${cfg.address}/${toString nebulaCfg.network.prefixLength}" ]; + dns = nebulaCfg.peers |> lib.filter (node: node.dns.enable) |> lib.map (node: node.address); + domains = [ nebulaCfg.network.domain ]; }; }; } diff --git a/modules/system/services/dns.nix b/modules/system/services/nebula/dns.nix similarity index 63% rename from modules/system/services/dns.nix rename to modules/system/services/nebula/dns.nix index 13e6c8f..b2c77e6 100644 --- a/modules/system/services/dns.nix +++ b/modules/system/services/nebula/dns.nix @@ -6,13 +6,13 @@ ... }: let - cfg = config.custom.services.dns; - netCfg = config.custom.networking; + nebulaCfg = config.custom.services.nebula; + cfg = nebulaCfg.node; in { - options.custom.services.dns.enable = lib.mkEnableOption ""; + options.custom.services.nebula.node.dns.enable = lib.mkEnableOption ""; - config = lib.mkIf cfg.enable { + config = lib.mkIf (cfg.enable && cfg.dns.enable) { # meta.ports = { # tcp = [ 53 ]; # udp = [ 53 ]; @@ -24,17 +24,17 @@ in settings = { server = { - interface = [ netCfg.overlay.interface ]; + interface = [ cfg.interface ]; access-control = [ - "${netCfg.overlay.networkAddress}/${toString netCfg.overlay.prefixLength} allow" + "${nebulaCfg.network.address}/${toString nebulaCfg.network.prefixLength} allow" ]; - local-zone = "\"${netCfg.overlay.domain}.\" static"; + local-zone = "\"${nebulaCfg.network.domain}.\" static"; local-data = let nodeRecords = - netCfg.nodes - |> lib.map (node: "\"${node.hostname}.${node.overlay.domain}. A ${node.overlay.address}\""); + nebulaCfg.nodes + |> lib.map (node: "\"${node.name}.${nebulaCfg.network.domain}. A ${node.address}\""); serviceRecords = self.nixosConfigurations |> lib.attrValues @@ -42,7 +42,7 @@ in host: host.config.meta.domains.local |> lib.filter (domain: lib'.isPrivateDomain domain) - |> lib.map (domain: "\"${domain}. A ${host.config.custom.networking.overlay.address}\"") + |> lib.map (domain: "\"${domain}. A ${host.config.custom.services.nebula.node.address}\"") ); in nodeRecords ++ serviceRecords; @@ -66,8 +66,8 @@ in }; systemd.services.unbound = { - requires = [ netCfg.overlay.systemdUnit ]; - after = [ netCfg.overlay.systemdUnit ]; + requires = [ "nebula@mesh.service" ]; + after = [ "nebula@mesh.service" ]; }; }; } diff --git a/modules/system/services/sshd.nix b/modules/system/services/nebula/sshd.nix similarity index 55% rename from modules/system/services/sshd.nix rename to modules/system/services/nebula/sshd.nix index 527b944..8ce7ed0 100644 --- a/modules/system/services/sshd.nix +++ b/modules/system/services/nebula/sshd.nix @@ -5,13 +5,14 @@ ... }: let - cfg = config.custom.services.sshd; - netCfg = config.custom.networking; + cfg = config.custom.services.nebula.node; in { - options.custom.services.sshd.enable = lib.mkEnableOption ""; + options.custom.services.nebula.node.sshd.enable = lib.mkEnableOption "" // { + default = true; + }; - config = lib.mkIf cfg.enable { + config = lib.mkIf (cfg.enable && cfg.sshd.enable) { meta.ports.tcp = [ 22 ]; services = { @@ -20,7 +21,7 @@ in openFirewall = false; ports = [ ]; listenAddresses = lib.singleton { - addr = netCfg.overlay.address; + addr = cfg.address; port = 22; }; settings = { @@ -31,26 +32,26 @@ in }; nebula.networks.mesh.firewall.inbound = - netCfg.peers + config.custom.services.nebula.peers |> lib.filter (node: node.isClient) - |> lib.map (client: { + |> lib.map (nebula: { port = 22; proto = "tcp"; - host = client.hostname; + host = nebula.name; }); }; systemd.services.sshd = { - requires = [ netCfg.overlay.systemdUnit ]; - after = [ netCfg.overlay.systemdUnit ]; + requires = [ "nebula@mesh.service" ]; + after = [ "nebula@mesh.service" ]; }; users.users.seb.openssh.authorizedKeys.keyFiles = self.nixosConfigurations + |> lib.filterAttrs (name: _: name != config.networking.hostName) |> lib.attrValues - |> lib.filter (host: host.config.custom.networking.hostname != netCfg.hostname) - |> lib.filter (host: host.config |> lib.hasAttr "home-manager") - |> lib.map (host: host.config.home-manager.users.seb.custom.programs.ssh) + |> lib.filter (value: value.config |> lib.hasAttr "home-manager") + |> lib.map (value: value.config.home-manager.users.seb.custom.programs.ssh) |> lib.filter (ssh: ssh.enable) |> lib.map (ssh: ssh.publicKeyPath); }; diff --git a/modules/system/services/syncthing.nix b/modules/system/services/syncthing.nix index 819726f..abfd81b 100644 --- a/modules/system/services/syncthing.nix +++ b/modules/system/services/syncthing.nix @@ -7,7 +7,6 @@ }: let cfg = config.custom.services.syncthing; - netCfg = config.custom.networking; inherit (config.services.syncthing) dataDir; @@ -51,6 +50,10 @@ in config = lib.mkIf cfg.enable { assertions = [ + { + assertion = config.custom.services.nebula.node.enable; + message = "Syncthing requires nebula"; + } { assertion = cfg.isServer -> (cfg.gui.domain != null); message = "Running syncthing on a server requires `gui.domain` to be set"; @@ -106,7 +109,7 @@ in _: value: { id = value.config.custom.services.syncthing.deviceId; addresses = [ - "tcp://${value.config.custom.networking.overlay.address}:${toString cfg.syncPort}" + "tcp://${value.config.custom.services.nebula.node.address}:${toString cfg.syncPort}" ]; } ); @@ -119,7 +122,7 @@ in }); options = { - listenAddress = "tcp://${netCfg.overlay.address}:${toString cfg.syncPort}"; + listenAddress = "tcp://${config.custom.services.nebula.node.address}:${toString cfg.syncPort}"; globalAnnounceEnabled = false; localAnnounceEnabled = false; relaysEnabled = false; diff --git a/modules/system/web-services/alloy.nix b/modules/system/web-services/alloy.nix index 3fea35b..e0bc827 100644 --- a/modules/system/web-services/alloy.nix +++ b/modules/system/web-services/alloy.nix @@ -15,11 +15,11 @@ in }; metricsEndpoint = lib.mkOption { type = lib.types.nonEmptyStr; - default = "https://metrics.${config.custom.networking.overlay.domain}/prometheus/api/v1/write"; + default = "https://metrics.${config.custom.services.nebula.network.domain}/prometheus/api/v1/write"; }; logsEndpoint = lib.mkOption { type = lib.types.nonEmptyStr; - default = "https://logs.${config.custom.networking.overlay.domain}/insert/loki/api/v1/push"; + default = "https://logs.${config.custom.services.nebula.network.domain}/insert/loki/api/v1/push"; }; collect = { metrics = { diff --git a/modules/system/web-services/filebrowser.nix b/modules/system/web-services/filebrowser.nix index 982a83d..eabd86a 100644 --- a/modules/system/web-services/filebrowser.nix +++ b/modules/system/web-services/filebrowser.nix @@ -1,5 +1,7 @@ { config, + modulesPath, + inputs, lib, lib', ... diff --git a/modules/system/web-services/gatus.nix b/modules/system/web-services/gatus.nix index 163b882..0cda068 100644 --- a/modules/system/web-services/gatus.nix +++ b/modules/system/web-services/gatus.nix @@ -113,7 +113,7 @@ in connectivity.checker.target = "1.1.1.1:53"; # Cloudflare DNS alerting.ntfy = { topic = "uptime"; - url = "https://alerts.${config.custom.networking.overlay.domain}"; + url = "https://alerts.${config.custom.services.nebula.network.domain}"; click = "https://${cfg.domain}"; default-alert = { enable = true; diff --git a/modules/system/web-services/grafana.nix b/modules/system/web-services/grafana.nix index a0c64b7..155674c 100644 --- a/modules/system/web-services/grafana.nix +++ b/modules/system/web-services/grafana.nix @@ -23,21 +23,21 @@ in enable = lib.mkEnableOption ""; url = lib.mkOption { type = lib.types.nonEmptyStr; - default = "https://metrics.${config.custom.networking.overlay.domain}"; + default = "https://metrics.${config.custom.services.nebula.network.domain}"; }; }; victoriametrics = { enable = lib.mkEnableOption ""; url = lib.mkOption { type = lib.types.nonEmptyStr; - default = "https://metrics.${config.custom.networking.overlay.domain}"; + default = "https://metrics.${config.custom.services.nebula.network.domain}"; }; }; victorialogs = { enable = lib.mkEnableOption ""; url = lib.mkOption { type = lib.types.nonEmptyStr; - default = "https://logs.${config.custom.networking.overlay.domain}"; + default = "https://logs.${config.custom.services.nebula.network.domain}"; }; }; };