forked from clan/clan-core
clan-cli: add interactive secrets/fact generation
This commit is contained in:
parent
f500aee786
commit
a1dcddf9b4
@ -54,6 +54,14 @@
|
|||||||
Extra paths to add to the PATH environment variable when running the generator.
|
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 variabel $prompt_value.
|
||||||
|
'';
|
||||||
|
};
|
||||||
script = lib.mkOption {
|
script = lib.mkOption {
|
||||||
type = lib.types.str;
|
type = lib.types.str;
|
||||||
description = ''
|
description = ''
|
||||||
@ -92,14 +100,14 @@
|
|||||||
config' = config;
|
config' = config;
|
||||||
in
|
in
|
||||||
lib.mkOption {
|
lib.mkOption {
|
||||||
type = lib.types.attrsOf (lib.types.submodule ({ config, ... }: {
|
type = lib.types.attrsOf (lib.types.submodule ({ config, name, ... }: {
|
||||||
options = {
|
options = {
|
||||||
name = lib.mkOption {
|
name = lib.mkOption {
|
||||||
type = lib.types.str;
|
type = lib.types.str;
|
||||||
description = ''
|
description = ''
|
||||||
name of the secret
|
name of the secret
|
||||||
'';
|
'';
|
||||||
default = config._module.args.name;
|
default = name;
|
||||||
};
|
};
|
||||||
path = lib.mkOption {
|
path = lib.mkOption {
|
||||||
type = lib.types.str;
|
type = lib.types.str;
|
||||||
|
@ -2,6 +2,7 @@ import argparse
|
|||||||
import importlib
|
import importlib
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
|
from collections.abc import Callable
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from tempfile import TemporaryDirectory
|
from tempfile import TemporaryDirectory
|
||||||
|
|
||||||
@ -24,6 +25,7 @@ def generate_service_secrets(
|
|||||||
secret_store: SecretStoreBase,
|
secret_store: SecretStoreBase,
|
||||||
fact_store: FactStoreBase,
|
fact_store: FactStoreBase,
|
||||||
tmpdir: Path,
|
tmpdir: Path,
|
||||||
|
prompt: Callable[[str], str],
|
||||||
) -> None:
|
) -> None:
|
||||||
service_dir = tmpdir / service
|
service_dir = tmpdir / service
|
||||||
# check if all secrets exist and generate them if at least one is missing
|
# check if all secrets exist and generate them if at least one is missing
|
||||||
@ -41,6 +43,16 @@ def generate_service_secrets(
|
|||||||
secrets_dir = service_dir / "secrets"
|
secrets_dir = service_dir / "secrets"
|
||||||
secrets_dir.mkdir(parents=True)
|
secrets_dir.mkdir(parents=True)
|
||||||
env["secrets"] = str(secrets_dir)
|
env["secrets"] = str(secrets_dir)
|
||||||
|
# compatibility for old outputs.nix users
|
||||||
|
if isinstance(machine.secrets_data[service]["generator"], str):
|
||||||
|
generator = machine.secrets_data[service]["generator"]
|
||||||
|
else:
|
||||||
|
generator = machine.secrets_data[service]["generator"]["finalScript"]
|
||||||
|
if machine.secrets_data[service]["generator"]["prompt"]:
|
||||||
|
prompt_value = prompt(
|
||||||
|
machine.secrets_data[service]["generator"]["prompt"]
|
||||||
|
)
|
||||||
|
env["prompt_value"] = prompt_value
|
||||||
# fmt: off
|
# fmt: off
|
||||||
cmd = nix_shell(
|
cmd = nix_shell(
|
||||||
[
|
[
|
||||||
@ -58,7 +70,7 @@ def generate_service_secrets(
|
|||||||
"--unshare-user",
|
"--unshare-user",
|
||||||
"--uid", "1000",
|
"--uid", "1000",
|
||||||
"--",
|
"--",
|
||||||
"bash", "-c", machine.secrets_data[service]["generator"]["finalScript"]
|
"bash", "-c", generator
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
# fmt: on
|
# fmt: on
|
||||||
@ -105,17 +117,30 @@ def generate_service_secrets(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def generate_secrets(machine: Machine) -> None:
|
def generate_secrets(
|
||||||
|
machine: Machine,
|
||||||
|
prompt: None | Callable[[str], str] = None,
|
||||||
|
) -> None:
|
||||||
secrets_module = importlib.import_module(machine.secrets_module)
|
secrets_module = importlib.import_module(machine.secrets_module)
|
||||||
secret_store = secrets_module.SecretStore(machine=machine)
|
secret_store = secrets_module.SecretStore(machine=machine)
|
||||||
|
|
||||||
facts_module = importlib.import_module(machine.facts_module)
|
facts_module = importlib.import_module(machine.facts_module)
|
||||||
fact_store = facts_module.FactStore(machine=machine)
|
fact_store = facts_module.FactStore(machine=machine)
|
||||||
|
|
||||||
|
if prompt is None:
|
||||||
|
prompt = lambda text: input(f"{text}: ")
|
||||||
|
|
||||||
with TemporaryDirectory() as tmp:
|
with TemporaryDirectory() as tmp:
|
||||||
tmpdir = Path(tmp)
|
tmpdir = Path(tmp)
|
||||||
for service in machine.secrets_data:
|
for service in machine.secrets_data:
|
||||||
generate_service_secrets(machine, service, secret_store, fact_store, tmpdir)
|
generate_service_secrets(
|
||||||
|
machine=machine,
|
||||||
|
service=service,
|
||||||
|
secret_store=secret_store,
|
||||||
|
fact_store=fact_store,
|
||||||
|
tmpdir=tmpdir,
|
||||||
|
prompt=prompt,
|
||||||
|
)
|
||||||
|
|
||||||
print("successfully generated secrets")
|
print("successfully generated secrets")
|
||||||
|
|
||||||
|
@ -39,6 +39,7 @@ def facts_to_nixos_config(facts: dict[str, dict[str, bytes]]) -> dict:
|
|||||||
def build_vm(
|
def build_vm(
|
||||||
machine: Machine, tmpdir: Path, nix_options: list[str] = []
|
machine: Machine, tmpdir: Path, nix_options: list[str] = []
|
||||||
) -> dict[str, str]:
|
) -> dict[str, str]:
|
||||||
|
# TODO pass prompt here for the GTK gui
|
||||||
secrets_dir = get_secrets(machine, tmpdir)
|
secrets_dir = get_secrets(machine, tmpdir)
|
||||||
|
|
||||||
facts_module = importlib.import_module(machine.facts_module)
|
facts_module = importlib.import_module(machine.facts_module)
|
||||||
@ -68,7 +69,6 @@ def get_secrets(
|
|||||||
secrets_module = importlib.import_module(machine.secrets_module)
|
secrets_module = importlib.import_module(machine.secrets_module)
|
||||||
secret_store = secrets_module.SecretStore(machine=machine)
|
secret_store = secrets_module.SecretStore(machine=machine)
|
||||||
|
|
||||||
# TODO Only generate secrets for local clans
|
|
||||||
generate_secrets(machine)
|
generate_secrets(machine)
|
||||||
|
|
||||||
secret_store.upload(secrets_dir)
|
secret_store.upload(secrets_dir)
|
||||||
|
Loading…
Reference in New Issue
Block a user