feat(wireguard): generate psks only if needed; add most of the qr code generator

This commit is contained in:
oddlama 2023-04-15 01:51:33 +02:00
parent 925d3856e0
commit d5f2880457
No known key found for this signature in database
GPG key ID: 14EFE510775FE39A
13 changed files with 225 additions and 108 deletions

View file

@ -52,6 +52,8 @@
... ...
} @ inputs: } @ inputs:
{ {
extraLib = import ./nix/lib.nix inputs;
# The identities that are used to rekey agenix secrets and to # The identities that are used to rekey agenix secrets and to
# decrypt all repository-wide secrets. # decrypt all repository-wide secrets.
secrets = { secrets = {

View file

@ -21,5 +21,8 @@
}; };
}; };
extra.wireguard.vms.address = ["10.0.0.10/32"]; extra.wireguard.vms = {
via = "ward";
addresses = ["10.0.0.10/32"];
};
} }

View file

@ -27,12 +27,12 @@
enable = true; enable = true;
port = 51822; port = 51822;
openFirewall = true; openFirewall = true;
};
address = ["10.0.0.1/24"];
externalPeers = { externalPeers = {
test1 = ["10.0.0.91/32"]; test1 = ["10.0.0.91/32"];
test2 = ["10.0.0.92/32"]; test2 = ["10.0.0.92/32"];
test3 = ["10.0.0.93/32"]; test3 = ["10.0.0.93/32"];
}; };
}; };
addresses = ["10.0.0.1/24"];
};
} }

View file

@ -23,10 +23,10 @@
enable = true; enable = true;
port = 51822; port = 51822;
openFirewall = true; openFirewall = true;
};
address = ["10.0.0.2/24"];
externalPeers = { externalPeers = {
zack1 = ["10.0.0.90/32"]; zack1 = ["10.0.0.90/32"];
}; };
}; };
addresses = ["10.0.0.2/24"];
};
} }

View file

