forked from mirrors_public/oddlama_nix-config
feat(wireguard): associate external peers to the specific defining node
This commit is contained in:
parent
d522a46f1d
commit
925d3856e0
6 changed files with 103 additions and 47 deletions
|
@ -20,4 +20,6 @@
|
|||
dhcpV6Config.RouteMetric = 40;
|
||||
};
|
||||
};
|
||||
|
||||
extra.wireguard.vms.address = ["10.0.0.10/32"];
|
||||
}
|
||||
|
|
|
@ -17,4 +17,16 @@
|
|||
};
|
||||
};
|
||||
};
|
||||
|
||||
extra.wireguard.vms = {
|
||||
server = {
|
||||
enable = true;
|
||||
port = 51822;
|
||||
openFirewall = true;
|
||||
};
|
||||
address = ["10.0.0.2/24"];
|
||||
externalPeers = {
|
||||
zack1 = ["10.0.0.90/32"];
|
||||
};
|
||||
};
|
||||
}
|
||||
|
|
|
@ -37,7 +37,7 @@
|
|||
|
||||
configForNetwork = wgName: wg: let
|
||||
inherit
|
||||
(extraLib.wireguard wgName)
|
||||
(extraLib.wireguard wgName nodes)
|
||||
allPeers
|
||||
peerPresharedKeyPath
|
||||
peerPresharedKeySecret
|
||||
|
@ -46,7 +46,7 @@
|
|||
peerPublicKeyPath
|
||||
;
|
||||
|
||||
otherPeers = filterAttrs (n: _: n != nodeName) (allPeers nodes);
|
||||
otherPeers = filterAttrs (n: _: n != nodeName) allPeers;
|
||||
in {
|
||||
secrets =
|
||||
concatAttrs (map (other: {
|
||||
|
@ -130,8 +130,12 @@ in {
|
|||
default = {};
|
||||
example = {my-android-phone = ["10.0.0.97/32"];};
|
||||
description = mdDoc ''
|
||||
Allows defining extra set of external peers that should be added to the configuration.
|
||||
For each external peers you can define one or multiple allowed ips.
|
||||
Allows defining an extra set of peers that should be added to this wireguard network,
|
||||
but will not be managed by this flake. (e.g. phones)
|
||||
|
||||
These external peers will only know this node as a peer, which will forward
|
||||
their traffic to other members of the network if required. This requires
|
||||
this node to act as a server.
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
@ -144,17 +148,17 @@ in {
|
|||
in {
|
||||
assertions = concatMap (wgName: let
|
||||
inherit
|
||||
(extraLib.wireguard wgName)
|
||||
(extraLib.wireguard wgName nodes)
|
||||
externalPeerNamesRaw
|
||||
usedAddresses
|
||||
associatedNodes
|
||||
;
|
||||
|
||||
duplicatePeers = duplicates (externalPeerNamesRaw nodes);
|
||||
duplicateAddrs = duplicates (map (x: head (splitString "/" x)) (usedAddresses nodes));
|
||||
duplicatePeers = duplicates externalPeerNamesRaw;
|
||||
duplicateAddrs = duplicates (map (x: head (splitString "/" x)) usedAddresses);
|
||||
in [
|
||||
{
|
||||
assertion = any (n: nodes.${n}.config.extra.wireguard.${wgName}.server.enable) (associatedNodes nodes);
|
||||
assertion = any (n: nodes.${n}.config.extra.wireguard.${wgName}.server.enable) associatedNodes;
|
||||
message = "Wireguard network '${wgName}': At least one node must be a server.";
|
||||
}
|
||||
{
|
||||
|
@ -165,6 +169,10 @@ in {
|
|||
assertion = duplicateAddrs == [];
|
||||
message = "Wireguard network '${wgName}': Addresses used multiple times: ${concatStringsSep ", " duplicateAddrs}";
|
||||
}
|
||||
# TODO externalPeers != [] -> server.listen
|
||||
# TODO externalPeers != [] -> ip forwarding
|
||||
# TODO psks only between all nodes and each node-externalpeer pair
|
||||
# TODO no overlapping allowed ip range? 0.0.0.0 would be ok to overlap though
|
||||
]) (attrNames cfg);
|
||||
|
||||
networking.firewall.allowedUDPPorts = mkIf (cfg.server.enable && cfg.server.openFirewall) [cfg.server.port];
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
concatStringsSep
|
||||
escapeShellArg
|
||||
filter
|
||||
optionalString
|
||||
removeSuffix
|
||||
substring
|
||||
unique
|
||||
|
@ -33,17 +34,19 @@
|
|||
|
||||
generateNetworkKeys = wgName: let
|
||||
inherit
|
||||
(extraLib.wireguard wgName)
|
||||
(extraLib.wireguard wgName self.nodes)
|
||||
allPeers
|
||||
associatedNodes
|
||||
associatedServerNodes
|
||||
associatedClientNodes
|
||||
externalPeersForNode
|
||||
peerPresharedKeyFile
|
||||
peerPrivateKeyFile
|
||||
peerPublicKeyFile
|
||||
sortedPeers
|
||||
;
|
||||
|
||||
nodesWithNet = associatedNodes self.nodes;
|
||||
peers = attrNames (allPeers self.nodes);
|
||||
|
||||
# Every peer needs a private and public key.
|
||||
generatePeerKeys = peerName: let
|
||||
keyBasename = escapeShellArg ("./" + removeSuffix ".pub" (peerPublicKeyFile peerName));
|
||||
pubkeyFile = escapeShellArg ("./" + peerPublicKeyFile peerName);
|
||||
|
@ -59,22 +62,35 @@
|
|||
fi
|
||||
'';
|
||||
|
||||
generatePeerPsks = nodePeerName:
|
||||
map (peerName: let
|
||||
pskFile = escapeShellArg ("./" + peerPresharedKeyFile nodePeerName peerName);
|
||||
# Generates the psk for peer1 and peer2.
|
||||
generatePeerPsk = {
|
||||
peer1,
|
||||
peer2,
|
||||
}: let
|
||||
pskFile = escapeShellArg ("./" + peerPresharedKeyFile peer1 peer2);
|
||||
in ''
|
||||
if [[ ! -e ${pskFile} ]]; then
|
||||
mkdir -p $(dirname ${pskFile})
|
||||
echo "Generating [33m"${pskFile}"[m"
|
||||
psk=$(${pkgs.wireguard-tools}/bin/wg genpsk)
|
||||
${pkgs.rage}/bin/rage -e ${masterIdentityArgs} ${extraEncryptionPubkeys} <<< "$psk" > ${pskFile} \
|
||||
|| { echo "[1;31merror:[m Failed to encrypt wireguard psk for peers ${nodePeerName} and ${peerName} on network ${wgName}!" >&2; exit 1; }
|
||||
|| { echo "[1;31merror:[m Failed to encrypt wireguard psk for peers ${peer1} and ${peer2} on network ${wgName}!" >&2; exit 1; }
|
||||
fi
|
||||
'') (filter (x: x != nodePeerName) peers);
|
||||
'';
|
||||
|
||||
# This generates all psks for each combination of peers given.
|
||||
# xs is a list of peers and fys a function that generates a list of peers
|
||||
# for any given x.
|
||||
psksForPeerCombinations = xs: fys: map generatePeerPsk (unique (concatMap (x: map (sortedPeers x) (fys x)) xs));
|
||||
in
|
||||
["echo ==== ${wgName} ===="]
|
||||
++ map generatePeerKeys peers
|
||||
++ concatMap generatePeerPsks nodesWithNet;
|
||||
++ map generatePeerKeys (attrNames allPeers)
|
||||
# All server-nodes need a psk for each other, but not reflexive.
|
||||
++ psksForPeerCombinations associatedServerNodes (n: filter (x: x != n) associatedServerNodes)
|
||||
# Each server-node need a psk for all client nodes
|
||||
++ psksForPeerCombinations associatedServerNodes (_: associatedClientNodes)
|
||||
# Each server-node need a psk for all their external peers
|
||||
++ psksForPeerCombinations associatedServerNodes (n: attrNames (externalPeersForNode n));
|
||||
in
|
||||
pkgs.writeShellScript "generate-wireguard-keys" ''
|
||||
set -euo pipefail
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
|
||||
externalPeersForNet = wgName:
|
||||
map (peer: {inherit wgName peer;})
|
||||
(attrNames ((extraLib.wireguard wgName).externalPeers self.nodes));
|
||||
(attrNames (extraLib.wireguard wgName self.nodes).allExternalPeers);
|
||||
allExternalPeers = concatMap externalPeersForNet wireguardNetworks;
|
||||
in
|
||||
# TODO generate "classic" config and run qrencode
|
||||
|
|
58
nix/lib.nix
58
nix/lib.nix
|
@ -11,6 +11,7 @@
|
|||
mapAttrs'
|
||||
mergeAttrs
|
||||
nameValuePair
|
||||
partition
|
||||
unique
|
||||
;
|
||||
in rec {
|
||||
|
@ -33,8 +34,8 @@ in rec {
|
|||
concatAttrs = foldl' mergeAttrs {};
|
||||
|
||||
# Wireguard related functions that are reused in several files of this flake
|
||||
wireguard = wgName: rec {
|
||||
_sortedPeers = peerA: peerB:
|
||||
wireguard = wgName: nodes: rec {
|
||||
sortedPeers = peerA: peerB:
|
||||
if peerA < peerB
|
||||
then {
|
||||
peer1 = peerA;
|
||||
|
@ -53,32 +54,49 @@ in rec {
|
|||
peerPrivateKeySecret = peerName: "wireguard-${wgName}-priv-${peerName}";
|
||||
|
||||
peerPresharedKeyFile = peerA: peerB: let
|
||||
inherit (_sortedPeers peerA peerB) peer1 peer2;
|
||||
inherit (sortedPeers peerA peerB) peer1 peer2;
|
||||
in "secrets/wireguard/${wgName}/psks/${peer1}+${peer2}.age";
|
||||
peerPresharedKeyPath = peerA: peerB: "${../.}/" + peerPresharedKeyFile peerA peerB;
|
||||
peerPresharedKeySecret = peerA: peerB: let
|
||||
inherit (_sortedPeers peerA peerB) peer1 peer2;
|
||||
inherit (sortedPeers peerA peerB) peer1 peer2;
|
||||
in "wireguard-${wgName}-psks-${peer1}+${peer2}";
|
||||
|
||||
# All nodes that are part of this network
|
||||
associatedNodes = nodes: filter (n: builtins.hasAttr wgName nodes.${n}.config.extra.wireguard) (attrNames nodes);
|
||||
nodePeers = nodes: genAttrs (associatedNodes nodes) (n: nodes.${n}.config.extra.wireguard.${wgName}.address);
|
||||
associatedNodes =
|
||||
filter
|
||||
(n: builtins.hasAttr wgName nodes.${n}.config.extra.wireguard)
|
||||
(attrNames nodes);
|
||||
|
||||
# Partition nodes by whether they are servers
|
||||
_associatedNodes_isServerPartition =
|
||||
partition
|
||||
(n: nodes.${n}.config.extra.wireguard.${wgName}.server.enable)
|
||||
associatedNodes;
|
||||
|
||||
associatedServerNodes = _associatedNodes_isServerPartition.right;
|
||||
associatedClientNodes = _associatedNodes_isServerPartition.wrong;
|
||||
|
||||
# Maps all nodes that are part of this network to their addresses
|
||||
nodePeers = genAttrs associatedNodes (n: nodes.${n}.config.extra.wireguard.${wgName}.address);
|
||||
|
||||
# Only peers that are defined as externalPeers on the given node.
|
||||
# Prepends "external-" to their name.
|
||||
externalPeersForNode = node:
|
||||
mapAttrs' (p: nameValuePair "external-${p}") nodes.${node}.config.extra.wireguard.${wgName}.externalPeers;
|
||||
|
||||
# All peers that are defined as externalPeers on any node.
|
||||
# Prepends "external-" to their name.
|
||||
externalPeers = nodes:
|
||||
concatAttrs (
|
||||
map (n: mapAttrs' (extPeerName: nameValuePair "external-${extPeerName}") nodes.${n}.config.extra.wireguard.${wgName}.externalPeers)
|
||||
(associatedNodes nodes)
|
||||
);
|
||||
# Concatenation of all external peer names names without any transformations.
|
||||
externalPeerNamesRaw = nodes: concatMap (n: attrNames nodes.${n}.config.extra.wireguard.${wgName}.externalPeers) (associatedNodes nodes);
|
||||
# A list of all occurring addresses.
|
||||
usedAddresses = nodes: let
|
||||
nodesWithNet = associatedNodes nodes;
|
||||
in
|
||||
concatMap (n: nodes.${n}.config.extra.wireguard.${wgName}.address) nodesWithNet
|
||||
++ flatten (concatMap (n: attrValues nodes.${n}.config.extra.wireguard.${wgName}.externalPeers) nodesWithNet);
|
||||
allExternalPeers = concatAttrs (map externalPeersForNode associatedNodes);
|
||||
|
||||
allPeers = nodes: nodePeers nodes // externalPeers nodes;
|
||||
# All peers that are part of this network
|
||||
allPeers = nodePeers // allExternalPeers;
|
||||
|
||||
# Concatenation of all external peer names names without any transformations.
|
||||
externalPeerNamesRaw = concatMap (n: attrNames nodes.${n}.config.extra.wireguard.${wgName}.externalPeers) associatedNodes;
|
||||
|
||||
# A list of all occurring addresses.
|
||||
usedAddresses =
|
||||
concatMap (n: nodes.${n}.config.extra.wireguard.${wgName}.address) associatedNodes
|
||||
++ flatten (concatMap (n: attrValues nodes.${n}.config.extra.wireguard.${wgName}.externalPeers) associatedNodes);
|
||||
};
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue