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 =
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

View File

@ -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.

View File

@ -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 (

View File

@ -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") {

View File

@ -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";
};

View File

@ -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;

View File

@ -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";
};

View File

@ -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;
};