wireguard: make external peers connect to all controllers
This commit is contained in:
@@ -309,10 +309,12 @@ in
|
|||||||
List of external peer names that are not part of the clan.
|
List of external peer names that are not part of the clan.
|
||||||
|
|
||||||
For ever entry here, a key pair for an external device will be generated.
|
For ever entry here, a key pair for an external device will be generated.
|
||||||
Each external peer must be configured on exactly ONE controller.
|
|
||||||
This key pair can then then be displayed via `clan vars get` and inserted into an external device, like a phone or laptop.
|
This key pair can then then be displayed via `clan vars get` and inserted into an external device, like a phone or laptop.
|
||||||
|
|
||||||
The names in this list must not collide with machine names in the clan.
|
Each external peer can connect to the mesh through one or more controllers.
|
||||||
|
To connect to multiple controllers, set `roles.controller.settings.externalPeers`.
|
||||||
|
|
||||||
|
The external peer names must not collide with machine names in the clan.
|
||||||
The machines which are part of the clan will be able to resolve the external peers via their host names, but not vice versa.
|
The machines which are part of the clan will be able to resolve the external peers via their host names, but not vice versa.
|
||||||
External peers can still reach machines from within the clan via their IPv6 addresses.
|
External peers can still reach machines from within the clan via their IPv6 addresses.
|
||||||
'';
|
'';
|
||||||
@@ -340,6 +342,10 @@ in
|
|||||||
let
|
let
|
||||||
allOtherControllers = lib.filterAttrs (name: _v: name != machine.name) roles.controller.machines;
|
allOtherControllers = lib.filterAttrs (name: _v: name != machine.name) roles.controller.machines;
|
||||||
allPeers = roles.peer.machines;
|
allPeers = roles.peer.machines;
|
||||||
|
# Collect all external peers from all controllers
|
||||||
|
allExternalPeers = lib.unique (
|
||||||
|
lib.flatten (lib.mapAttrsToList (_: ctrl: ctrl.settings.externalPeers) roles.controller.machines)
|
||||||
|
);
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
imports = [
|
imports = [
|
||||||
@@ -447,7 +453,7 @@ in
|
|||||||
persistentKeepalive = 25;
|
persistentKeepalive = 25;
|
||||||
}) allPeers)
|
}) allPeers)
|
||||||
++
|
++
|
||||||
# External peers configuration
|
# External peers configuration - includes all external peers from all controllers
|
||||||
(map (peer: {
|
(map (peer: {
|
||||||
publicKey = (
|
publicKey = (
|
||||||
builtins.readFile (
|
builtins.readFile (
|
||||||
@@ -474,7 +480,7 @@ in
|
|||||||
|
|
||||||
# No endpoint for external peers, they initiate the connection
|
# No endpoint for external peers, they initiate the connection
|
||||||
persistentKeepalive = 25;
|
persistentKeepalive = 25;
|
||||||
}) settings.externalPeers)
|
}) allExternalPeers)
|
||||||
++
|
++
|
||||||
# Other controllers configuration
|
# Other controllers configuration
|
||||||
(lib.mapAttrsToList (name: value: {
|
(lib.mapAttrsToList (name: value: {
|
||||||
|
|||||||
@@ -21,6 +21,11 @@ let
|
|||||||
config.clan.directory
|
config.clan.directory
|
||||||
+ "/vars/per-machine/${controllerName}/wireguard-network-wg-test-one/prefix/value"
|
+ "/vars/per-machine/${controllerName}/wireguard-network-wg-test-one/prefix/value"
|
||||||
);
|
);
|
||||||
|
peerSuffix =
|
||||||
|
peerName:
|
||||||
|
builtins.readFile (
|
||||||
|
config.clan.directory + "/vars/per-machine/${peerName}/wireguard-network-wg-test-one/suffix/value"
|
||||||
|
);
|
||||||
# external peer suffixes are stored via shared vars
|
# external peer suffixes are stored via shared vars
|
||||||
externalPeerSuffix =
|
externalPeerSuffix =
|
||||||
externalName:
|
externalName:
|
||||||
@@ -70,6 +75,8 @@ in
|
|||||||
|
|
||||||
roles.controller.machines."controller2".settings = {
|
roles.controller.machines."controller2".settings = {
|
||||||
endpoint = "192.168.1.2";
|
endpoint = "192.168.1.2";
|
||||||
|
# add the same external peer to controller2 to test multi-controller connection
|
||||||
|
externalPeers = [ "external1" ];
|
||||||
};
|
};
|
||||||
|
|
||||||
roles.peer.machines = {
|
roles.peer.machines = {
|
||||||
@@ -99,15 +106,21 @@ in
|
|||||||
nodes.external1 =
|
nodes.external1 =
|
||||||
let
|
let
|
||||||
controller1Prefix = controllerPrefix "controller1";
|
controller1Prefix = controllerPrefix "controller1";
|
||||||
|
controller2Prefix = controllerPrefix "controller2";
|
||||||
external1Suffix = externalPeerSuffix "external1";
|
external1Suffix = externalPeerSuffix "external1";
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
networking.extraHosts = ''
|
networking.extraHosts = ''
|
||||||
${controller1Prefix}::1 controller1.wg-test-one
|
${controller1Prefix}::1 controller1.wg-test-one
|
||||||
|
${controller2Prefix}::1 controller2.wg-test-one
|
||||||
'';
|
'';
|
||||||
networking.wireguard.interfaces."wg0" = {
|
networking.wireguard.interfaces."wg0" = {
|
||||||
|
|
||||||
ips = [ "${controller1Prefix + ":" + external1Suffix}/56" ];
|
# Multiple IPs, one in each controller's subnet
|
||||||
|
ips = [
|
||||||
|
"${controller1Prefix + ":" + external1Suffix}/56"
|
||||||
|
"${controller2Prefix + ":" + external1Suffix}/56"
|
||||||
|
];
|
||||||
|
|
||||||
privateKeyFile =
|
privateKeyFile =
|
||||||
builtins.toFile "wg-priv-key"
|
builtins.toFile "wg-priv-key"
|
||||||
@@ -116,7 +129,9 @@ in
|
|||||||
# echo "AGE-SECRET-KEY-1PL0M9CWRCG3PZ9DXRTTLMCVD57U6JDFE8K7DNVQ35F4JENZ6G3MQ0RQLRV" | SOPS_AGE_KEY_FILE=/dev/stdin nix run nixpkgs#sops decrypt clanServices/wireguard/tests/vm/vars/shared/wireguard-network-wg-test-one-external-peer-external1/privatekey/secret
|
# echo "AGE-SECRET-KEY-1PL0M9CWRCG3PZ9DXRTTLMCVD57U6JDFE8K7DNVQ35F4JENZ6G3MQ0RQLRV" | SOPS_AGE_KEY_FILE=/dev/stdin nix run nixpkgs#sops decrypt clanServices/wireguard/tests/vm/vars/shared/wireguard-network-wg-test-one-external-peer-external1/privatekey/secret
|
||||||
"wO8dl3JWgV5J+0D/2UDcLsxTD25IWTvd5ed6vv2Nikk=";
|
"wO8dl3JWgV5J+0D/2UDcLsxTD25IWTvd5ed6vv2Nikk=";
|
||||||
|
|
||||||
|
# Connect to both controllers
|
||||||
peers = [
|
peers = [
|
||||||
|
# Controller 1
|
||||||
{
|
{
|
||||||
publicKey = (
|
publicKey = (
|
||||||
builtins.readFile (
|
builtins.readFile (
|
||||||
@@ -124,14 +139,26 @@ in
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
# Allow each controller's /56 subnet
|
# Allow controller1's /56 subnet
|
||||||
allowedIPs = [
|
allowedIPs = [ "${controller1Prefix}::/56" ];
|
||||||
# "${controller1Prefix}::/56"
|
|
||||||
"::/0"
|
|
||||||
];
|
|
||||||
|
|
||||||
endpoint = "controller1:51820";
|
endpoint = "controller1:51820";
|
||||||
|
|
||||||
|
persistentKeepalive = 25;
|
||||||
|
}
|
||||||
|
# Controller 2
|
||||||
|
{
|
||||||
|
publicKey = (
|
||||||
|
builtins.readFile (
|
||||||
|
config.clan.directory + "/vars/per-machine/controller2/wireguard-keys-wg-test-one/publickey/value"
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
# Allow controller2's /56 subnet
|
||||||
|
allowedIPs = [ "${controller2Prefix}::/56" ];
|
||||||
|
|
||||||
|
endpoint = "controller2:51820";
|
||||||
|
|
||||||
persistentKeepalive = 25;
|
persistentKeepalive = 25;
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
@@ -141,8 +168,8 @@ in
|
|||||||
testScript = ''
|
testScript = ''
|
||||||
start_all()
|
start_all()
|
||||||
|
|
||||||
# Show all addresses
|
# Start network on all machines including external1
|
||||||
machines = [peer1, peer2, peer3, controller1, controller2]
|
machines = [peer1, peer2, peer3, controller1, controller2, external1]
|
||||||
for m in machines:
|
for m in machines:
|
||||||
m.systemctl("start network-online.target")
|
m.systemctl("start network-online.target")
|
||||||
|
|
||||||
@@ -154,14 +181,35 @@ in
|
|||||||
print("STARTING PING TESTS")
|
print("STARTING PING TESTS")
|
||||||
print("="*60)
|
print("="*60)
|
||||||
|
|
||||||
for m1 in machines:
|
# Test mesh connectivity between regular clan machines
|
||||||
# ping all other machines
|
clan_machines = [peer1, peer2, peer3, controller1, controller2]
|
||||||
for m2 in machines:
|
for m1 in clan_machines:
|
||||||
|
for m2 in clan_machines:
|
||||||
if m1 != m2:
|
if m1 != m2:
|
||||||
print(f"\n--- Pinging from {m1.name} to {m2.name}.wg-test-one ---")
|
print(f"\n--- Pinging from {m1.name} to {m2.name}.wg-test-one ---")
|
||||||
m1.wait_until_succeeds(f"ping -c1 {m2.name}.wg-test-one >&2")
|
m1.wait_until_succeeds(f"ping -c1 {m2.name}.wg-test-one >&2")
|
||||||
# ping external peer from all other peers and controllers
|
|
||||||
print(f"\n--- Pinging from {m1.name} to external1.wg-test-one ---")
|
# Test that external peer can reach both controllers (multi-controller connection)
|
||||||
m1.wait_until_succeeds("ping -c1 external1.wg-test-one >&2")
|
print("\n--- Testing external1 -> controller1 (direct connection) ---")
|
||||||
|
external1.wait_until_succeeds("ping -c1 controller1.wg-test-one >&2")
|
||||||
|
|
||||||
|
print("\n--- Testing external1 -> controller2 (direct connection) ---")
|
||||||
|
external1.wait_until_succeeds("ping -c1 controller2.wg-test-one >&2")
|
||||||
|
|
||||||
|
# Test that all clan machines can reach the external peer
|
||||||
|
for m in clan_machines:
|
||||||
|
print(f"\n--- Pinging from {m.name} to external1.wg-test-one ---")
|
||||||
|
m.wait_until_succeeds("ping -c1 external1.wg-test-one >&2")
|
||||||
|
|
||||||
|
# Test that external peer can reach a regular peer via controller1
|
||||||
|
print("\n--- Testing external1 -> peer1 (via controller1) ---")
|
||||||
|
external1.wait_until_succeeds("ping -c1 ${controllerPrefix "controller1"}:${peerSuffix "peer1"} >&2")
|
||||||
|
|
||||||
|
# Test controller failover
|
||||||
|
print("\n--- Shutting down controller1 ---")
|
||||||
|
controller1.shutdown()
|
||||||
|
print("\n--- Testing external1 -> peer1 (via controller2 after controller1 shutdown) ---")
|
||||||
|
external1.wait_until_succeeds("ping -c1 ${controllerPrefix "controller2"}:${peerSuffix "peer1"} >&2")
|
||||||
|
|
||||||
'';
|
'';
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user