add option to extend path for generator
All checks were successful
checks-impure / test (pull_request) Successful in 1m9s
checks / test (pull_request) Successful in 2m6s

This commit is contained in:
Jörg Thalheim 2023-11-30 13:01:38 +01:00
parent 7d3801a916
commit 373fc83160
5 changed files with 56 additions and 30 deletions

View File

@ -46,14 +46,36 @@
''; '';
}; };
generator = lib.mkOption { generator = lib.mkOption {
type = lib.types.str; type = lib.types.submodule ({ config, ... }: {
description = '' options = {
Script to generate the secret. path = lib.mkOption {
The script will be called with the following variables: type = lib.types.listOf (lib.types.either lib.types.path lib.types.package);
- facts: path to a directory where facts can be stored default = [ ];
- secrets: path to a directory where secrets can be stored description = ''
The script is expected to generate all secrets and facts defined in the module. Extra paths to add to the PATH environment variable when running the generator.
''; '';
};
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 = ''
export PATH="${lib.makeBinPath config.path}"
${config.script}
'';
};
};
});
}; };
secrets = secrets =
let let

View File

@ -39,7 +39,7 @@ in
trap "rm -rf $facts" EXIT trap "rm -rf $facts" EXIT
secrets=$(mktemp -d) secrets=$(mktemp -d)
trap "rm -rf $secrets" EXIT trap "rm -rf $secrets" EXIT
( ${v.generator} ) ( ${v.generator.finalScript} )
${lib.concatMapStrings (fact: '' ${lib.concatMapStrings (fact: ''
mkdir -p "$CLAN_DIR"/"$(dirname ${fact.path})" mkdir -p "$CLAN_DIR"/"$(dirname ${fact.path})"

View File

@ -32,7 +32,14 @@ in
import json import json
import sys import sys
from clan_cli.secrets.sops_generate import generate_secrets_from_nix from clan_cli.secrets.sops_generate import generate_secrets_from_nix
args = json.loads(${builtins.toJSON (builtins.toJSON { machine_name = config.clanCore.machineName; secret_submodules = config.clanCore.secrets; })}) args = json.loads(${builtins.toJSON (builtins.toJSON {
machine_name = config.clanCore.machineName;
secret_submodules = lib.mapAttrs (_name: secret: {
secrets = builtins.attrNames secret.secrets;
facts = lib.mapAttrs (_: secret: secret.path) secret.facts;
generator = secret.generator.finalScript;
}) config.clanCore.secrets;
})})
generate_secrets_from_nix(**args) generate_secrets_from_nix(**args)
''; '';
uploadSecrets = pkgs.writeScript "upload-secrets" '' uploadSecrets = pkgs.writeScript "upload-secrets" ''

View File

@ -138,9 +138,9 @@ in
facts.zerotier-meshname = { }; facts.zerotier-meshname = { };
facts.zerotier-network-id = { }; facts.zerotier-network-id = { };
secrets.zerotier-identity-secret = { }; secrets.zerotier-identity-secret = { };
generator = '' generator.path = [ config.services.zerotierone.package pkgs.fakeroot pkgs.python3 ];
export PATH=${lib.makeBinPath [ config.services.zerotierone.package pkgs.fakeroot ]} generator.script = ''
${pkgs.python3.interpreter} ${./generate.py} --mode network \ python3 ${./generate.py} --mode network \
--ip "$facts/zerotier-ip" \ --ip "$facts/zerotier-ip" \
--meshname "$facts/zerotier-meshname" \ --meshname "$facts/zerotier-meshname" \
--identity-secret "$secrets/zerotier-identity-secret" \ --identity-secret "$secrets/zerotier-identity-secret" \
@ -155,10 +155,9 @@ in
facts.zerotier-ip = { }; facts.zerotier-ip = { };
facts.zerotier-meshname = { }; facts.zerotier-meshname = { };
secrets.zerotier-identity-secret = { }; secrets.zerotier-identity-secret = { };
generator.path = [ config.services.zerotierone.package pkgs.python3 ];
generator = '' generator.script = ''
export PATH=${lib.makeBinPath [ config.services.zerotierone.package ]} python3 ${./generate.py} --mode identity \
${pkgs.python3.interpreter} ${./generate.py} --mode identity \
--ip "$facts/zerotier-ip" \ --ip "$facts/zerotier-ip" \
--meshname "$facts/zerotier-meshname" \ --meshname "$facts/zerotier-meshname" \
--identity-secret "$secrets/zerotier-identity-secret" \ --identity-secret "$secrets/zerotier-identity-secret" \

View File

@ -41,11 +41,9 @@ def generate_secrets_group(
clan_dir = flake_dir clan_dir = flake_dir
secrets = secret_options["secrets"] secrets = secret_options["secrets"]
needs_regeneration = any( needs_regeneration = any(
not has_secret(flake_dir, f"{machine_name}-{secret['name']}") not has_secret(flake_dir, f"{machine_name}-{name}") for name in secrets
for secret in secrets.values()
) or any( ) or any(
not (flake_dir / fact["path"]).exists() not (flake_dir / fact).exists() for fact in secret_options["facts"].values()
for fact in secret_options["facts"].values()
) )
generator = secret_options["generator"] generator = secret_options["generator"]
@ -56,7 +54,7 @@ def generate_secrets_group(
secrets_dir = subdir / "secrets" secrets_dir = subdir / "secrets"
secrets_dir.mkdir(parents=True) secrets_dir.mkdir(parents=True)
text = f"""\ text = f"""
set -euo pipefail set -euo pipefail
export facts={shlex.quote(str(facts_dir))} export facts={shlex.quote(str(facts_dir))}
export secrets={shlex.quote(str(secrets_dir))} export secrets={shlex.quote(str(secrets_dir))}
@ -69,25 +67,25 @@ export secrets={shlex.quote(str(secrets_dir))}
msg = "failed to the following command:\n" msg = "failed to the following command:\n"
msg += text msg += text
raise ClanError(msg) raise ClanError(msg)
for secret in secrets.values(): for name in secrets:
secret_file = secrets_dir / secret["name"] secret_file = secrets_dir / name
if not secret_file.is_file(): if not secret_file.is_file():
msg = f"did not generate a file for '{secret['name']}' when running the following command:\n" msg = f"did not generate a file for '{name}' when running the following command:\n"
msg += text msg += text
raise ClanError(msg) raise ClanError(msg)
encrypt_secret( encrypt_secret(
flake_dir, flake_dir,
sops_secrets_folder(flake_dir) / f"{machine_name}-{secret['name']}", sops_secrets_folder(flake_dir) / f"{machine_name}-{name}",
secret_file.read_text(), secret_file.read_text(),
add_machines=[machine_name], add_machines=[machine_name],
) )
for fact in secret_options["facts"].values(): for name, fact_path in secret_options["facts"].items():
fact_file = facts_dir / fact["name"] fact_file = facts_dir / name
if not fact_file.is_file(): if not fact_file.is_file():
msg = f"did not generate a file for '{fact['name']}' when running the following command:\n" msg = f"did not generate a file for '{name}' when running the following command:\n"
msg += text msg += text
raise ClanError(msg) raise ClanError(msg)
fact_path = clan_dir.joinpath(fact["path"]) fact_path = clan_dir / fact_path
fact_path.parent.mkdir(parents=True, exist_ok=True) fact_path.parent.mkdir(parents=True, exist_ok=True)
shutil.copyfile(fact_file, fact_path) shutil.copyfile(fact_file, fact_path)