@ -11,9 +11,11 @@
(lib) (lib)
any any
attrNames attrNames
attrValues
concatMap concatMap
concatMapStrings concatMapStrings
concatStringsSep concatStringsSep
filter
filterAttrs filterAttrs
head head
mapAttrsToList mapAttrsToList
@ -23,6 +25,7 @@
mkOption mkOption
mkEnableOption mkEnableOption
optionalAttrs optionalAttrs
optionals
splitString splitString
types types
; ;
@ -35,10 +38,12 @@
cfg = config.extra.wireguard; cfg = config.extra.wireguard;
configForNetwork = wgName: wg: let configForNetwork = wgName: wgCfg: let
inherit inherit
(extraLib.wireguard wgName nodes) (extraLib.wireguard wgName)
allPeers associatedServerNodes
associatedClientNodes
externalPeerName
peerPresharedKeyPath peerPresharedKeyPath
peerPresharedKeySecret peerPresharedKeySecret
peerPrivateKeyPath peerPrivateKeyPath
@ -46,17 +51,32 @@
peerPublicKeyPath peerPublicKeyPath
; ;
otherPeers = filterAttrs (n: _: n != nodeName) allPeers; filterSelf = filter (x: x != nodeName);
wgCfgOf = node: nodes.${node}.config.extra.wireguard.${wgName};
ourClientNodes =
optionals wgCfg.server.enable
(filter (n: (wgCfgOf n).via == nodeName) associatedClientNodes);
# The list of peers that we have to know the psk to.
neededPeers =
if wgCfg.server.enable
then
filterSelf associatedServerNodes
++ map externalPeerName (attrNames wgCfg.server.externalPeers)
++ ourClientNodes
else [wgCfg.via];
in { in {
secrets = secrets =
concatAttrs (map (other: { concatAttrs (map (other: {
${peerPresharedKeySecret nodeName other}.file = peerPresharedKeyPath nodeName other; ${peerPresharedKeySecret nodeName other}.file = peerPresharedKeyPath nodeName other;
}) (attrNames otherPeers)) })
neededPeers)
// { // {
${peerPrivateKeySecret nodeName}.file = peerPrivateKeyPath nodeName; ${peerPrivateKeySecret nodeName}.file = peerPrivateKeyPath nodeName;
}; };
netdevs."${wg.priority}-${wgName}" = { netdevs."${wgCfg.priority}-${wgName}" = {
netdevConfig = { netdevConfig = {
Kind = "wireguard"; Kind = "wireguard";
Name = "${wgName}"; Name = "${wgName}";
@ -66,27 +86,64 @@
{ {
PrivateKeyFile = config.rekey.secrets.${peerPrivateKeySecret nodeName}.path; PrivateKeyFile = config.rekey.secrets.${peerPrivateKeySecret nodeName}.path;
} }
// optionalAttrs wg.server.enable { // optionalAttrs wgCfg.server.enable {
ListenPort = wg.server.port; ListenPort = wgCfg.server.port;
}; };
wireguardPeers = wireguardPeers =
mapAttrsToList (peerName: peerAllowedIPs: { if wgCfg.server.enable
wireguardPeerConfig = then
{ # Always include all other server nodes.
map (serverNode: {
wireguardPeerConfig = {
PublicKey = builtins.readFile (peerPublicKeyPath serverNode);
PresharedKeyFile = config.rekey.secrets.${peerPresharedKeySecret nodeName serverNode}.path;
# The allowed ips of a server node are it's own addreses,
# plus each external peer's addresses,
# plus each client's addresses that is connected via this node.
AllowedIPs =
(wgCfgOf serverNode).addresses
++ attrValues (wgCfgOf serverNode).server.externalPeers
++ map (n: (wgCfgOf n).addresses) ourClientNodes;
};
}) (filterSelf associatedServerNodes)
# All our external peers
++ mapAttrsToList (extPeer: allowedIPs: let
peerName = externalPeerName extPeer;
in {
wireguardPeerConfig = {
PublicKey = builtins.readFile (peerPublicKeyPath peerName); PublicKey = builtins.readFile (peerPublicKeyPath peerName);
PresharedKeyFile = config.rekey.secrets.${peerPresharedKeySecret nodeName peerName}.path; PresharedKeyFile = config.rekey.secrets.${peerPresharedKeySecret nodeName peerName}.path;
AllowedIPs = peerAllowedIPs; AllowedIPs = allowedIPs;
}
// optionalAttrs wg.server.enable {
PersistentKeepalive = 25; PersistentKeepalive = 25;
}; };
}) })
otherPeers; wgCfg.server.externalPeers
# All client nodes that have their via set to us.
++ mapAttrsToList (clientNode: {
wireguardPeerConfig = {
PublicKey = builtins.readFile (peerPublicKeyPath clientNode);
PresharedKeyFile = config.rekey.secrets.${peerPresharedKeySecret nodeName clientNode}.path;
AllowedIPs = (wgCfgOf clientNode).addresses;
PersistentKeepalive = 25;
};
})
ourClientNodes
else
# We are a client node, so only include our via server.
[
{
wireguardPeerConfig = {
PublicKey = builtins.readFile (peerPublicKeyPath wgCfg.via);
PresharedKeyFile = config.rekey.secrets.${peerPresharedKeySecret nodeName wgCfg.via}.path;
AllowedIPs = (wgCfgOf wgCfg.via).addresses;
};
}
];
}; };
networks."${wg.priority}-${wgName}" = { networks."${wgCfg.priority}-${wgName}" = {
matchConfig.Name = wgName; matchConfig.Name = wgName;
networkConfig.Address = wg.address; networkConfig.Address = wgCfg.addresses;
}; };
}; };
in { in {
@ -109,21 +166,6 @@ in {
type = types.bool; type = types.bool;
description = mdDoc "Whether to open the firewall for the specified `listenPort`, if {option}`listen` is `true`."; description = mdDoc "Whether to open the firewall for the specified `listenPort`, if {option}`listen` is `true`.";
}; };
};
priority = mkOption {
default = "20";
type = types.str;
description = mdDoc "The order priority used when creating systemd netdev and network files.";
};
address = mkOption {
type = types.listOf types.str;
description = mdDoc ''
The addresses to configure for this interface. Will automatically be added
as this peer's allowed addresses to all other peers.
'';
};
externalPeers = mkOption { externalPeers = mkOption {
type = types.attrsOf (types.listOf types.str); type = types.attrsOf (types.listOf types.str);
@ -139,6 +181,30 @@ in {
''; '';
}; };
}; };
priority = mkOption {
default = "20";
type = types.str;
description = mdDoc "The order priority used when creating systemd netdev and network files.";
};
via = mkOption {
default = null;
type = types.uniq (types.nullOr types.str);
description = mdDoc ''
The server node via which to connect to the network.
This must defined if and only if this node is not a server.
'';
};
addresses = mkOption {
type = types.listOf types.str;
description = mdDoc ''
The addresses to configure for this interface. Will automatically be added
as this peer's allowed addresses to all other peers.
'';
};
};
}); });
}; };
@ -148,12 +214,14 @@ in {
in { in {
assertions = concatMap (wgName: let assertions = concatMap (wgName: let
inherit inherit
(extraLib.wireguard wgName nodes) (extraLib.wireguard wgName)
externalPeerNamesRaw externalPeerNamesRaw
usedAddresses usedAddresses
associatedNodes associatedNodes
; ;
wgCfg = cfg.${wgName};
wgCfgOf = node: nodes.${node}.config.extra.wireguard.${wgName};
duplicatePeers = duplicates externalPeerNamesRaw; duplicatePeers = duplicates externalPeerNamesRaw;
duplicateAddrs = duplicates (map (x: head (splitString "/" x)) usedAddresses); duplicateAddrs = duplicates (map (x: head (splitString "/" x)) usedAddresses);
in [ in [
@ -169,9 +237,19 @@ in {
assertion = duplicateAddrs == []; assertion = duplicateAddrs == [];
message = "Wireguard network '${wgName}': Addresses used multiple times: ${concatStringsSep ", " duplicateAddrs}"; message = "Wireguard network '${wgName}': Addresses used multiple times: ${concatStringsSep ", " duplicateAddrs}";
} }
# TODO externalPeers != [] -> server.listen {
# TODO externalPeers != [] -> ip forwarding assertion = wgCfg.server.externalPeers != {} -> wgCfg.server.enable;
# TODO psks only between all nodes and each node-externalpeer pair message = "Wireguard network '${wgName}': Defining external peers requires server.enable = true.";
}
{
assertion = wgCfg.server.enable == (wgCfg.via == null);
message = "Wireguard network '${wgName}': A via server must be defined exactly iff this isn't a server node.";
}
{
assertion = wgCfg.via != null -> (wgCfgOf wgCfg.via).server.enable;
message = "Wireguard network '${wgName}': The specified via node '${wgCfg.via}' must be a wireguard server.";
}
# TODO externalPeers != {} -> ip forwarding
# TODO no overlapping allowed ip range? 0.0.0.0 would be ok to overlap though # TODO no overlapping allowed ip range? 0.0.0.0 would be ok to overlap though
]) (attrNames cfg); ]) (attrNames cfg);

View file

@ -1,36 +1,22 @@
{ {
self, self,
pkgs, pkgs,
nixpkgs,
... ...
}: let }: let
inherit inherit (nixpkgs.lib) concatStringsSep;
(pkgs.lib) inherit (extraLib) rageEncryptArgs;
concatMapStrings
concatStringsSep
escapeShellArg
substring
;
isAbsolutePath = x: substring 0 1 x == "/";
masterIdentityArgs = concatMapStrings (x: ''-i ${escapeShellArg x} '') self.secrets.masterIdentities;
extraEncryptionPubkeys =
concatMapStrings (
x:
if isAbsolutePath x
then ''-R ${escapeShellArg x} ''
else ''-r ${escapeShellArg x} ''
)
self.secrets.extraEncryptionPubkeys;
in in
pkgs.writeShellScript "format-secrets" '' pkgs.writeShellScript "format-secrets" ''
set -euo pipefail set -euo pipefail
[[ -d .git ]] && [[ -f flake.nix ]] || { echo "error: Please execute this from the project's root folder (the folder with flake.nix)" >&2; exit 1; } [[ -d .git ]] && [[ -f flake.nix ]] || { echo "error: Please execute this from the project's root folder (the folder with flake.nix)" >&2; exit 1; }
for f in $(find . -type f -name '*.nix.age'); do for f in $(find . -type f -name '*.nix.age'); do
echo "Formatting $f ..." echo "Formatting $f ..."
decrypted=$(${../rage-decrypt.sh} --print-out-path "$f" ${concatStringsSep " " self.secrets.masterIdentities}) \ decrypted=$(${../rage-decrypt-and-cache.sh} --print-out-path "$f" ${concatStringsSep " " self.secrets.masterIdentities}) \
|| { echo "error: Failed to decrypt!" >&2; exit 1; } || { echo "error: Failed to decrypt!" >&2; exit 1; }
formatted=$(${pkgs.alejandra}/bin/alejandra --quiet < "$decrypted") \ formatted=$(${pkgs.alejandra}/bin/alejandra --quiet < "$decrypted") \
|| { echo "error: Failed to format $decrypted!" >&2; exit 1; } || { echo "error: Failed to format $decrypted!" >&2; exit 1; }
${pkgs.rage}/bin/rage -e ${masterIdentityArgs} ${extraEncryptionPubkeys} <<< "$formatted" > "$f" \ ${pkgs.rage}/bin/rage -e ${rageEncryptArgs} <<< "$formatted" > "$f" \
|| { echo "error: Failed to re-encrypt!" >&2; exit 1; } || { echo "error: Failed to re-encrypt!" >&2; exit 1; }
done done
'' ''

View file

@ -17,24 +17,14 @@
unique unique
; ;
extraLib = import ../lib.nix inputs; inherit (self.extraLib) rageEncryptArgs;
isAbsolutePath = x: substring 0 1 x == "/";
masterIdentityArgs = concatMapStrings (x: ''-i ${escapeShellArg x} '') self.secrets.masterIdentities;
extraEncryptionPubkeys =
concatMapStrings (
x:
if isAbsolutePath x
then ''-R ${escapeShellArg x} ''
else ''-r ${escapeShellArg x} ''
)
self.secrets.extraEncryptionPubkeys;
nodeNames = attrNames self.nodes; nodeNames = attrNames self.nodes;
wireguardNetworks = unique (concatMap (n: attrNames self.nodes.${n}.config.extra.wireguard) nodeNames); wireguardNetworks = unique (concatMap (n: attrNames self.nodes.${n}.config.extra.wireguard) nodeNames);
generateNetworkKeys = wgName: let generateNetworkKeys = wgName: let
inherit inherit
(extraLib.wireguard wgName self.nodes) (self.extraLib.wireguard wgName)
allPeers allPeers
associatedNodes associatedNodes
associatedServerNodes associatedServerNodes
@ -57,7 +47,7 @@
echo "Generating "${keyBasename}".{age,pub}" echo "Generating "${keyBasename}".{age,pub}"
privkey=$(${pkgs.wireguard-tools}/bin/wg genkey) privkey=$(${pkgs.wireguard-tools}/bin/wg genkey)
echo "$privkey" | ${pkgs.wireguard-tools}/bin/wg pubkey > ${pubkeyFile} echo "$privkey" | ${pkgs.wireguard-tools}/bin/wg pubkey > ${pubkeyFile}
${pkgs.rage}/bin/rage -e ${masterIdentityArgs} ${extraEncryptionPubkeys} <<< "$privkey" > ${privkeyFile} \ ${pkgs.rage}/bin/rage -e ${rageEncryptArgs} <<< "$privkey" > ${privkeyFile} \
|| { echo "error: Failed to encrypt wireguard private key for peer ${peerName} on network ${wgName}!" >&2; exit 1; } || { echo "error: Failed to encrypt wireguard private key for peer ${peerName} on network ${wgName}!" >&2; exit 1; }
fi fi
''; '';
@ -73,7 +63,7 @@
mkdir -p $(dirname ${pskFile}) mkdir -p $(dirname ${pskFile})
echo "Generating "${pskFile}"" echo "Generating "${pskFile}""
psk=$(${pkgs.wireguard-tools}/bin/wg genpsk) psk=$(${pkgs.wireguard-tools}/bin/wg genpsk)
${pkgs.rage}/bin/rage -e ${masterIdentityArgs} ${extraEncryptionPubkeys} <<< "$psk" > ${pskFile} \ ${pkgs.rage}/bin/rage -e ${rageEncryptArgs} <<< "$psk" > ${pskFile} \
|| { echo "error: Failed to encrypt wireguard psk for peers ${peer1} and ${peer2} on network ${wgName}!" >&2; exit 1; } || { echo "error: Failed to encrypt wireguard psk for peers ${peer1} and ${peer2} on network ${wgName}!" >&2; exit 1; }
fi fi
''; '';

View file

@ -9,22 +9,57 @@
concatMap concatMap
concatStringsSep concatStringsSep
escapeShellArg escapeShellArg
filter
unique unique
; ;
extraLib = import ../lib.nix inputs; inherit (self.extraLib) rageDecryptArgs;
nodeNames = attrNames self.nodes; nodeNames = attrNames self.nodes;
wireguardNetworks = unique (concatMap (n: attrNames self.nodes.${n}.config.extra.wireguard) nodeNames); wireguardNetworks = unique (concatMap (n: attrNames self.nodes.${n}.config.extra.wireguard) nodeNames);
externalPeersForNet = wgName: externalPeersForNet = wgName:
map (peer: {inherit wgName peer;}) concatMap (serverNode:
(attrNames (extraLib.wireguard wgName self.nodes).allExternalPeers); map
(peer: {inherit wgName serverNode peer;})
(attrNames self.nodes.${serverNode}.config.extra.wireguard.${wgName}.server.externalPeers))
(self.extraLib.wireguard wgName).associatedServerNodes;
allExternalPeers = concatMap externalPeersForNet wireguardNetworks; allExternalPeers = concatMap externalPeersForNet wireguardNetworks;
in in
# TODO generate "classic" config and run qrencode
pkgs.writeShellScript "show-wireguard-qr" '' pkgs.writeShellScript "show-wireguard-qr" ''
set -euo pipefail set -euo pipefail
echo ${escapeShellArg (concatStringsSep "\n" (map (x: "${x.wgName}.${x.peer}") allExternalPeers))} | ${pkgs.fzf}/bin/fzf json_sel=$(echo ${escapeShellArg (concatStringsSep "\n" (map (x: "${builtins.toJSON x}\t${x.wgName}.${x.serverNode}.${x.peer}") allExternalPeers))} \
| ${pkgs.fzf}/bin/fzf --delimiter='\t' --ansi --multi --query="''${1-}" --tiebreak=end --bind=tab:down,btab:up,change:top,ctrl-space:toggle --with-nth=2.. --height='~50%' --tac \
| ${pkgs.coreutils}/bin/cut -d$'\t' -f1)
[[ -n "$json_sel" ]] || exit 1
# TODO for each output line
# TODO maybe just call a json -> make script that gives wireguard config to make this easier
wgName=$(${pkgs.jq}/bin/jq -r .wgName <<< "$json_sel")
serverNode=$(${pkgs.jq}/bin/jq -r .serverNode <<< "$json_sel")
peer=$(${pkgs.jq}/bin/jq -r .peer <<< "$json_sel")
serverPubkey=$(nix eval --raw ".#extraLib" \
--apply 'extraLib: builtins.readFile ((extraLib.wireguard "'"$wgName"'").peerPublicKeyPath "'"$serverNode"'")')
privKeyPath=$(nix eval --raw ".#extraLib" \
--apply 'extraLib: (extraLib.wireguard "'"$wgName"'").peerPrivateKeyPath "'"$peer"'"')
serverPskPath=$(nix eval --raw ".#extraLib" \
--apply 'extraLib: (extraLib.wireguard "'"$wgName"'").peerPresharedKeyPath "'"$serverNode"'" "'"$peer"'"')
privKey=$(${pkgs.rage}/bin/rage -d ${rageDecryptArgs} "$privKeyPath") \
|| { echo "error: Failed to decrypt!" >&2; exit 1; }
serverPsk=$(${pkgs.rage}/bin/rage -d ${rageDecryptArgs} "$serverPskPath") \
|| { echo "error: Failed to decrypt!" >&2; exit 1; }
cat <<EOF | tee /dev/tty | ${pkgs.qrencode}/bin/qrencode -t ansiutf8
[Interface]
Address =
PrivateKey = $privKey
[Peer]
PublicKey = $serverPubkey
PresharedKey = $serverPsk
AllowedIPs =
Endpoint =
EOF
'' ''

View file

@ -28,5 +28,5 @@ in {
rageImportEncrypted = identities: nixFile: rageImportEncrypted = identities: nixFile:
assert assertMsg (builtins.isPath nixFile) "The file to decrypt must be given as a path to prevent impurity."; assert assertMsg (builtins.isPath nixFile) "The file to decrypt must be given as a path to prevent impurity.";
assert assertMsg (hasSuffix ".nix.age" nixFile) "The content of the decrypted file must be a nix expression and should therefore end in .nix.age"; assert assertMsg (hasSuffix ".nix.age" nixFile) "The content of the decrypted file must be a nix expression and should therefore end in .nix.age";
exec ([./rage-decrypt.sh nixFile] ++ identities); exec ([./rage-decrypt-and-cache.sh nixFile] ++ identities);
} }

