Key providers and other changes I forgot (sorry git historians)

release
Matthew Salerno 1 year ago
parent ca4c6e0393
commit e3c89e816f

@ -333,7 +333,8 @@ $ echo -e "paste the big text result from nix repl in here"
``` ```
# Integrations: # Integrations:
By default, WireNix supports setting wireguard keypairs with agenix-rekey. By default, WireNix supports setting wireguard keypairs with
[agenix-rekey](https://github.com/oddlama/agenix-rekey).
WireNix also supports networkd, network manager, and the nixos static network WireNix also supports networkd, network manager, and the nixos static network
configuration (default). configuration (default).

@ -0,0 +1,36 @@
{ config, lib, ... }@inputs:
with lib;
with import ./lib.nix;
{
options = {
wirenix = {
enable = mkOption {
default = true;
type = with lib.types; bool;
description = ''
Wirenix
'';
};
secretsDir = mkOption {
type = types.path;
description = mdDoc ''
where you want the wireguard secrets stored.
'';
};
};
};
config =
let
configurers = defaultConfigurers // config.modules.wirenix.additionalConfigurers;
parsers = defaultParsers // config.modules.wirenix.additionalParsers;
acl = config.modules.wirenix.aclConfig;
parser = parsers."${acl.version}" inputs;
configurer = configurers."${config.modules.wirenix.configurer}" inputs;
nixosConfigForPeer = peerName: builtins.head (builtins.attrValues (
lib.attrsets.filterAttrs (
name: value: (lib.attrsets.attrByPath ["config" "modules" "wirenix" "peerName"] null value) == peerName
) nixosConfigurations));
in
lib.mkIf (config.modules.wirenix.enable)
configurer (parser acl) config.modules.wirenix.peerName;
}

@ -1,32 +1,43 @@
{lib, ...}: intermediateConfig: peerName: {lib, ...}@inputs: keyProviders: intermediateConfig: peerName:
with lib.trivial; with lib.trivial;
with lib.attrsets; with lib.attrsets;
with lib.lists; with lib.lists;
with lib; with lib;
with builtins;
with import ../lib.nix;
let let
thisPeer = intermediateConfig.peers."${peerName}"; thisPeer = intermediateConfig.peers."${peerName}";
# these aren't really important, I just wanted to reverse the argument order # these aren't really important, I just wanted to reverse the argument order
forEachAttr' = flip mapAttrs'; forEachAttr' = flip mapAttrs';
forEachAttrToList = flip mapAttrsToList; forEachAttrToList = flip mapAttrsToList;
mergeIf = attr: key: if builtins.hasAttr key attr then {"${key}" = attr."${key}";} else {}; keyProvidersInit = map (x: x inputs intermediateConfig peerName) keyProviders;
getPeerPubKey = otherPeerName: findFirst (x: x != null) (throw "Wirenix: Could not find public key for " + otherPeerName)
(map (provider: provider.getPeerPubKey otherPeerName) keyProvidersInit);
getPrivKeyFile = getPrivKeyFile (x: x != null) (throw "Wirenix: Could not find private key file for " + peerName)
(map (provider: provider.getPrivKeyFile) keyProvidersInit);
getPubKey = findFirst (x: x != null) (throw "Wirenix: Could not find public key for " + peerName)
(map (provider: provider.getPubKey) keyProvidersInit);
getSubnetPSKFile = subnetName: findFirst (x: x != null) (null)
(map (provider: provider.getSubnetPSKFile subnetName) keyProvidersInit);
in in
{ {
networking.wireguard = { networking.wireguard = {
interfaces = forEachAttr' thisPeer.subnetConnections (name: subnetConnection: { name = "wg-${name}"; interfaces = forEachAttr' thisPeer.subnetConnections (subnetName: subnetConnection: { name = "wn-${subnetName}";
value = { value = {
ips = subnetConnection.ipAddresses; ips = subnetConnection.ipAddresses;
listenPort = subnetConnection.listenPort; listenPort = subnetConnection.listenPort;
privateKeyFile = thisPeer.privateKeyFile; privateKeyFile = getPrivKeyFile;
peers = forEachAttrToList subnetConnection.peerConnections (peerName: peerConnection: peers = forEachAttrToList subnetConnection.peerConnections (otherPeerName: peerConnection:
{ {
name = peerName; name = otherPeerName;
publicKey = peerConnection.peer.publicKey; publicKey = getPeerPubKey otherPeerName;
presharedKeyFile = getSubnetPSKFile subnetName;
allowedIPs = peerConnection.ipAddresses; allowedIPs = peerConnection.ipAddresses;
endpoint = "${peerConnection.endpoint.ip}:${builtins.toString peerConnection.endpoint.port}"; endpoint = "${peerConnection.endpoint.ip}:${builtins.toString peerConnection.endpoint.port}";
} // }
(mergeIf peerConnection.endpoint "persistentKeepalive") // // (mergeIf peerConnection.endpoint "persistentKeepalive")
(mergeIf peerConnection.endpoint "dynamicEndpointRefreshSeconds") // // (mergeIf peerConnection.endpoint "dynamicEndpointRefreshSeconds")
(mergeIf peerConnection.endpoint "dynamicEndpointRefreshRestartSeconds") // (mergeIf peerConnection.endpoint "dynamicEndpointRefreshRestartSeconds")
); );
};} };}
); );

@ -0,0 +1,10 @@
{lib, ...}: intermediateConfig:
with import ../lib.nix;
with lib.attrsets;
with builtins;
{
config = {};
getPeerPubKey = peerName: attrByPath [peerName "publicKey"] null intermediateConfig.peers;
getPeerPrivKeyFile = peerName: attrByPath [peerName "privateKeyFile"] null intermediateConfig.peers;
getSubnetPSK = subnetName: attrByPath [subnetName "presharedKeyFile"] null intermediateConfig.subnets;
}

@ -0,0 +1,33 @@
{config, nixosConfigurations, lib, ...}: intermediateConfig: peerName:
with (import ../lib.nix);
with lib.attrsets;
with builtins;
let secretsDir = peerName: (nixosConfigForPeer nixosConfigurations peerName).config.modules.wirenix.secrestsDir; in
{
config = {
age.generators.wireguard-priv = {pkgs, file, ...}: ''
priv=$(${pkgs.wireguard-tools}/bin/wg genkey)
${pkgs.wireguard-tools}/bin/wg pubkey <<< "$priv" > ${lib.escapeShellArg (lib.removeSuffix ".age" file + ".pub")}
echo "$priv"
'';
age.generators.wireguard-psk = {pkgs, file, ...}: ''
psk=$(${pkgs.wireguard-tools}/bin/wg genpsk)
echo "$psk"
'';
age.secrets = {
age.secrets = {
"wirenix-peer-${peerName}" = {
rekeyFile = config.modules.wirenix.secretsDir + /wirenix- + peerName + ".age";
generator.script = "wireguard-priv";
};
} // mapAttrs' (name: value: nameValuePair ("wirenix-subnet-${name}") {
rekeyFile = config.modules.wirenix.subnetSecretsDir + /wirenix-subnet- + name + ".age";
generator.script = "wireguard-psk";
}) intermediateConfig.peers."${peerName}".subnetConnections;
};
getPeerPubKey = otherPeerName: lib.removeSuffix ".age" ((secretsDir otherPeerName).config.secrets."wirenix-peer-${peerName}".path) + ".pub";
getPrivKeyFile = config.age.secrets."wirenix-peer-${peerName}".path;
getPubKey = lib.removeSuffix ".age" (config.age.secrets."wirenix-peer-${peerName}".path) + ".pub";
getSubnetPSKFile = subnetName: config.age.secrets."wirenix-subnet-${subnetName}".path;
}

@ -12,7 +12,12 @@ rec {
auto = static; # TODO: make smart auto = static; # TODO: make smart
static = import ./configurers/static.nix; static = import ./configurers/static.nix;
networkd = import ./configurers/networkd.nix; networkd = import ./configurers/networkd.nix;
networkmanager = import ./configurers/networkmanager.nix; network-manager = import ./configurers/networkmanager.nix;
};
/** Builtin key providers */
defaultKeyProviders = {
acl = import ./key-providers/acl.nix;
agenix-rekey = import ./key-providers/agenix-rekey.nix;
}; };
/** listOfSetsToSetByKey :: string -> list -> attrSet /** listOfSetsToSetByKey :: string -> list -> attrSet
* Example: * Example:
@ -87,4 +92,11 @@ rec {
); );
in in
mapAttrs (name: value: recurse "" value) intermediateConfig; mapAttrs (name: value: recurse "" value) intermediateConfig;
nixosConfigForPeer = nixosConfigurations: peerName: builtins.head (builtins.attrValues (
lib.attrsets.filterAttrs (
name: value: (lib.attrsets.attrByPath ["config" "modules" "wirenix" "peerName"] null value) == peerName
) nixosConfigurations));
mergeIf = attr: key: if builtins.hasAttr key attr then {"${key}" = attr."${key}";} else {};
} }

@ -8,25 +8,24 @@ let
/** parsePeer :: acl_peer -> ic_peer */ /** parsePeer :: acl_peer -> ic_peer */
parsePeer = acl_peer: { parsePeer = acl_peer: {
subnetConnections = listOfSetsToSetByKey "name" (pipeMap [subnetFromName (getSubnetConnectionAndName acl_peer)] (attrNames acl_peer.subnets)); subnetConnections = listOfSetsToSetByKey "name" (pipeMap [subnetFromName (getSubnetConnectionAndName acl_peer)] (attrNames acl_peer.subnets));
publicKey = acl_peer.publicKey; }
privateKeyFile = acl_peer.privateKeyFile; // mergeIf acl_peer "extraArgs"
} // // mergeIf acl_peer "publicKey"
(if acl_peer ? extraArgs then {extraArgs = acl_peer.extraArgs;} else {}) // // mergeIf acl_peer "privateKeyFile"
{ // (if acl_peer ? groups then {groups = map groupFromName acl_peer.groups;} else {groups = {};});
publicKey = acl_peer.publicKey;
privateKeyFile = acl_peer.privateKeyFile;
} //
(if acl_peer ? groups then {groups = map groupFromName acl_peer.groups;} else {groups = {};});
/** parseGroup :: acl_group -> ic_group */ /** parseGroup :: acl_group -> ic_group */
parseGroup = acl_group: { parseGroup = acl_group: {
peers = mapListOfSetsToSetByKey "name" parsePeer (selectPeers [{type="group"; rule="is"; value="${acl_group.name}";}]); peers = mapListOfSetsToSetByKey "name" parsePeer (selectPeers [{type="group"; rule="is"; value="${acl_group.name}";}]);
} // (if acl_group ? extraArgs then {extraArgs = acl_group.extraArgs;} else {}); }
// mergeIf acl_group "extraArgs";
/** parseSubnet :: acl_subnet -> ic_subnet */ /** parseSubnet :: acl_subnet -> ic_subnet */
parseSubnet = acl_subnet: { parseSubnet = acl_subnet: {
peers = mapListOfSetsToSetByKey "name" parsePeer (selectPeers [{type="subnet"; rule="is"; value="${acl_subnet.name}";}]); peers = mapListOfSetsToSetByKey "name" parsePeer (selectPeers [{type="subnet"; rule="is"; value="${acl_subnet.name}";}]);
} // (if acl_subnet ? extraArgs then {extraArgs = acl_subnet.extraArgs;} else {}); }
// mergeIf acl_subnet "extraArgs"
// mergeIf acl_subnet "presharedKeyFile";
/** getSubnetConnection :: acl_peer -> acl_subnet -> (subnetConnection // {name}) */ /** getSubnetConnection :: acl_peer -> acl_subnet -> (subnetConnection // {name}) */
getSubnetConnectionAndName = acl_peer: acl_subnet: { getSubnetConnectionAndName = acl_peer: acl_subnet: {
@ -35,8 +34,9 @@ let
ipAddresses = getIpAddresses acl_subnet acl_peer; ipAddresses = getIpAddresses acl_subnet acl_peer;
listenPort = acl_peer.subnets."${acl_subnet.name}".listenPort; listenPort = acl_peer.subnets."${acl_subnet.name}".listenPort;
peerConnections = getPeerConnections acl_peer acl_subnet; peerConnections = getPeerConnections acl_peer acl_subnet;
} // (if acl_peer.subnets."${acl_subnet.name}" ? extraArgs then {extraArgs = acl_peer.subnets."${acl_subnet.name}".extraArgs;} else {}); }
// mergeIf (getAttr acl_subnet.name acl_peer.subnets) "extraArgs";
/** getIpAddresses :: acl_peer -> acl_subnet -> [str] */ /** getIpAddresses :: acl_peer -> acl_subnet -> [str] */
getIpAddresses = acl_subnet: acl_peer: getIpAddresses = acl_subnet: acl_peer:
if (acl_peer.subnets."${acl_subnet.name}" ? ipAddresses) then ( if (acl_peer.subnets."${acl_subnet.name}" ? ipAddresses) then (
@ -133,4 +133,5 @@ in
peers = mapListOfSetsToSetByKey "name" parsePeer v1_acl.peers; peers = mapListOfSetsToSetByKey "name" parsePeer v1_acl.peers;
subnets = mapListOfSetsToSetByKey "name" parseSubnet v1_acl.subnets; subnets = mapListOfSetsToSetByKey "name" parseSubnet v1_acl.subnets;
groups = mapListOfSetsToSetByKey "name" parseGroup v1_acl.groups; groups = mapListOfSetsToSetByKey "name" parseGroup v1_acl.groups;
} // (if v1_acl ? extraArgs then {extraArgs = v1_acl.extraArgs;} else {}) }
// mergeIf v1_acl "extraArgs"

@ -22,27 +22,33 @@ with import ./lib.nix;
''; '';
}; };
configurer = mkOption { configurer = mkOption {
default = "auto"; default = defaultConfigurers.static;
type = types.str; defaultText = literalExpression "wirenix.lib.defaultConfigurers.static";
type = with types; functionTo (functionTo (functionTo (functionTo attrset)));
description = mdDoc '' description = mdDoc ''
Configurer to use. Builtin values can be "auto", "networkmanager", or "networkd". Configurer to use. Builtin values can be
See the `additionalConfigurers` for adding more options. `wirenix.lib.defaultConfigurers.static`
`wirenix.lib.defaultConfigurers.networkd` or
`wirenix.lib.defaultConfigurers.network-manager`
Or you can put your own configurer here.
''; '';
}; };
additionalConfigurers = mkOption { keyProviders = mkOption {
default = "auto"; default = [defaultKeyProviders.acl];
type = with types; attrsOf (functionTo attrset); type = with types; listOf (functionTo attrset);
defaultText = literalExpression "[ wirenix.lib.defaultKeyProviders.acl ]";
description = mdDoc '' description = mdDoc ''
Additional configurers to load, with their names being used to select from the List of key providers. Key providers will be queried in order.
configurer option. Builtin providers are `wirenix.lib.defaultKeyProviders.acl`
and `wirenix.lib.defaultKeyProviders.agenix-rekey`. The latter
requires the agenix-rekey flake.
''; '';
}; };
additionalParsers = mkOption { additionalParsers = mkOption {
default = "auto";
type = with types; attrsOf (functionTo attrset); type = with types; attrsOf (functionTo attrset);
description = mdDoc '' description = mdDoc ''
Additional parsers to load, with their names being used to compare to the acl's Additional parsers to load, with their names being used to compare to the acl's
"version" feild. "version" field.
''; '';
}; };
aclConfig = mkOption { aclConfig = mkOption {
@ -52,6 +58,19 @@ with import ./lib.nix;
Shared configuration file that describes all clients Shared configuration file that describes all clients
''; '';
}; };
secretsDir = mkOption {
type = types.path;
description = mdDoc ''
If using a secrets manager, where you have wireguard secrets stored for the client.
'';
};
subnetSecretsDir = mkOption {
type = types.path;
description = mdDoc ''
If using a secrets manager, where you have wireguard secrets stored for subnets.
Needs to be the same on all clients.
'';
};
}; };
}; };
@ -59,12 +78,12 @@ with import ./lib.nix;
config = config =
let let
configurers = defaultConfigurers // config.modules.wirenix.additionalConfigurers;
parsers = defaultParsers // config.modules.wirenix.additionalParsers; parsers = defaultParsers // config.modules.wirenix.additionalParsers;
acl = config.modules.wirenix.aclConfig; acl = config.modules.wirenix.aclConfig;
parser = parsers."${acl.version}" inputs; parser = parsers."${acl.version}" inputs;
configurer = configurers."${config.modules.wirenix.configurer}" inputs; configurer = config.modules.wirenix.configurer inputs;
keyProviders = config.modules.wirenix.keyProviders;
in in
lib.mkIf (config.modules.wirenix.enable) lib.mkIf (config.modules.wirenix.enable)
configurer (parser acl) config.modules.wirenix.peerName; configurer (parser acl) keyProviders config.modules.wirenix.peerName;
} }
Loading…
Cancel
Save