114 lines
No EOL
5 KiB
Nix
114 lines
No EOL
5 KiB
Nix
{ 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;
|
|
|
|
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;
|
|
|
|
# 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;
|
|
|
|
# The mesh is for now only IPv4 based
|
|
if4 = {
|
|
"mesh-${shorten peerName}-${toString remoteZone}-${toString remoteId}" = {
|
|
ips = [
|
|
"172.19.${toString myId}.${toString myId}/32"
|
|
"172.19.${toString myId}.${toString remoteId}/32"
|
|
"fc00::${toString myId}:${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.${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
|
|
|
|
# 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}
|
|
'';
|
|
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";
|
|
};
|
|
};
|
|
} |