refactor clanCore.secrets -> clanCore.facts

This commit is contained in:
lassulus
2024-03-25 15:55:25 +01:00
committed by Jörg Thalheim
parent d344f512c7
commit 2893025f3f
19 changed files with 342 additions and 165 deletions

View File

@@ -1,6 +1,7 @@
{
imports = [
./backups.nix
./facts
./manual.nix
./imports.nix
./metadata.nix
@@ -10,7 +11,6 @@
./outputs.nix
./packages.nix
./schema.nix
./secrets
./vm.nix
./wayland-proxy-virtwl.nix
./zerotier

View File

@@ -1,47 +1,44 @@
{ config, lib, ... }:
{
config,
lib,
pkgs,
...
}:
{
options.clanCore.secretStore = lib.mkOption {
type = lib.types.enum [
"sops"
"password-store"
"vm"
"custom"
];
default = "sops";
description = ''
method to store secrets
custom can be used to define a custom secret store.
'';
};
options.clanCore.secretsDirectory = lib.mkOption {
type = lib.types.path;
description = ''
The directory where secrets are installed to. This is backend specific.
'';
};
options.clanCore.secretsUploadDirectory = lib.mkOption {
type = lib.types.nullOr lib.types.path;
default = null;
description = ''
The directory where secrets are uploaded into, This is backend specific.
'';
};
options.clanCore.secretsPrefix = lib.mkOption {
type = lib.types.str;
default = "";
description = ''
Prefix for secrets. This is backend specific.
'';
};
imports = [
(lib.mkRemovedOptionModule [
"clanCore"
"secretsPrefix"
] "secretsPrefix was only used by the sops module and the code is now integrated in there")
(lib.mkRenamedOptionModule
[
"clanCore"
"secretStore"
]
[
"clanCore"
"facts"
"secretStore"
]
)
(lib.mkRenamedOptionModule
[
"clanCore"
"secretsDirectory"
]
[
"clanCore"
"facts"
"secretDirectory"
]
)
(lib.mkRenamedOptionModule
[
"clanCore"
"secretsUploadDirectory"
]
[
"clanCore"
"facts"
"secretUploadDirectory"
]
)
];
options.clanCore.secrets = lib.mkOption {
default = { };
type = lib.types.attrsOf (
@@ -56,7 +53,7 @@
};
generator = lib.mkOption {
type = lib.types.submodule (
{ config, ... }:
{ ... }:
{
options = {
path = lib.mkOption {
@@ -84,28 +81,6 @@
The script is expected to generate all secrets and facts defined in the module.
'';
};
finalScript = lib.mkOption {
type = lib.types.str;
readOnly = true;
internal = true;
default = ''
set -eu -o pipefail
export PATH="${lib.makeBinPath config.path}:${pkgs.coreutils}/bin"
# prepare sandbox user
mkdir -p /etc
cp ${
pkgs.runCommand "fake-etc" { } ''
export PATH="${pkgs.coreutils}/bin"
mkdir -p $out
cp /etc/* $out/
''
}/* /etc/
${config.script}
'';
};
};
}
);
@@ -134,11 +109,11 @@
description = ''
path to a secret which is generated by the generator
'';
default = "${config'.clanCore.secretsDirectory}/${config'.clanCore.secretsPrefix}${config.name}";
defaultText = lib.literalExpression "\${config'.clanCore.secretsDirectory}/\${config'.clanCore.secretsPrefix}\${config.name}";
default = "${config'.clanCore.facts.secretDirectory}/${config.name}";
defaultText = lib.literalExpression "\${config'.clanCore.facts.secretDirectory}/\${config.name}";
};
}
// lib.optionalAttrs (config'.clanCore.secretStore == "sops") {
// lib.optionalAttrs (config'.clanCore.facts.secretStore == "sops") {
groups = lib.mkOption {
type = lib.types.listOf lib.types.str;
default = config'.clanCore.sops.defaultGroups;
@@ -190,9 +165,16 @@
})
);
};
imports = [
./sops.nix
./password-store.nix
./vm.nix
];
config = lib.mkIf (config.clanCore.secrets != { }) {
clanCore.facts.services = lib.mapAttrs' (
name: service:
lib.warn "clanCore.secrets.${name} is deprecated, use clanCore.facts.services.${name} instead" (
lib.nameValuePair name ({
secret = service.secrets;
public = service.facts;
generator = service.generator;
})
)
) config.clanCore.secrets;
};
}

View File

@@ -0,0 +1,217 @@
{
config,
lib,
pkgs,
...
}:
{
options.clanCore.facts = {
secretStore = lib.mkOption {
type = lib.types.enum [
"sops"
"password-store"
"vm"
"custom"
];
default = "sops";
description = ''
method to store secret facts
custom can be used to define a custom secret fact store.
'';
};
secretModule = lib.mkOption {
type = lib.types.str;
internal = true;
description = ''
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;
description = ''
The directory where secrets are uploaded into, This is backend specific.
'';
};
publicStore = lib.mkOption {
type = lib.types.enum [
"in_repo"
"vm"
"custom"
];
default = "in_repo";
description = ''
method to store public facts.
custom can be used to define a custom public fact store.
'';
};
publicModule = lib.mkOption {
type = lib.types.str;
internal = true;
description = ''
the python import path to the public module
'';
};
publicDirectory = lib.mkOption {
type = lib.types.nullOr lib.types.path;
default = null;
};
services = lib.mkOption {
default = { };
type = lib.types.attrsOf (
lib.types.submodule (service: {
options = {
name = lib.mkOption {
type = lib.types.str;
default = service.config._module.args.name;
description = ''
Namespace of the service
'';
};
generator = lib.mkOption {
type = lib.types.submodule (
{ config, ... }:
{
options = {
path = lib.mkOption {
type = lib.types.listOf (lib.types.either lib.types.path lib.types.package);
default = [ ];
description = ''
Extra paths to add to the PATH environment variable when running the generator.
'';
};
prompt = lib.mkOption {
type = lib.types.nullOr lib.types.str;
default = null;
description = ''
prompt text to ask for a value.
This value will be passed to the script as the environment variable $prompt_value.
'';
};
script = lib.mkOption {
type = lib.types.str;
description = ''
Script to generate the secret.
The script will be called with the following variables:
- facts: path to a directory where facts can be stored
- secrets: path to a directory where secrets can be stored
The script is expected to generate all secrets and facts defined in the module.
'';
};
finalScript = lib.mkOption {
type = lib.types.str;
readOnly = true;
internal = true;
default = ''
set -eu -o pipefail
export PATH="${lib.makeBinPath config.path}:${pkgs.coreutils}/bin"
# prepare sandbox user
mkdir -p /etc
cp ${
pkgs.runCommand "fake-etc" { } ''
export PATH="${pkgs.coreutils}/bin"
mkdir -p $out
cp /etc/* $out/
''
}/* /etc/
${config.script}
'';
};
};
}
);
};
secret = lib.mkOption {
default = { };
type = lib.types.attrsOf (
lib.types.submodule (secret: {
options =
{
name = lib.mkOption {
type = lib.types.str;
description = ''
name of the secret
'';
default = secret.config._module.args.name;
};
path = lib.mkOption {
type = lib.types.str;
description = ''
path to a secret which is generated by the generator
'';
default = "${config.clanCore.facts.secretDirectory}/${secret.config.name}";
};
}
// lib.optionalAttrs (config.clanCore.facts.secretModule == "clan_cli.facts.secret_modules.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
'';
};
public = lib.mkOption {
default = { };
type = lib.types.attrsOf (
lib.types.submodule (fact: {
options = {
name = lib.mkOption {
type = lib.types.str;
description = ''
name of the public fact
'';
default = fact.config._module.args.name;
};
path = lib.mkOption {
type = lib.types.path;
description = ''
path to a fact which is generated by the generator
'';
defaultText = lib.literalExpression "\${config.clanCore.clanDir}/machines/\${config.clanCore.machineName}/facts/\${fact.config.name}";
default =
config.clanCore.clanDir + "/machines/${config.clanCore.machineName}/facts/${fact.config.name}";
};
value = lib.mkOption {
defaultText = lib.literalExpression "\${config.clanCore.clanDir}/\${fact.config.path}";
type = lib.types.nullOr lib.types.str;
default =
if builtins.pathExists fact.config.path then lib.strings.fileContents fact.config.path else null;
};
};
})
);
};
};
})
);
};
};
imports = [
./compat.nix
./secret/sops.nix
./secret/password-store.nix
./secret/vm.nix
./public/in_repo.nix
./public/vm.nix
];
}

View File

@@ -0,0 +1,6 @@
{ config, lib, ... }:
{
config = lib.mkIf (config.clanCore.facts.publicStore == "in_repo") {
clanCore.facts.publicModule = "clan_cli.facts.public_modules.in_repo";
};
}

View File

@@ -0,0 +1,6 @@
{ config, lib, ... }:
{
config = lib.mkIf (config.clanCore.facts.publicStore == "vm") {
clanCore.facts.publicModule = "clan_cli.facts.public_modules.vm";
};
}

View File

@@ -0,0 +1,15 @@
{ config, lib, ... }:
{
options.clan.password-store.targetDirectory = lib.mkOption {
type = lib.types.path;
default = "/etc/secrets";
description = ''
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.secretUploadDirectory = config.clan.password-store.targetDirectory;
clanCore.facts.secretModule = "clan_cli.facts.secret_modules.password_store";
};
}

View File

@@ -41,10 +41,10 @@ in
description = "The default groups to for encryption use when no groups are specified.";
};
};
config = lib.mkIf (config.clanCore.secretStore == "sops") {
clanCore.secretsDirectory = "/run/secrets";
clanCore.secretsPrefix = config.clanCore.machineName + "-";
system.clan.secretFactsModule = "clan_cli.facts.secret_modules.sops";
config = lib.mkIf (config.clanCore.facts.secretStore == "sops") {
clanCore.facts.secretDirectory = "/run/secrets";
clanCore.facts.secretModule = "clan_cli.facts.secret_modules.sops";
clanCore.facts.secretUploadDirectory = lib.mkDefault "/var/lib/sops-nix";
sops.secrets = builtins.mapAttrs (name: _: {
sopsFile = config.clanCore.clanDir + "/sops/secrets/${name}/secret";
format = "binary";
@@ -57,6 +57,5 @@ in
sops.age.keyFile = lib.mkIf (builtins.pathExists (
config.clanCore.clanDir + "/sops/secrets/${config.clanCore.machineName}-age.key/secret"
)) (lib.mkDefault "/var/lib/sops-nix/key.txt");
clanCore.secretsUploadDirectory = lib.mkDefault "/var/lib/sops-nix";
};
}

View File

@@ -0,0 +1,8 @@
{ config, lib, ... }:
{
config = lib.mkIf (config.clanCore.facts.secretStore == "vm") {
clanCore.facts.secretDirectory = "/etc/secrets";
clanCore.facts.secretUploadDirectory = "/etc/secrets";
clanCore.facts.secretModule = "clan_cli.facts.secret_modules.vm";
};
}

View File

@@ -23,6 +23,7 @@
};
clanDir = lib.mkOption {
type = lib.types.either lib.types.path lib.types.str;
default = ".";
description = ''
the location of the flake repo, used to calculate the location of facts and secrets
'';

View File

@@ -44,33 +44,6 @@
'';
default = false;
};
secretsUploadDirectory = lib.mkOption {
type = lib.types.path;
description = ''
the directory on the deployment server where secrets are uploaded
'';
};
publicFactsModule = lib.mkOption {
type = lib.types.str;
description = ''
the python import path to the facts module
'';
default = "clan_cli.facts.public_modules.in_repo";
};
secretFactsModule = lib.mkOption {
type = lib.types.str;
description = ''
the python import path to the secrets module
'';
default = "clan_cli.facts.secret_modules.sops";
};
secretsData = lib.mkOption {
type = lib.types.path;
description = ''
secret data as json for the generator
'';
default = pkgs.writers.writeJSON "secrets.json" config.clanCore.secrets;
};
vm.create = lib.mkOption {
type = lib.types.path;
description = ''
@@ -92,10 +65,9 @@
# optimization for faster secret generate/upload and machines update
config = {
system.clan.deployment.data = {
inherit (config.system.clan) publicFactsModule secretFactsModule secretsData;
inherit (config.clanCore) facts;
inherit (config.clan.networking) targetHost buildHost;
inherit (config.clan.deployment) requireExplicitUpdate;
inherit (config.clanCore) secretsUploadDirectory;
};
system.clan.deployment.file = pkgs.writeText "deployment.json" (
builtins.toJSON config.system.clan.deployment.data

View File

@@ -1,15 +0,0 @@
{ config, lib, ... }:
{
options.clan.password-store.targetDirectory = lib.mkOption {
type = lib.types.path;
default = "/etc/secrets";
description = ''
The directory where the password store is uploaded to.
'';
};
config = lib.mkIf (config.clanCore.secretStore == "password-store") {
clanCore.secretsDirectory = config.clan.password-store.targetDirectory;
clanCore.secretsUploadDirectory = config.clan.password-store.targetDirectory;
system.clan.secretFactsModule = "clan_cli.facts.secret_modules.password_store";
};
}

View File

@@ -1,9 +0,0 @@
{ config, lib, ... }:
{
config = lib.mkIf (config.clanCore.secretStore == "vm") {
clanCore.secretsDirectory = "/etc/secrets";
clanCore.secretsUploadDirectory = "/etc/secrets";
system.clan.secretFactsModule = "clan_cli.facts.secret_modules.vm";
system.clan.publicFactsModule = "clan_cli.facts.public_modules.vm";
};
}