switch to a full networkd setup

This commit is contained in:
asyncnomi 2025-07-22 23:07:45 +02:00
parent 09c91ccf84
commit 1d704ccbc8
3 changed files with 65 additions and 77 deletions

View file

@ -12,36 +12,44 @@ let
buildSecret = zone: { buildSecret = zone: {
"wg-private-zone-${toString zone}" = { "wg-private-zone-${toString zone}" = {
file = ./../../secrets/bastion + ( "/wg-private-zone-" + toString zone + ".age" ); file = ./../../secrets/bastion + ( "/wg-private-zone-" + toString zone + ".age" );
owner = "root"; owner = "systemd-network";
group = "root"; group = "systemd-network";
}; };
}; };
peers = map (peerConfig: { interfacePeers = map (peerConfig: {
name = "${peerConfig.name}"; PublicKey = peerConfig.publicKey;
publicKey = peerConfig.publicKey; AllowedIPs = [
allowedIPs = [
"172.19.${toString (myZone + 127)}.${toString peerConfig.id}/32" "172.19.${toString (myZone + 127)}.${toString peerConfig.id}/32"
"fc00:f::${toString (myZone + 127)}:${toString peerConfig.id}/128" "fc00:f::${toString (myZone + 127)}:${toString peerConfig.id}/128"
]; ];
persistentKeepalive = 25; PersistentKeepalive = 25;
}) users-wg; }) users-wg;
interface = { interfaceConfig = {
"mgmt" = { PrivateKeyFile = config.age.secrets."wg-private-zone-${toString myZone}".path;
ips = [ ListenPort = 51920;
"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;
};
}; };
in in
{ {
age.secrets = buildSecret myZone; age.secrets = buildSecret myZone;
# Return all WireGuard interfaces for each node # Build Management interface
networking.wireguard.interfaces = 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"
];
};
};
} }

View file

