simplified-mesh #1
18 changed files with 103 additions and 145 deletions
24
nodes.nix
24
nodes.nix
|
@ -308,7 +308,7 @@
|
||||||
|
|
||||||
bastion-ren-lasuite-federez = {
|
bastion-ren-lasuite-federez = {
|
||||||
zone = 2;
|
zone = 2;
|
||||||
id = 14;
|
id = 1;
|
||||||
system = "x86_64-linux";
|
system = "x86_64-linux";
|
||||||
ver = "25.05";
|
ver = "25.05";
|
||||||
modules = [
|
modules = [
|
||||||
|
@ -331,7 +331,7 @@
|
||||||
|
|
||||||
db-ren-lasuite-federez = {
|
db-ren-lasuite-federez = {
|
||||||
zone = 2;
|
zone = 2;
|
||||||
id = 15;
|
id = 2;
|
||||||
system = "x86_64-linux";
|
system = "x86_64-linux";
|
||||||
ver = "25.05";
|
ver = "25.05";
|
||||||
modules = [
|
modules = [
|
||||||
|
@ -354,7 +354,7 @@
|
||||||
|
|
||||||
dns-ren-lasuite-federez = {
|
dns-ren-lasuite-federez = {
|
||||||
zone = 2;
|
zone = 2;
|
||||||
id = 16;
|
id = 3;
|
||||||
system = "x86_64-linux";
|
system = "x86_64-linux";
|
||||||
ver = "25.05";
|
ver = "25.05";
|
||||||
modules = [
|
modules = [
|
||||||
|
@ -377,7 +377,7 @@
|
||||||
|
|
||||||
docs-ren-lasuite-federez = {
|
docs-ren-lasuite-federez = {
|
||||||
zone = 2;
|
zone = 2;
|
||||||
id = 17;
|
id = 4;
|
||||||
system = "x86_64-linux";
|
system = "x86_64-linux";
|
||||||
ver = "25.05";
|
ver = "25.05";
|
||||||
modules = [
|
modules = [
|
||||||
|
@ -400,7 +400,7 @@
|
||||||
|
|
||||||
meet-ren-lasuite-federez = {
|
meet-ren-lasuite-federez = {
|
||||||
zone = 2;
|
zone = 2;
|
||||||
id = 18;
|
id = 5;
|
||||||
system = "x86_64-linux";
|
system = "x86_64-linux";
|
||||||
ver = "25.05";
|
ver = "25.05";
|
||||||
modules = [
|
modules = [
|
||||||
|
@ -423,7 +423,7 @@
|
||||||
|
|
||||||
gris-ren-lasuite-federez = {
|
gris-ren-lasuite-federez = {
|
||||||
zone = 2;
|
zone = 2;
|
||||||
id = 19;
|
id = 6;
|
||||||
system = "x86_64-linux";
|
system = "x86_64-linux";
|
||||||
ver = "25.05";
|
ver = "25.05";
|
||||||
modules = [
|
modules = [
|
||||||
|
@ -446,7 +446,7 @@
|
||||||
|
|
||||||
mail-ren-lasuite-federez = {
|
mail-ren-lasuite-federez = {
|
||||||
zone = 2;
|
zone = 2;
|
||||||
id = 20;
|
id = 7;
|
||||||
system = "x86_64-linux";
|
system = "x86_64-linux";
|
||||||
ver = "25.05";
|
ver = "25.05";
|
||||||
modules = [
|
modules = [
|
||||||
|
@ -469,7 +469,7 @@
|
||||||
|
|
||||||
garage-ren-lasuite-federez = {
|
garage-ren-lasuite-federez = {
|
||||||
zone = 2;
|
zone = 2;
|
||||||
id = 21;
|
id = 8;
|
||||||
system = "x86_64-linux";
|
system = "x86_64-linux";
|
||||||
ver = "25.05";
|
ver = "25.05";
|
||||||
modules = [
|
modules = [
|
||||||
|
@ -492,7 +492,7 @@
|
||||||
|
|
||||||
livekit-ren-lasuite-federez = {
|
livekit-ren-lasuite-federez = {
|
||||||
zone = 2;
|
zone = 2;
|
||||||
id = 22;
|
id = 9;
|
||||||
system = "x86_64-linux";
|
system = "x86_64-linux";
|
||||||
ver = "25.05";
|
ver = "25.05";
|
||||||
modules = [
|
modules = [
|
||||||
|
@ -515,7 +515,7 @@
|
||||||
|
|
||||||
backup-ren-lasuite-federez = {
|
backup-ren-lasuite-federez = {
|
||||||
zone = 2;
|
zone = 2;
|
||||||
id = 23;
|
id = 10;
|
||||||
system = "x86_64-linux";
|
system = "x86_64-linux";
|
||||||
ver = "25.05";
|
ver = "25.05";
|
||||||
modules = [
|
modules = [
|
||||||
|
@ -538,7 +538,7 @@
|
||||||
|
|
||||||
prom-ren-lasuite-federez = {
|
prom-ren-lasuite-federez = {
|
||||||
zone = 2;
|
zone = 2;
|
||||||
id = 24;
|
id = 11;
|
||||||
system = "x86_64-linux";
|
system = "x86_64-linux";
|
||||||
ver = "25.05";
|
ver = "25.05";
|
||||||
modules = [
|
modules = [
|
||||||
|
@ -561,7 +561,7 @@
|
||||||
|
|
||||||
auth-ren-lasuite-federez = {
|
auth-ren-lasuite-federez = {
|
||||||
zone = 2;
|
zone = 2;
|
||||||
id = 25;
|
id = 12;
|
||||||
system = "x86_64-linux";
|
system = "x86_64-linux";
|
||||||
ver = "25.05";
|
ver = "25.05";
|
||||||
modules = [
|
modules = [
|
||||||
|
|
|
@ -57,18 +57,18 @@ in
|
||||||
"wireguard/wg-private-zone-1-id-13.age".publicKeys = system-wg ++ users;
|
"wireguard/wg-private-zone-1-id-13.age".publicKeys = system-wg ++ users;
|
||||||
|
|
||||||
# Zone 2 (Rennes)
|
# Zone 2 (Rennes)
|
||||||
"wireguard/wg-private-zone-2-id-14.age".publicKeys = system-wg ++ users;
|
"wireguard/wg-private-zone-2-id-1.age".publicKeys = system-wg ++ users;
|
||||||
"wireguard/wg-private-zone-2-id-15.age".publicKeys = system-wg ++ users;
|
"wireguard/wg-private-zone-2-id-2.age".publicKeys = system-wg ++ users;
|
||||||
"wireguard/wg-private-zone-2-id-16.age".publicKeys = system-wg ++ users;
|
"wireguard/wg-private-zone-2-id-3.age".publicKeys = system-wg ++ users;
|
||||||
"wireguard/wg-private-zone-2-id-17.age".publicKeys = system-wg ++ users;
|
"wireguard/wg-private-zone-2-id-4.age".publicKeys = system-wg ++ users;
|
||||||
"wireguard/wg-private-zone-2-id-18.age".publicKeys = system-wg ++ users;
|
"wireguard/wg-private-zone-2-id-5.age".publicKeys = system-wg ++ users;
|
||||||
"wireguard/wg-private-zone-2-id-19.age".publicKeys = system-wg ++ users;
|
"wireguard/wg-private-zone-2-id-6.age".publicKeys = system-wg ++ users;
|
||||||
"wireguard/wg-private-zone-2-id-20.age".publicKeys = system-wg ++ users;
|
"wireguard/wg-private-zone-2-id-7.age".publicKeys = system-wg ++ users;
|
||||||
"wireguard/wg-private-zone-2-id-21.age".publicKeys = system-wg ++ users;
|
"wireguard/wg-private-zone-2-id-8.age".publicKeys = system-wg ++ users;
|
||||||
"wireguard/wg-private-zone-2-id-22.age".publicKeys = system-wg ++ users;
|
"wireguard/wg-private-zone-2-id-9.age".publicKeys = system-wg ++ users;
|
||||||
"wireguard/wg-private-zone-2-id-23.age".publicKeys = system-wg ++ users;
|
"wireguard/wg-private-zone-2-id-10.age".publicKeys = system-wg ++ users;
|
||||||
"wireguard/wg-private-zone-2-id-24.age".publicKeys = system-wg ++ users;
|
"wireguard/wg-private-zone-2-id-11.age".publicKeys = system-wg ++ users;
|
||||||
"wireguard/wg-private-zone-2-id-25.age".publicKeys = system-wg ++ users;
|
"wireguard/wg-private-zone-2-id-12.age".publicKeys = system-wg ++ users;
|
||||||
|
|
||||||
# Bastion secrets
|
# Bastion secrets
|
||||||
|
|
||||||
|
|
|
@ -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"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
};
|
||||||
}
|
}
|
|
@ -3,7 +3,8 @@
|
||||||
let
|
let
|
||||||
# Import nodes
|
# Import nodes
|
||||||
nodes = import ./../../nodes.nix;
|
nodes = import ./../../nodes.nix;
|
||||||
myPeer = nodes."${config.hostName}";
|
myName = config.hostName;
|
||||||
|
myPeer = nodes."${myName}";
|
||||||
myId = myPeer.id;
|
myId = myPeer.id;
|
||||||
myZone = myPeer.zone;
|
myZone = myPeer.zone;
|
||||||
|
|
||||||
|
@ -13,107 +14,66 @@ 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;
|
||||||
|
|
||||||
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
|
# Filter itself out of the peer list
|
||||||
peerConfigs = lib.filterAttrs (_peerName: peerConfig: peerConfig.id != myId) nodes;
|
peerConfigs = lib.filterAttrs (peerName: _peerConfig: peerName != myName) nodes;
|
||||||
|
|
||||||
# We'll make one if per peer, this is more flexible
|
interfacePeers = lib.mapAttrsToList (peerName: peerConfig: {
|
||||||
interfacePeers = lib.flatten (lib.mapAttrsToList (peerName: peerConfig: let
|
PublicKey = peerConfig.wg-pub;
|
||||||
remoteId = peerConfig.id;
|
AllowedIPs = [
|
||||||
remoteZone = peerConfig.zone;
|
"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;
|
||||||
|
|
||||||
# The mesh is for now only IPv4 based
|
interfaceConfig = {
|
||||||
if4 = {
|
PrivateKeyFile = config.age.secrets."wg-private-zone-${toString myZone}-id-${toString myId}".path;
|
||||||
"mesh-${shorten peerName}-${toString remoteZone}-${toString remoteId}" = {
|
ListenPort = 51820;
|
||||||
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);
|
# Return route for mgmt traffic
|
||||||
|
bastionConfigs = lib.filterAttrs (peerName: _peerConfig: lib.elem peerName mapping.bastion) peerConfigs;
|
||||||
|
|
||||||
wireguardInterfaces = builtins.foldl' (acc: set: acc // set) {} interfacePeers;
|
rtwg4 = map (node: {
|
||||||
|
Gateway = "172.19.${toString node.zone}.${toString node.id}";
|
||||||
|
Destination = "172.19.${toString (node.zone + 127)}.0/24";
|
||||||
|
}) (lib.attrValues bastionConfigs);
|
||||||
|
|
||||||
generateRoute = peerName: peerConfig: ''
|
rtwg6 = map (node: {
|
||||||
# Static route to declare static wireguard peer inner tunnel ip (that has been thrown away to the "off" table)
|
Gateway = "fc00::${toString node.zone}:${toString node.id}";
|
||||||
${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
|
Destination = "fc00:f::${toString (node.zone + 127)}:0/112";
|
||||||
${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
|
}) (lib.attrValues bastionConfigs);
|
||||||
|
|
||||||
# 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}
|
|
||||||
'';
|
|
||||||
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 = wireguardInterfaces;
|
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";
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
|
@ -35,11 +35,5 @@ in
|
||||||
linkConfig.RequiredForOnline = "routable";
|
linkConfig.RequiredForOnline = "routable";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
config.addRouteTablesToIPRoute2 = true;
|
|
||||||
config.routeTables = {
|
|
||||||
# Act as a route bin
|
|
||||||
off = 999;
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
}
|
}
|
|
@ -7,10 +7,6 @@ let
|
||||||
|
|
||||||
# Import mapping
|
# Import mapping
|
||||||
mapping = import ./../../mapping.nix;
|
mapping = import ./../../mapping.nix;
|
||||||
|
|
||||||
meshUdpRange = "51000-${toString (51000 + builtins.head (
|
|
||||||
builtins.sort (a: b: a > b) (
|
|
||||||
lib.mapAttrsToList (name: node: node.id) nodes)))}";
|
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
networking = {
|
networking = {
|
||||||
|
@ -50,7 +46,7 @@ in
|
||||||
tcp dport 22 accept
|
tcp dport 22 accept
|
||||||
|
|
||||||
# Mesh
|
# Mesh
|
||||||
udp dport ${meshUdpRange} accept
|
udp dport 51820 accept
|
||||||
|
|
||||||
${if lib.elem myName mapping.bastion then ''
|
${if lib.elem myName mapping.bastion then ''
|
||||||
# Mgmt
|
# Mgmt
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue