factstore: secret backends now can return the path to a secret dynamically

try to move path function out
This commit is contained in:
Jörg Thalheim 2024-04-09 18:04:26 +02:00 committed by Mic92
parent faaf6649c5
commit 0d4e1f870b
8 changed files with 75 additions and 67 deletions

View File

@ -20,7 +20,11 @@
renderClanOptions = renderClanOptions =
let let
docs = pkgs.nixosOptionsDoc { docs = pkgs.nixosOptionsDoc {
options = (pkgs.nixos { imports = [ self.nixosModules.clanCore ]; }).options; options =
(pkgs.nixos {
imports = [ self.nixosModules.clanCore ];
clanCore.clanDir = ./.;
}).options;
warningsAreErrors = false; warningsAreErrors = false;
}; };
in in

View File

@ -16,7 +16,10 @@
{ nixpkgs.hostPlatform = "x86_64-linux"; } { 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 # 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. # but some of our module options secretly depend on nixos modules.

View File

@ -16,17 +16,10 @@
"secretStore" "secretStore"
] ]
) )
(lib.mkRenamedOptionModule (lib.mkRemovedOptionModule [
[ "clanCore"
"clanCore" "secretsDirectory"
"secretsDirectory" ] "clancore.secretsDirectory was removed. Use clanCore.facts.secretPathFunction instead")
]
[
"clanCore"
"facts"
"secretDirectory"
]
)
(lib.mkRenamedOptionModule (lib.mkRenamedOptionModule
[ [
"clanCore" "clanCore"
@ -86,50 +79,43 @@
} }
); );
}; };
secrets = secrets = lib.mkOption {
let default = { };
config' = config; type = lib.types.attrsOf (
in lib.types.submodule (secret: {
lib.mkOption { options =
default = { };
type = lib.types.attrsOf (
lib.types.submodule (
{ config, name, ... }:
{ {
options = name = lib.mkOption {
{ type = lib.types.str;
name = lib.mkOption { description = ''
type = lib.types.str; name of the secret
description = '' '';
name of the secret default = secret.name;
''; };
default = name; path = lib.mkOption {
}; type = lib.types.path;
path = lib.mkOption { description = ''
type = lib.types.str; path to a secret which is generated by the generator
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";
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.
'';
};
};
} }
) // lib.optionalAttrs (config.clanCore.facts.secretStore == "sops") {
); groups = lib.mkOption {
description = '' type = lib.types.listOf lib.types.str;
path where the secret is located in the filesystem 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 { facts = lib.mkOption {
default = { }; default = { };
type = lib.types.attrsOf ( type = lib.types.attrsOf (

View File

@ -19,6 +19,7 @@
custom can be used to define a custom secret fact store. custom can be used to define a custom secret fact store.
''; '';
}; };
secretModule = lib.mkOption { secretModule = lib.mkOption {
type = lib.types.str; type = lib.types.str;
internal = true; internal = true;
@ -26,12 +27,7 @@
the python import path to the secret module 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 { secretUploadDirectory = lib.mkOption {
type = lib.types.nullOr lib.types.path; type = lib.types.nullOr lib.types.path;
default = null; 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 { publicStore = lib.mkOption {
type = lib.types.enum [ type = lib.types.enum [
"in_repo" "in_repo"
@ -150,7 +155,7 @@
description = '' description = ''
path to a secret which is generated by the generator 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") { // lib.optionalAttrs (config.clanCore.facts.secretModule == "clan_cli.facts.secret_modules.sops") {

View File

@ -7,8 +7,9 @@
The directory where the password store is uploaded to. The directory where the password store is uploaded to.
''; '';
}; };
config = lib.mkIf (config.clanCore.facts.secretStore == "password-store") { 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.secretUploadDirectory = config.clan.password-store.targetDirectory;
clanCore.facts.secretModule = "clan_cli.facts.secret_modules.password_store"; clanCore.facts.secretModule = "clan_cli.facts.secret_modules.password_store";
}; };

View File

@ -41,12 +41,14 @@ in
description = "The default groups to for encryption use when no groups are specified."; description = "The default groups to for encryption use when no groups are specified.";
}; };
}; };
config = lib.mkIf (config.clanCore.facts.secretStore == "sops") { 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.secretModule = "clan_cli.facts.secret_modules.sops";
clanCore.facts.secretUploadDirectory = lib.mkDefault "/var/lib/sops-nix"; clanCore.facts.secretUploadDirectory = lib.mkDefault "/var/lib/sops-nix";
sops.secrets = builtins.mapAttrs (name: _: { sops.secrets = builtins.mapAttrs (name: _: {
name = lib.strings.removePrefix "${config.clanCore.machineName}-" name;
sopsFile = config.clanCore.clanDir + "/sops/secrets/${name}/secret"; sopsFile = config.clanCore.clanDir + "/sops/secrets/${name}/secret";
format = "binary"; format = "binary";
}) secrets; }) secrets;

View File

@ -1,7 +1,7 @@
{ config, lib, ... }: { config, lib, ... }:
{ {
config = lib.mkIf (config.clanCore.facts.secretStore == "vm") { 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.secretUploadDirectory = "/etc/secrets";
clanCore.facts.secretModule = "clan_cli.facts.secret_modules.vm"; clanCore.facts.secretModule = "clan_cli.facts.secret_modules.vm";
}; };

View File

@ -65,7 +65,14 @@
# optimization for faster secret generate/upload and machines update # optimization for faster secret generate/upload and machines update
config = { config = {
system.clan.deployment.data = { 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.networking) targetHost buildHost;
inherit (config.clan.deployment) requireExplicitUpdate; inherit (config.clan.deployment) requireExplicitUpdate;
}; };