@ -13,8 +13,8 @@ let
buildSecret = zone: id: { buildSecret = zone: id: {
"wg-private-zone-${toString zone}-id-${toString id}" = { "wg-private-zone-${toString zone}-id-${toString id}" = {
file = ./../../secrets/wireguard + ( "/wg-private-zone-" + toString zone + "-id-" + toString id + ".age" ); file = ./../../secrets/wireguard + ( "/wg-private-zone-" + toString zone + "-id-" + toString id + ".age" );
owner = "root"; owner = "systemd-network";
group = "root"; group = "systemd-network";
}; };
}; };
generatedSecrets = lib.mapAttrsToList (name: node: buildSecret node.zone node.id) nodes; generatedSecrets = lib.mapAttrsToList (name: node: buildSecret node.zone node.id) nodes;
@ -22,71 +22,57 @@ let
# Filter itself out of the peer list # Filter itself out of the peer list
peerConfigs = lib.filterAttrs (_peerName: peerConfig: (peerConfig.zone != myZone) || (peerConfig.id != myId)) nodes; peerConfigs = lib.filterAttrs (_peerName: peerConfig: (peerConfig.zone != myZone) || (peerConfig.id != myId)) nodes;
peers = lib.mapAttrsToList (peerName: peerConfig: { interfacePeers = lib.mapAttrsToList (peerName: peerConfig: {
name = "${peerName}"; PublicKey = peerConfig.wg-pub;
publicKey = peerConfig.wg-pub; AllowedIPs = [
allowedIPs = [
"172.19.${toString peerConfig.zone}.${toString peerConfig.id}/32" "172.19.${toString peerConfig.zone}.${toString peerConfig.id}/32"
"fc00::${toString peerConfig.zone}:${toString peerConfig.id}/128" "fc00::${toString peerConfig.zone}:${toString peerConfig.id}/128"
] ++ lib.optionals (lib.elem peerName mapping.bastion) [ ] ++ lib.optionals (lib.elem peerName mapping.bastion) [
"172.19.${toString (peerConfig.zone + 127)}.0/24" "172.19.${toString (peerConfig.zone + 127)}.0/24"
"fc00:f::${toString (peerConfig.zone + 127)}:0/112" "fc00:f::${toString (peerConfig.zone + 127)}:0/112"
]; ];
endpoint = "${builtins.head (builtins.split "/" peerConfig.ip4)}:51820"; Endpoint = "${builtins.head (builtins.split "/" peerConfig.ip4)}:51820";
persistentKeepalive = 25; PersistentKeepalive = 25;
}) peerConfigs; }) peerConfigs;
interfaces = { interfaceConfig = {
"mesh" = { PrivateKeyFile = config.age.secrets."wg-private-zone-${toString myZone}-id-${toString myId}".path;
ips = [ ListenPort = 51820;
"172.19.${toString myZone}.${toString myId}/17"
"fc00::${toString myZone}:${toString myId}/112"
];
privateKeyFile = config.age.secrets."wg-private-zone-${toString myZone}-id-${toString myId}".path;
listenPort = 51820;
peers = peers;
};
}; };
generateRoute = peerName: peerConfig: '' # Return route for mgmt traffic
# Return path for mgmt trafic bastionConfigs = lib.filterAttrs (peerName: _peerConfig: lib.elem peerName mapping.bastion) peerConfigs;
${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.zone}.${toString peerConfig.id} dev mesh
${pkgs.iproute2}/bin/ip -6 route replace fc00:f::${toString (peerConfig.zone + 127)}:0/112 via fc00::${toString peerConfig.zone}:${toString peerConfig.id} dev mesh
'' else ""}
'';
generateAfter = peerName: peerConfig: "wireguard-mesh.target"; rtwg4 = map (node: {
Gateway = "172.19.${toString node.zone}.${toString node.id}";
routes = lib.mapAttrsToList (name: peer: generateRoute name peer) peerConfigs; Destination = "172.19.${toString (node.zone + 127)}.0/24";
afters = lib.mapAttrsToList (name: peer: generateAfter name peer) peerConfigs; }) (lib.attrValues bastionConfigs);
wireguardStaticRoute = pkgs.writeShellScriptBin "wireguardStaticRoute" '' rtwg6 = map (node: {
${lib.concatStrings routes} Gateway = "fc00::${toString node.zone}:${toString node.id}";
''; Destination = "fc00:f::${toString (node.zone + 127)}:0/112";
}) (lib.attrValues bastionConfigs);
in in
{ {
age.secrets = lib.lists.foldl' (acc: set: lib.attrsets.recursiveUpdate acc set) {} generatedSecrets; age.secrets = lib.lists.foldl' (acc: set: lib.attrsets.recursiveUpdate acc set) {} generatedSecrets;
# Networkd backend introduce in 25.05 # Build Mesh interface
# No independant target are generated systemd.network = {
# when using networkd as a backend netdevs."mesh" = {
# We need them, see below netdevConfig = {
networking.wireguard.useNetworkd = false; Name = "mesh";
Kind = "wireguard";
# Return all WireGuard interfaces for each node };
networking.wireguard.interfaces = interfaces; wireguardConfig = interfaceConfig;
wireguardPeers = interfacePeers;
# Execute custom routing for wireguard };
systemd.services.wireguardStaticRouting = { networks."mesh" = {
wantedBy = [ "multi-user.target" ]; matchConfig.Name = "mesh";
# Thus we need specific target to be reached to run it address = [
after = afters; "172.19.${toString myZone}.${toString myId}/17"
description = "Add custom ip route for wireguard."; "fc00::${toString myZone}:${toString myId}/112"
serviceConfig = { ];
Type = "oneshot"; routes = rtwg4 ++ rtwg6;
User = "root";
ExecStart = "${wireguardStaticRoute}/bin/wireguardStaticRoute";
}; };
}; };
} }

View file

@ -35,11 +35,5 @@ in
linkConfig.RequiredForOnline = "routable"; linkConfig.RequiredForOnline = "routable";
}; };
}; };
config.addRouteTablesToIPRoute2 = true;
config.routeTables = {
# Act as a route bin
off = 999;
};
}; };
} }