From ecefdd099a686e90179b3ea5528a646334d64cda Mon Sep 17 00:00:00 2001 From: Matthew Salerno Date: Sat, 12 Aug 2023 21:52:03 -0400 Subject: [PATCH] Bumper car bugfixing until it actually works as a flake --- agenix-rekey-compat.nix | 36 ------------- configurers/static.nix | 2 +- key-providers/acl.nix | 1 - key-providers/agenix-rekey.nix | 42 +++++++-------- lib.nix | 4 +- wire.nix | 98 ++++++++++++++++++++-------------- 6 files changed, 81 insertions(+), 102 deletions(-) delete mode 100644 agenix-rekey-compat.nix diff --git a/agenix-rekey-compat.nix b/agenix-rekey-compat.nix deleted file mode 100644 index 787de05..0000000 --- a/agenix-rekey-compat.nix +++ /dev/null @@ -1,36 +0,0 @@ -{ 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; -} \ No newline at end of file diff --git a/configurers/static.nix b/configurers/static.nix index 5fe52f9..17ff351 100644 --- a/configurers/static.nix +++ b/configurers/static.nix @@ -34,4 +34,4 @@ with getKeyProviderFuncs keyProviders inputs intermediateConfig peerName; };} ); }; -} \ No newline at end of file +} // getProviderConfig \ No newline at end of file diff --git a/key-providers/acl.nix b/key-providers/acl.nix index b75d399..da96f0c 100644 --- a/key-providers/acl.nix +++ b/key-providers/acl.nix @@ -3,7 +3,6 @@ with import ../lib.nix; with lib.attrsets; with builtins; { - config = {}; getPeerPubKey = otherPeerName: attrByPath [otherPeerName "publicKey"] null intermediateConfig.peers; getPrivKeyFile = attrByPath [peerName "privateKeyFile"] null intermediateConfig.peers; getSubnetPSKFile = subnetName: attrByPath [subnetName "presharedKeyFile"] null intermediateConfig.subnets; diff --git a/key-providers/agenix-rekey.nix b/key-providers/agenix-rekey.nix index 6435bd0..ea37185 100644 --- a/key-providers/agenix-rekey.nix +++ b/key-providers/agenix-rekey.nix @@ -1,32 +1,28 @@ -{config, nixosConfigurations, lib, ...}: intermediateConfig: peerName: +{config, 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 = { + config.age = { + secrets = { "wirenix-peer-${peerName}" = { - rekeyFile = config.modules.wirenix.secretsDir + /wirenix- + peerName + ".age"; - generator.script = "wireguard-priv"; + rekeyFile = config.wirenix.secretsDir + /wirenix-peer- + peerName + ".age"; + generator.script = {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" + ''; }; - } // 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"; + } // + mapAttrs' (name: value: nameValuePair ("wirenix-subnet-${name}") { + rekeyFile = config.wirenix.secretsDir + /wirenix-subnet- + name + ".age"; + generator.script = {pkgs, ...}: '' + psk=$(${pkgs.wireguard-tools}/bin/wg genpsk) + echo "$psk" + ''; + }) intermediateConfig.peers."${peerName}".subnetConnections; + }; + getPeerPubKey = otherPeerName: builtins.readFile (config.wirenix.secretsDir + /wirenix-peer-${peerName}.pub); getPrivKeyFile = config.age.secrets."wirenix-peer-${peerName}".path; getSubnetPSKFile = subnetName: config.age.secrets."wirenix-subnet-${subnetName}".path; } \ No newline at end of file diff --git a/lib.nix b/lib.nix index 5d82d27..c972549 100644 --- a/lib.nix +++ b/lib.nix @@ -19,8 +19,7 @@ rec { v1 = import ./parsers/v1.nix; }; /** Builtin configurers */ - defaultConfigurers = rec { - auto = static; # TODO: make smart + defaultConfigurers = { static = import ./configurers/static.nix; networkd = import ./configurers/networkd.nix; network-manager = import ./configurers/networkmanager.nix; @@ -120,6 +119,7 @@ rec { (map (provider: provider.getPrivKeyFile) keyProviders); getSubnetPSKFile = subnetName: findFirst (x: x != null) (null) (map (provider: provider.getSubnetPSKFile subnetName) keyProviders); + getProviderConfig = foldl' (x: y: x // y) {} (map (provider: if provider ? config then provider.config else {}) keyProviders); }; mergeIf = attr: key: if builtins.hasAttr key attr then {"${key}" = attr."${key}";} else {}; diff --git a/wire.nix b/wire.nix index 859d4d2..2885586 100644 --- a/wire.nix +++ b/wire.nix @@ -1,16 +1,32 @@ { config, lib, ... }@inputs: with lib; with import ./lib.nix; +with builtins; +let + cfg = config.wirenix; + parsers = defaultParsers // cfg.additionalParsers; + configurers = defaultConfigurers // cfg.additionalConfigurers; + availableKeyProviders = defaultKeyProviders // cfg.additionalKeyProviders; + acl = cfg.aclConfig; + parser = parsers."${acl.version}" inputs; + configurer = (getAttr cfg.configurer configurers) inputs; #config.wirenix.configurer inputs; + keyProviders = map (providerName: getAttr providerName availableKeyProviders) cfg.keyProviders; # config.wirenix.keyProviders; + mkMergeTopLevel = names: attrs: attrsets.getAttrs names ( + mapAttrs (k: v: mkMerge v) (attrsets.foldAttrs (n: a: [n] ++ a) [] attrs) + ); + /** + * We can merge if we want to + * We can leave your friends behind + * 'Cause your friends don't merge and if they don't merge + * Well they're, no friends of mine. + */ + safetyMerge = possibleTopLevelKeys: attrs: + (mkMergeTopLevel possibleTopLevelKeys ((lists.singleton (attrsets.genAttrs possibleTopLevelKeys (name: {})))++attrs)); +in { options = { wirenix = { - enable = mkOption { - default = true; - type = with lib.types; bool; - description = '' - Wirenix - ''; - }; + enable = mkEnableOption "wirenix"; peerName = mkOption { default = config.networking.hostName; defaultText = literalExpression "hostName"; @@ -22,21 +38,18 @@ with import ./lib.nix; ''; }; configurer = mkOption { - default = defaultConfigurers.static; - defaultText = literalExpression "wirenix.lib.defaultConfigurers.static"; - type = with types; functionTo (functionTo (functionTo (functionTo attrset))); + default = "static"; + type = types.str; description = mdDoc '' Configurer to use. Builtin values can be - `wirenix.lib.defaultConfigurers.static` - `wirenix.lib.defaultConfigurers.networkd` or - `wirenix.lib.defaultConfigurers.network-manager` + "static" "networkd" or "network-manager" Or you can put your own configurer here. ''; }; keyProviders = mkOption { - default = [defaultKeyProviders.acl]; - type = with types; listOf (functionTo attrset); - defaultText = literalExpression "[ wirenix.lib.defaultKeyProviders.acl ]"; + default = ["acl"]; + type = with types; listOf str; + defaultText = literalExpression "[ "acl" ]"; description = mdDoc '' List of key providers. Key providers will be queried in order. Builtin providers are `wirenix.lib.defaultKeyProviders.acl` @@ -44,46 +57,53 @@ with import ./lib.nix; requires the agenix-rekey flake. ''; }; + additionalKeyProviders = mkOption { + default = {}; + type = with types; attrsOf (functionTo attrs); + description = mdDoc '' + Additional key providers to load, with their names being used to select them in the + `keyProviders` option + ''; + }; additionalParsers = mkOption { - type = with types; attrsOf (functionTo attrset); + default = {}; + type = with types; attrsOf (functionTo attrs); description = mdDoc '' Additional parsers to load, with their names being used to compare to the acl's "version" field. ''; }; - aclConfig = mkOption { + additionalConfigurers = mkOption { default = {}; - type = types.attrset; + type = with types; attrsOf (functionTo attrs); + description = mdDoc '' + Additional configurers to load, with their names being used to select them in the + `configurer` option. + ''; + }; + aclConfig = mkOption { + type = types.attrs; description = '' Shared configuration file that describes all clients ''; }; secretsDir = mkOption { - type = types.path; + default = null; + type = with types; nullOr 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. + If using a secrets manager, where you have wirenix secrets stored. Must be + the same on all peers that need to connect to eachother ''; }; }; }; # --------------------------------------------------------------- # - - config = - let - parsers = defaultParsers // config.modules.wirenix.additionalParsers; - acl = config.modules.wirenix.aclConfig; - parser = parsers."${acl.version}" inputs; - configurer = config.modules.wirenix.configurer inputs; - keyProviders = config.modules.wirenix.keyProviders; - in - lib.mkIf (config.modules.wirenix.enable) - configurer (parser acl) keyProviders config.modules.wirenix.peerName; + # Due to merge weirdness, I have to define what configuration keys + # we're touching upfront, and make sure they exist + config = (safetyMerge ["networking" "sops" "age" "systemd" "services" "environment"] + [ + (configurer keyProviders (parser acl) cfg.peerName) + ] + ); } \ No newline at end of file