{ config, lib, ... }: let # Import nodes nodes = import ./../../nodes.nix; 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"; }; }; generatedSecrets = lib.mapAttrsToList (name: node: buildSecret node.zone node.id) nodes; generateWireGuardInterface = nodesConfig: let myPeer = nodesConfig."${config.hostName}"; myZone = myPeer.zone; myId = myPeer.id; # Filter itself out of the peer list peerConfigs = lib.filterAttrs (_peerName: peerConfig: (peerConfig.zone != myZone) || (peerConfig.id != myId)) nodesConfig; peers = lib.mapAttrsToList (peerName: peerConfig: { name = "${peerName}"; publicKey = peerConfig.wg-pub; allowedIPs = [ "172.19.${toString peerConfig.zone}.${toString peerConfig.id}/32" "fc00::${toString peerConfig.zone}:${toString peerConfig.id}/128" ]; endpoint = "${builtins.head (builtins.split "/" peerConfig.ip4)}:51820"; persistentKeepalive = 25; }) peerConfigs; interface = { "mesh" = { ips = [ "172.19.${toString myZone}.${toString myId}/17" "fc00::${toString myZone}:${toString myId}/96" ]; privateKeyFile = config.age.secrets."wg-private-zone-${toString myZone}-id-${toString myId}".path; listenPort = 51820; peers = peers; }; }; in interface; wireguardInterfaces = generateWireGuardInterface nodes; 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 # If custom systemd ordering is needed # between wg interface and the rest of # networking: switch to false here networking.wireguard.useNetworkd = true; # Return all WireGuard interfaces for each node networking.wireguard.interfaces = wireguardInterfaces; # Open UDP port for wireguard traffic networking.firewall.allowedUDPPorts = [ 51820 ]; }