{ config, lib, pkgs, ... }: let # Import nodes nodes = import ./../../nodes.nix; myPeer = nodes."${config.hostName}"; myId = myPeer.id; myZone = myPeer.zone; # And mappings mapping = import ./../../mapping.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; # Filter itself out of the peer list peerConfigs = lib.filterAttrs (_peerName: peerConfig: (peerConfig.zone != myZone) || (peerConfig.id != myId)) nodes; 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" ] ++ 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; interfaces = { "mesh" = { ips = [ "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 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.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"; 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} ''; 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 = interfaces; # 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"; }; }; }