View file

@ -10,19 +10,14 @@
agenix-rekey, agenix-rekey,
... ...
} @ inputs: let } @ inputs: let
inherit inherit (nixpkgs.lib) optionals;
(nixpkgs.lib)
optionals
;
extraLib = import ./lib.nix inputs;
in in
nodeName: nodeMeta: { nodeName: nodeMeta: {
inherit (nodeMeta) system; inherit (nodeMeta) system;
pkgs = self.pkgs.${nodeMeta.system}; pkgs = self.pkgs.${nodeMeta.system};
specialArgs = { specialArgs = {
inherit (nixpkgs) lib; inherit (nixpkgs) lib;
inherit extraLib; inherit (self) extraLib;
inherit inputs; inherit inputs;
inherit nodeName; inherit nodeName;
inherit nodeMeta; inherit nodeMeta;

View file

@ -1,9 +1,15 @@
{nixpkgs, ...}: let {
self,
nixpkgs,
...
}: let
inherit inherit
(nixpkgs.lib) (nixpkgs.lib)
attrNames attrNames
attrValues attrValues
concatMap concatMap
concatMapStrings
escapeShellArg
filter filter
flatten flatten
foldl' foldl'
@ -12,6 +18,7 @@
mergeAttrs mergeAttrs
nameValuePair nameValuePair
partition partition
substring
unique unique
; ;
in rec { in rec {
@ -33,8 +40,24 @@ in rec {
# Concatenates all given attrsets as if calling a // b in order. # Concatenates all given attrsets as if calling a // b in order.
concatAttrs = foldl' mergeAttrs {}; concatAttrs = foldl' mergeAttrs {};
# True if the path or string starts with /
isAbsolutePath = x: substring 0 1 x == "/";
rageMasterIdentityArgs = concatMapStrings (x: ''-i ${escapeShellArg x} '') self.secrets.masterIdentities;
rageExtraEncryptionPubkeys =
concatMapStrings (
x:
if isAbsolutePath x
then ''-R ${escapeShellArg x} ''
else ''-r ${escapeShellArg x} ''
)
self.secrets.extraEncryptionPubkeys;
# The arguments required to de-/encrypt a secret in this repository
rageDecryptArgs = "${rageMasterIdentityArgs}";
rageEncryptArgs = "${rageMasterIdentityArgs} ${rageExtraEncryptionPubkeys}";
# Wireguard related functions that are reused in several files of this flake # Wireguard related functions that are reused in several files of this flake
wireguard = wgName: nodes: rec { wireguard = wgName: rec {
sortedPeers = peerA: peerB: sortedPeers = peerA: peerB:
if peerA < peerB if peerA < peerB
then { then {
@ -64,25 +87,27 @@ in rec {
# All nodes that are part of this network # All nodes that are part of this network
associatedNodes = associatedNodes =
filter filter
(n: builtins.hasAttr wgName nodes.${n}.config.extra.wireguard) (n: builtins.hasAttr wgName self.nodes.${n}.config.extra.wireguard)
(attrNames nodes); (attrNames self.nodes);
# Partition nodes by whether they are servers # Partition nodes by whether they are servers
_associatedNodes_isServerPartition = _associatedNodes_isServerPartition =
partition partition
(n: nodes.${n}.config.extra.wireguard.${wgName}.server.enable) (n: self.nodes.${n}.config.extra.wireguard.${wgName}.server.enable)
associatedNodes; associatedNodes;
associatedServerNodes = _associatedNodes_isServerPartition.right; associatedServerNodes = _associatedNodes_isServerPartition.right;
associatedClientNodes = _associatedNodes_isServerPartition.wrong; associatedClientNodes = _associatedNodes_isServerPartition.wrong;
# Maps all nodes that are part of this network to their addresses # Maps all nodes that are part of this network to their addresses
nodePeers = genAttrs associatedNodes (n: nodes.${n}.config.extra.wireguard.${wgName}.address); nodePeers = genAttrs associatedNodes (n: self.nodes.${n}.config.extra.wireguard.${wgName}.addresses);
externalPeerName = p: "external-${p}";
# Only peers that are defined as externalPeers on the given node. # Only peers that are defined as externalPeers on the given node.
# Prepends "external-" to their name. # Prepends "external-" to their name.
externalPeersForNode = node: externalPeersForNode = node:
mapAttrs' (p: nameValuePair "external-${p}") nodes.${node}.config.extra.wireguard.${wgName}.externalPeers; mapAttrs' (p: nameValuePair (externalPeerName p)) self.nodes.${node}.config.extra.wireguard.${wgName}.server.externalPeers;
# All peers that are defined as externalPeers on any node. # All peers that are defined as externalPeers on any node.
# Prepends "external-" to their name. # Prepends "external-" to their name.
@ -92,11 +117,11 @@ in rec {
allPeers = nodePeers // allExternalPeers; allPeers = nodePeers // allExternalPeers;
# Concatenation of all external peer names names without any transformations. # Concatenation of all external peer names names without any transformations.
externalPeerNamesRaw = concatMap (n: attrNames nodes.${n}.config.extra.wireguard.${wgName}.externalPeers) associatedNodes; externalPeerNamesRaw = concatMap (n: attrNames self.nodes.${n}.config.extra.wireguard.${wgName}.server.externalPeers) associatedNodes;
# A list of all occurring addresses. # A list of all occurring addresses.
usedAddresses = usedAddresses =
concatMap (n: nodes.${n}.config.extra.wireguard.${wgName}.address) associatedNodes concatMap (n: self.nodes.${n}.config.extra.wireguard.${wgName}.addresses) associatedNodes
++ flatten (concatMap (n: attrValues nodes.${n}.config.extra.wireguard.${wgName}.externalPeers) associatedNodes); ++ flatten (concatMap (n: attrValues self.nodes.${n}.config.extra.wireguard.${wgName}.server.externalPeers) associatedNodes);
}; };
} }

View file

@ -15,8 +15,11 @@
self, self,
nixpkgs, nixpkgs,
... ...
} @ inputs: } @ inputs: let
with nixpkgs.lib; let inherit
(nixpkgs.lib)
mapAttrs
;
# If the given expression is a bare set, it will be wrapped in a function, # If the given expression is a bare set, it will be wrapped in a function,
# so that the imported file can always be applied to the inputs, similar to # so that the imported file can always be applied to the inputs, similar to
# how modules can be functions or sets. # how modules can be functions or sets.