From 0d4e1f870b0356eca2518afda543e9210aa84a05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Thalheim?= Date: Tue, 9 Apr 2024 18:04:26 +0200 Subject: [PATCH] factstore: secret backends now can return the path to a secret dynamically try to move path function out --- checks/flake-module.nix | 6 +- docs/flake-module/default.nix | 5 +- nixosModules/clanCore/facts/compat.nix | 92 ++++++++----------- nixosModules/clanCore/facts/default.nix | 19 ++-- .../clanCore/facts/secret/password-store.nix | 3 +- nixosModules/clanCore/facts/secret/sops.nix | 6 +- nixosModules/clanCore/facts/secret/vm.nix | 2 +- nixosModules/clanCore/outputs.nix | 9 +- 8 files changed, 75 insertions(+), 67 deletions(-) diff --git a/checks/flake-module.nix b/checks/flake-module.nix index 00119bef..7366db4a 100644 --- a/checks/flake-module.nix +++ b/checks/flake-module.nix @@ -20,7 +20,11 @@ renderClanOptions = let docs = pkgs.nixosOptionsDoc { - options = (pkgs.nixos { imports = [ self.nixosModules.clanCore ]; }).options; + options = + (pkgs.nixos { + imports = [ self.nixosModules.clanCore ]; + clanCore.clanDir = ./.; + }).options; warningsAreErrors = false; }; in diff --git a/docs/flake-module/default.nix b/docs/flake-module/default.nix index 65ead4a2..4b8c5168 100644 --- a/docs/flake-module/default.nix +++ b/docs/flake-module/default.nix @@ -16,7 +16,10 @@ { nixpkgs.hostPlatform = "x86_64-linux"; } ]; - clanCoreNixosModules = [ self.nixosModules.clanCore ] ++ allNixosModules; + clanCoreNixosModules = [ + self.nixosModules.clanCore + { clanCore.clanDir = ./.; } + ] ++ allNixosModules; # TODO: optimally we would not have to evaluate all nixos modules for every page # but some of our module options secretly depend on nixos modules. diff --git a/nixosModules/clanCore/facts/compat.nix b/nixosModules/clanCore/facts/compat.nix index 95f06654..cd7ceb22 100644 --- a/nixosModules/clanCore/facts/compat.nix +++ b/nixosModules/clanCore/facts/compat.nix @@ -16,17 +16,10 @@ "secretStore" ] ) - (lib.mkRenamedOptionModule - [ - "clanCore" - "secretsDirectory" - ] - [ - "clanCore" - "facts" - "secretDirectory" - ] - ) + (lib.mkRemovedOptionModule [ + "clanCore" + "secretsDirectory" + ] "clancore.secretsDirectory was removed. Use clanCore.facts.secretPathFunction instead") (lib.mkRenamedOptionModule [ "clanCore" @@ -86,50 +79,43 @@ } ); }; - secrets = - let - config' = config; - in - lib.mkOption { - default = { }; - type = lib.types.attrsOf ( - lib.types.submodule ( - { config, name, ... }: + secrets = lib.mkOption { + default = { }; + type = lib.types.attrsOf ( + lib.types.submodule (secret: { + options = { - options = - { - name = lib.mkOption { - type = lib.types.str; - description = '' - name of the secret - ''; - default = name; - }; - path = lib.mkOption { - type = lib.types.str; - description = '' - path to a secret which is generated by the generator - ''; - default = "${config'.clanCore.facts.secretDirectory}/${config.name}"; - defaultText = lib.literalExpression "\${config'.clanCore.facts.secretDirectory}/\${config.name}"; - }; - } - // lib.optionalAttrs (config'.clanCore.facts.secretStore == "sops") { - groups = lib.mkOption { - type = lib.types.listOf lib.types.str; - default = config'.clanCore.sops.defaultGroups; - description = '' - Groups to decrypt the secret for. By default we always use the user's key. - ''; - }; - }; + name = lib.mkOption { + type = lib.types.str; + description = '' + name of the secret + ''; + default = secret.name; + }; + path = lib.mkOption { + type = lib.types.path; + description = '' + path to a secret which is generated by the generator + ''; + default = config.clanCore.facts.secretPathFunction secret; + defaultText = lib.literalExpression "config.clanCore.facts.secretPathFunction secret"; + }; } - ) - ); - description = '' - path where the secret is located in the filesystem - ''; - }; + // lib.optionalAttrs (config.clanCore.facts.secretStore == "sops") { + groups = lib.mkOption { + type = lib.types.listOf lib.types.str; + default = config.clanCore.sops.defaultGroups; + description = '' + Groups to decrypt the secret for. By default we always use the user's key. + ''; + }; + }; + }) + ); + description = '' + path where the secret is located in the filesystem + ''; + }; facts = lib.mkOption { default = { }; type = lib.types.attrsOf ( diff --git a/nixosModules/clanCore/facts/default.nix b/nixosModules/clanCore/facts/default.nix index b13aacbc..53de05ed 100644 --- a/nixosModules/clanCore/facts/default.nix +++ b/nixosModules/clanCore/facts/default.nix @@ -19,6 +19,7 @@ custom can be used to define a custom secret fact store. ''; }; + secretModule = lib.mkOption { type = lib.types.str; internal = true; @@ -26,12 +27,7 @@ the python import path to the secret module ''; }; - secretDirectory = lib.mkOption { - type = lib.types.path; - description = '' - The directory where secrets are installed to. This is backend specific. - ''; - }; + secretUploadDirectory = lib.mkOption { type = lib.types.nullOr lib.types.path; default = null; @@ -40,6 +36,15 @@ ''; }; + secretPathFunction = lib.mkOption { + type = lib.types.raw; + description = '' + The function to use to generate the path for a secret. + The default function will use the path attribute of the secret. + The function will be called with the secret submodule as an argument. + ''; + }; + publicStore = lib.mkOption { type = lib.types.enum [ "in_repo" @@ -150,7 +155,7 @@ description = '' path to a secret which is generated by the generator ''; - default = "${config.clanCore.facts.secretDirectory}/${secret.config.name}"; + default = config.clanCore.facts.secretPathFunction secret; }; } // lib.optionalAttrs (config.clanCore.facts.secretModule == "clan_cli.facts.secret_modules.sops") { diff --git a/nixosModules/clanCore/facts/secret/password-store.nix b/nixosModules/clanCore/facts/secret/password-store.nix index c454f31f..2e69bb6d 100644 --- a/nixosModules/clanCore/facts/secret/password-store.nix +++ b/nixosModules/clanCore/facts/secret/password-store.nix @@ -7,8 +7,9 @@ The directory where the password store is uploaded to. ''; }; + config = lib.mkIf (config.clanCore.facts.secretStore == "password-store") { - clanCore.facts.secretDirectory = config.clan.password-store.targetDirectory; + clanCore.facts.secretPathFunction = secret: "/etc/secrets/${secret.config.name}"; clanCore.facts.secretUploadDirectory = config.clan.password-store.targetDirectory; clanCore.facts.secretModule = "clan_cli.facts.secret_modules.password_store"; }; diff --git a/nixosModules/clanCore/facts/secret/sops.nix b/nixosModules/clanCore/facts/secret/sops.nix index 3aeac7d9..86ce1ead 100644 --- a/nixosModules/clanCore/facts/secret/sops.nix +++ b/nixosModules/clanCore/facts/secret/sops.nix @@ -41,12 +41,14 @@ in description = "The default groups to for encryption use when no groups are specified."; }; }; + config = lib.mkIf (config.clanCore.facts.secretStore == "sops") { - clanCore.facts.secretDirectory = "/run/secrets"; + # Before we generate a secret we cannot know the path yet, so we need to set it to an empty string + clanCore.facts.secretPathFunction = + secret: config.sops.secrets.${secret.config.name}.path or "/no-such-path"; clanCore.facts.secretModule = "clan_cli.facts.secret_modules.sops"; clanCore.facts.secretUploadDirectory = lib.mkDefault "/var/lib/sops-nix"; sops.secrets = builtins.mapAttrs (name: _: { - name = lib.strings.removePrefix "${config.clanCore.machineName}-" name; sopsFile = config.clanCore.clanDir + "/sops/secrets/${name}/secret"; format = "binary"; }) secrets; diff --git a/nixosModules/clanCore/facts/secret/vm.nix b/nixosModules/clanCore/facts/secret/vm.nix index fc61305a..d4c5919f 100644 --- a/nixosModules/clanCore/facts/secret/vm.nix +++ b/nixosModules/clanCore/facts/secret/vm.nix @@ -1,7 +1,7 @@ { config, lib, ... }: { config = lib.mkIf (config.clanCore.facts.secretStore == "vm") { - clanCore.facts.secretDirectory = "/etc/secrets"; + clanCore.facts.secretPathFunction = secret: "/etc/secrets/${secret.config.name}"; clanCore.facts.secretUploadDirectory = "/etc/secrets"; clanCore.facts.secretModule = "clan_cli.facts.secret_modules.vm"; }; diff --git a/nixosModules/clanCore/outputs.nix b/nixosModules/clanCore/outputs.nix index 2b0d62f3..c2916552 100644 --- a/nixosModules/clanCore/outputs.nix +++ b/nixosModules/clanCore/outputs.nix @@ -65,7 +65,14 @@ # optimization for faster secret generate/upload and machines update config = { system.clan.deployment.data = { - inherit (config.clanCore) facts; + facts = { + inherit (config.clanCore.facts) + secretUploadDirectory + secretModule + publicModule + services + ; + }; inherit (config.clan.networking) targetHost buildHost; inherit (config.clan.deployment) requireExplicitUpdate; };