diff --git a/nodes.nix b/nodes.nix index 3004549..7148b31 100644 --- a/nodes.nix +++ b/nodes.nix @@ -308,7 +308,7 @@ bastion-ren-lasuite-federez = { zone = 2; - id = 14; + id = 1; system = "x86_64-linux"; ver = "25.05"; modules = [ @@ -331,7 +331,7 @@ db-ren-lasuite-federez = { zone = 2; - id = 15; + id = 2; system = "x86_64-linux"; ver = "25.05"; modules = [ @@ -354,7 +354,7 @@ dns-ren-lasuite-federez = { zone = 2; - id = 16; + id = 3; system = "x86_64-linux"; ver = "25.05"; modules = [ @@ -377,7 +377,7 @@ docs-ren-lasuite-federez = { zone = 2; - id = 17; + id = 4; system = "x86_64-linux"; ver = "25.05"; modules = [ @@ -400,7 +400,7 @@ meet-ren-lasuite-federez = { zone = 2; - id = 18; + id = 5; system = "x86_64-linux"; ver = "25.05"; modules = [ @@ -423,7 +423,7 @@ gris-ren-lasuite-federez = { zone = 2; - id = 19; + id = 6; system = "x86_64-linux"; ver = "25.05"; modules = [ @@ -446,7 +446,7 @@ mail-ren-lasuite-federez = { zone = 2; - id = 20; + id = 7; system = "x86_64-linux"; ver = "25.05"; modules = [ @@ -469,7 +469,7 @@ garage-ren-lasuite-federez = { zone = 2; - id = 21; + id = 8; system = "x86_64-linux"; ver = "25.05"; modules = [ @@ -492,7 +492,7 @@ livekit-ren-lasuite-federez = { zone = 2; - id = 22; + id = 9; system = "x86_64-linux"; ver = "25.05"; modules = [ @@ -515,7 +515,7 @@ backup-ren-lasuite-federez = { zone = 2; - id = 23; + id = 10; system = "x86_64-linux"; ver = "25.05"; modules = [ @@ -538,7 +538,7 @@ prom-ren-lasuite-federez = { zone = 2; - id = 24; + id = 11; system = "x86_64-linux"; ver = "25.05"; modules = [ @@ -561,7 +561,7 @@ auth-ren-lasuite-federez = { zone = 2; - id = 25; + id = 12; system = "x86_64-linux"; ver = "25.05"; modules = [ diff --git a/secrets/secrets.nix b/secrets/secrets.nix index a4fc9dc..de9f8d6 100644 --- a/secrets/secrets.nix +++ b/secrets/secrets.nix @@ -57,18 +57,18 @@ in "wireguard/wg-private-zone-1-id-13.age".publicKeys = system-wg ++ users; # Zone 2 (Rennes) - "wireguard/wg-private-zone-2-id-14.age".publicKeys = system-wg ++ users; - "wireguard/wg-private-zone-2-id-15.age".publicKeys = system-wg ++ users; - "wireguard/wg-private-zone-2-id-16.age".publicKeys = system-wg ++ users; - "wireguard/wg-private-zone-2-id-17.age".publicKeys = system-wg ++ users; - "wireguard/wg-private-zone-2-id-18.age".publicKeys = system-wg ++ users; - "wireguard/wg-private-zone-2-id-19.age".publicKeys = system-wg ++ users; - "wireguard/wg-private-zone-2-id-20.age".publicKeys = system-wg ++ users; - "wireguard/wg-private-zone-2-id-21.age".publicKeys = system-wg ++ users; - "wireguard/wg-private-zone-2-id-22.age".publicKeys = system-wg ++ users; - "wireguard/wg-private-zone-2-id-23.age".publicKeys = system-wg ++ users; - "wireguard/wg-private-zone-2-id-24.age".publicKeys = system-wg ++ users; - "wireguard/wg-private-zone-2-id-25.age".publicKeys = system-wg ++ users; + "wireguard/wg-private-zone-2-id-1.age".publicKeys = system-wg ++ users; + "wireguard/wg-private-zone-2-id-2.age".publicKeys = system-wg ++ users; + "wireguard/wg-private-zone-2-id-3.age".publicKeys = system-wg ++ users; + "wireguard/wg-private-zone-2-id-4.age".publicKeys = system-wg ++ users; + "wireguard/wg-private-zone-2-id-5.age".publicKeys = system-wg ++ users; + "wireguard/wg-private-zone-2-id-6.age".publicKeys = system-wg ++ users; + "wireguard/wg-private-zone-2-id-7.age".publicKeys = system-wg ++ users; + "wireguard/wg-private-zone-2-id-8.age".publicKeys = system-wg ++ users; + "wireguard/wg-private-zone-2-id-9.age".publicKeys = system-wg ++ users; + "wireguard/wg-private-zone-2-id-10.age".publicKeys = system-wg ++ users; + "wireguard/wg-private-zone-2-id-11.age".publicKeys = system-wg ++ users; + "wireguard/wg-private-zone-2-id-12.age".publicKeys = system-wg ++ users; # Bastion secrets diff --git a/secrets/wireguard/wg-private-zone-2-id-14.age b/secrets/wireguard/wg-private-zone-2-id-1.age similarity index 100% rename from secrets/wireguard/wg-private-zone-2-id-14.age rename to secrets/wireguard/wg-private-zone-2-id-1.age diff --git a/secrets/wireguard/wg-private-zone-2-id-23.age b/secrets/wireguard/wg-private-zone-2-id-10.age similarity index 100% rename from secrets/wireguard/wg-private-zone-2-id-23.age rename to secrets/wireguard/wg-private-zone-2-id-10.age diff --git a/secrets/wireguard/wg-private-zone-2-id-24.age b/secrets/wireguard/wg-private-zone-2-id-11.age similarity index 100% rename from secrets/wireguard/wg-private-zone-2-id-24.age rename to secrets/wireguard/wg-private-zone-2-id-11.age diff --git a/secrets/wireguard/wg-private-zone-2-id-25.age b/secrets/wireguard/wg-private-zone-2-id-12.age similarity index 100% rename from secrets/wireguard/wg-private-zone-2-id-25.age rename to secrets/wireguard/wg-private-zone-2-id-12.age diff --git a/secrets/wireguard/wg-private-zone-2-id-15.age b/secrets/wireguard/wg-private-zone-2-id-2.age similarity index 100% rename from secrets/wireguard/wg-private-zone-2-id-15.age rename to secrets/wireguard/wg-private-zone-2-id-2.age diff --git a/secrets/wireguard/wg-private-zone-2-id-16.age b/secrets/wireguard/wg-private-zone-2-id-3.age similarity index 100% rename from secrets/wireguard/wg-private-zone-2-id-16.age rename to secrets/wireguard/wg-private-zone-2-id-3.age diff --git a/secrets/wireguard/wg-private-zone-2-id-17.age b/secrets/wireguard/wg-private-zone-2-id-4.age similarity index 100% rename from secrets/wireguard/wg-private-zone-2-id-17.age rename to secrets/wireguard/wg-private-zone-2-id-4.age diff --git a/secrets/wireguard/wg-private-zone-2-id-18.age b/secrets/wireguard/wg-private-zone-2-id-5.age similarity index 100% rename from secrets/wireguard/wg-private-zone-2-id-18.age rename to secrets/wireguard/wg-private-zone-2-id-5.age diff --git a/secrets/wireguard/wg-private-zone-2-id-19.age b/secrets/wireguard/wg-private-zone-2-id-6.age similarity index 100% rename from secrets/wireguard/wg-private-zone-2-id-19.age rename to secrets/wireguard/wg-private-zone-2-id-6.age diff --git a/secrets/wireguard/wg-private-zone-2-id-20.age b/secrets/wireguard/wg-private-zone-2-id-7.age similarity index 100% rename from secrets/wireguard/wg-private-zone-2-id-20.age rename to secrets/wireguard/wg-private-zone-2-id-7.age diff --git a/secrets/wireguard/wg-private-zone-2-id-21.age b/secrets/wireguard/wg-private-zone-2-id-8.age similarity index 100% rename from secrets/wireguard/wg-private-zone-2-id-21.age rename to secrets/wireguard/wg-private-zone-2-id-8.age diff --git a/secrets/wireguard/wg-private-zone-2-id-22.age b/secrets/wireguard/wg-private-zone-2-id-9.age similarity index 100% rename from secrets/wireguard/wg-private-zone-2-id-22.age rename to secrets/wireguard/wg-private-zone-2-id-9.age diff --git a/shared/bastion/wireguard.nix b/shared/bastion/wireguard.nix index c839fc4..184b2aa 100644 --- a/shared/bastion/wireguard.nix +++ b/shared/bastion/wireguard.nix @@ -12,36 +12,44 @@ let buildSecret = zone: { "wg-private-zone-${toString zone}" = { file = ./../../secrets/bastion + ( "/wg-private-zone-" + toString zone + ".age" ); - owner = "root"; - group = "root"; + owner = "systemd-network"; + group = "systemd-network"; }; }; - peers = map (peerConfig: { - name = "${peerConfig.name}"; - publicKey = peerConfig.publicKey; - allowedIPs = [ + interfacePeers = map (peerConfig: { + PublicKey = peerConfig.publicKey; + AllowedIPs = [ "172.19.${toString (myZone + 127)}.${toString peerConfig.id}/32" "fc00:f::${toString (myZone + 127)}:${toString peerConfig.id}/128" ]; - persistentKeepalive = 25; + PersistentKeepalive = 25; }) users-wg; - interface = { - "mgmt" = { - ips = [ - "172.19.${toString (myZone + 127)}.254/24" - "fc00:f::${toString (myZone + 127)}:254/96" - ]; - privateKeyFile = config.age.secrets."wg-private-zone-${toString myZone}".path; - listenPort = 51920; - peers = peers; - }; + interfaceConfig = { + PrivateKeyFile = config.age.secrets."wg-private-zone-${toString myZone}".path; + ListenPort = 51920; }; in { age.secrets = buildSecret myZone; - # Return all WireGuard interfaces for each node - networking.wireguard.interfaces = interface; + # Build Management interface + systemd.network = { + netdevs."mgmt" = { + netdevConfig = { + Name = "mgmt"; + Kind = "wireguard"; + }; + wireguardConfig = interfaceConfig; + wireguardPeers = interfacePeers; + }; + networks."mgmt" = { + matchConfig.Name = "mgmt"; + address = [ + "172.19.${toString (myZone + 127)}.254/24" + "fc00:f::${toString (myZone + 127)}:254/96" + ]; + }; + }; } \ No newline at end of file diff --git a/shared/commons/mesh.nix b/shared/commons/mesh.nix index 60e17f8..1438044 100644 --- a/shared/commons/mesh.nix +++ b/shared/commons/mesh.nix @@ -3,7 +3,8 @@ let # Import nodes nodes = import ./../../nodes.nix; - myPeer = nodes."${config.hostName}"; + myName = config.hostName; + myPeer = nodes."${myName}"; myId = myPeer.id; myZone = myPeer.zone; @@ -13,107 +14,66 @@ let buildSecret = zone: id: { "wg-private-zone-${toString zone}-id-${toString id}" = { file = ./../../secrets/wireguard + ( "/wg-private-zone-" + toString zone + "-id-" + toString id + ".age" ); - owner = "root"; - group = "root"; + owner = "systemd-network"; + group = "systemd-network"; }; }; generatedSecrets = lib.mapAttrsToList (name: node: buildSecret node.zone node.id) nodes; - shorten = peerName: let - parts = lib.splitString "-" peerName; - shortened = lib.concatStrings (map (part: lib.substring 0 1 part) parts); - in shortened; - # Filter itself out of the peer list - peerConfigs = lib.filterAttrs (_peerName: peerConfig: peerConfig.id != myId) nodes; + peerConfigs = lib.filterAttrs (peerName: _peerConfig: peerName != myName) nodes; + + interfacePeers = lib.mapAttrsToList (peerName: peerConfig: { + PublicKey = peerConfig.wg-pub; + AllowedIPs = [ + "172.19.${toString peerConfig.zone}.${toString peerConfig.id}/32" + "fc00::${toString peerConfig.zone}:${toString peerConfig.id}/128" + ] ++ lib.optionals (lib.elem peerName mapping.bastion) [ + "172.19.${toString (peerConfig.zone + 127)}.0/24" + "fc00:f::${toString (peerConfig.zone + 127)}:0/112" + ]; + Endpoint = "${builtins.head (builtins.split "/" peerConfig.ip4)}:51820"; + PersistentKeepalive = 25; + }) peerConfigs; + + interfaceConfig = { + PrivateKeyFile = config.age.secrets."wg-private-zone-${toString myZone}-id-${toString myId}".path; + ListenPort = 51820; + }; - # We'll make one if per peer, this is more flexible - interfacePeers = lib.flatten (lib.mapAttrsToList (peerName: peerConfig: let - remoteId = peerConfig.id; - remoteZone = peerConfig.zone; + # Return route for mgmt traffic + bastionConfigs = lib.filterAttrs (peerName: _peerConfig: lib.elem peerName mapping.bastion) peerConfigs; - # The mesh is for now only IPv4 based - if4 = { - "mesh-${shorten peerName}-${toString remoteZone}-${toString remoteId}" = { - ips = [ - "172.19.0.${toString myId}/32" - "172.19.${toString myId}.${toString remoteId}/32" - "fc00::${toString myId}/128" - "fc00::${toString myId}:${toString remoteId}/128" - ]; - privateKeyFile = config.age.secrets."wg-private-zone-${toString myZone}-id-${toString myId}".path; - listenPort = 51000 + remoteId; - peers = [{ - name = "${peerName}-ip4"; - publicKey = peerConfig.wg-pub; - allowedIPs = [ - # Allow mesh trafic - "172.19.0.${toString peerConfig.id}/32" - "172.19.${toString peerConfig.id}.0/24" - "fc00::${toString peerConfig.id}:0/96" - # Allow mgmt transport - "172.19.128.0/17" - "fc00:f::/96" - ]; - endpoint = "${builtins.head (builtins.split "/" peerConfig.ip4)}:${toString (51000 + myId)}"; - persistentKeepalive = 25; - }]; - # Throw away route created by wireguard - table = "off"; - }; - }; - - in if4) peerConfigs); - - wireguardInterfaces = builtins.foldl' (acc: set: acc // set) {} interfacePeers; - - generateRoute = peerName: peerConfig: '' - # Static route to declare static wireguard peer inner tunnel ip (that has been thrown away to the "off" table) - ${pkgs.iproute2}/bin/ip route replace 172.19.${toString peerConfig.id}.0/24 dev mesh-${shorten peerName}-${toString peerConfig.zone}-${toString peerConfig.id} scope link - ${pkgs.iproute2}/bin/ip -6 route replace fc00::${toString peerConfig.id}:0/112 dev mesh-${shorten peerName}-${toString peerConfig.zone}-${toString peerConfig.id} scope link - - # Nodes self ip - ${pkgs.iproute2}/bin/ip route replace 172.19.0.${toString peerConfig.id}/32 dev mesh-${shorten peerName}-${toString peerConfig.zone}-${toString peerConfig.id} scope link - ${pkgs.iproute2}/bin/ip -6 route replace fc00::${toString peerConfig.id}/128 dev mesh-${shorten peerName}-${toString peerConfig.zone}-${toString peerConfig.id} scope link - - # Return path for mgmt trafic - ${if lib.elem peerName mapping.bastion then '' - ${pkgs.iproute2}/bin/ip route replace 172.19.${toString (peerConfig.zone + 127)}.0/24 via 172.19.${toString peerConfig.id}.${toString myId} dev mesh-${shorten peerName}-${toString peerConfig.zone}-${toString peerConfig.id} - ${pkgs.iproute2}/bin/ip -6 route replace fc00:f::${toString (peerConfig.zone + 127)}:0/112 via fc00::${toString peerConfig.id}:${toString myId} dev mesh-${shorten peerName}-${toString peerConfig.zone}-${toString peerConfig.id} - '' else ""} - ''; - - generateAfter = peerName: peerConfig: "wireguard-mesh-${shorten peerName}-${toString peerConfig.zone}-${toString peerConfig.id}.target"; - - routes = lib.mapAttrsToList (name: peer: generateRoute name peer) peerConfigs; - afters = lib.mapAttrsToList (name: peer: generateAfter name peer) peerConfigs; - - wireguardStaticRoute = pkgs.writeShellScriptBin "wireguardStaticRoute" '' - ${lib.concatStrings routes} - ''; + rtwg4 = map (node: { + Gateway = "172.19.${toString node.zone}.${toString node.id}"; + Destination = "172.19.${toString (node.zone + 127)}.0/24"; + }) (lib.attrValues bastionConfigs); + + rtwg6 = map (node: { + Gateway = "fc00::${toString node.zone}:${toString node.id}"; + Destination = "fc00:f::${toString (node.zone + 127)}:0/112"; + }) (lib.attrValues bastionConfigs); in { age.secrets = lib.lists.foldl' (acc: set: lib.attrsets.recursiveUpdate acc set) {} generatedSecrets; - # Networkd backend introduce in 25.05 - # No independant target are generated - # when using networkd as a backend - # We need them, see below - networking.wireguard.useNetworkd = false; - - # Return all WireGuard interfaces for each node - networking.wireguard.interfaces = wireguardInterfaces; - - # Execute custom routing for wireguard - systemd.services.wireguardStaticRouting = { - wantedBy = [ "multi-user.target" ]; - # Thus we need specific target to be reached to run it - after = afters; - description = "Add custom ip route for wireguard."; - serviceConfig = { - Type = "oneshot"; - User = "root"; - ExecStart = "${wireguardStaticRoute}/bin/wireguardStaticRoute"; + # Build Mesh interface + systemd.network = { + netdevs."mesh" = { + netdevConfig = { + Name = "mesh"; + Kind = "wireguard"; + }; + wireguardConfig = interfaceConfig; + wireguardPeers = interfacePeers; + }; + networks."mesh" = { + matchConfig.Name = "mesh"; + address = [ + "172.19.${toString myZone}.${toString myId}/17" + "fc00::${toString myZone}:${toString myId}/112" + ]; + routes = rtwg4 ++ rtwg6; }; }; } \ No newline at end of file diff --git a/shared/commons/networking.nix b/shared/commons/networking.nix index 1f3101e..a604e50 100644 --- a/shared/commons/networking.nix +++ b/shared/commons/networking.nix @@ -35,11 +35,5 @@ in linkConfig.RequiredForOnline = "routable"; }; }; - - config.addRouteTablesToIPRoute2 = true; - config.routeTables = { - # Act as a route bin - off = 999; - }; }; } \ No newline at end of file diff --git a/shared/commons/nftables.nix b/shared/commons/nftables.nix index 26f0491..120ee2b 100644 --- a/shared/commons/nftables.nix +++ b/shared/commons/nftables.nix @@ -7,10 +7,6 @@ let # Import mapping mapping = import ./../../mapping.nix; - - meshUdpRange = "51000-${toString (51000 + builtins.head ( - builtins.sort (a: b: a > b) ( - lib.mapAttrsToList (name: node: node.id) nodes)))}"; in { networking = { @@ -50,7 +46,7 @@ in tcp dport 22 accept # Mesh - udp dport ${meshUdpRange} accept + udp dport 51820 accept ${if lib.elem myName mapping.bastion then '' # Mgmt