Merge pull request 'vars: allow setting files as needed for activation' (#2633) from vars-needed_activation into main
This commit is contained in:
@@ -28,7 +28,7 @@ In your nixos configuration you can get a path to secrets like this `config.sops
|
|||||||
|
|
||||||
```nix
|
```nix
|
||||||
{ config, ...}: {
|
{ config, ...}: {
|
||||||
sops.secrets.my-password.neededForUsers = true;
|
sops.secrets.my-password.neededFor = "users";
|
||||||
|
|
||||||
users.users.mic92 = {
|
users.users.mic92 = {
|
||||||
isNormalUser = true;
|
isNormalUser = true;
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ in
|
|||||||
mode
|
mode
|
||||||
deploy
|
deploy
|
||||||
secret
|
secret
|
||||||
neededForUsers
|
neededFor
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -196,14 +196,18 @@ in
|
|||||||
'';
|
'';
|
||||||
type = str;
|
type = str;
|
||||||
};
|
};
|
||||||
neededForUsers = lib.mkOption {
|
neededFor = lib.mkOption {
|
||||||
description = ''
|
description = ''
|
||||||
Enabling this option causes the secret to be decrypted/installed before users and groups are created.
|
Enabling this option causes the secret to be decrypted/installed before users and groups are created.
|
||||||
This can be used to retrieve user's passwords.
|
This can be used to retrieve user's passwords.
|
||||||
Setting this option moves the secret to /run/secrets-for-users and disallows setting owner and group to anything else than root.
|
Setting this option moves the secret to /run/secrets-for-users and disallows setting owner and group to anything else than root.
|
||||||
'';
|
'';
|
||||||
type = bool;
|
type = lib.types.enum [
|
||||||
default = false;
|
"activation"
|
||||||
|
"users"
|
||||||
|
"services"
|
||||||
|
];
|
||||||
|
default = "services";
|
||||||
};
|
};
|
||||||
owner = lib.mkOption {
|
owner = lib.mkOption {
|
||||||
description = "The user name or id that will own the file.";
|
description = "The user name or id that will own the file.";
|
||||||
|
|||||||
@@ -69,10 +69,15 @@ in
|
|||||||
file:
|
file:
|
||||||
lib.mkIf file.config.secret {
|
lib.mkIf file.config.secret {
|
||||||
path =
|
path =
|
||||||
if file.config.neededForUsers then
|
if file.config.neededFor == "users" then
|
||||||
"/run/user-secrets/${file.config.generatorName}/${file.config.name}"
|
"/run/user-secrets/${file.config.generatorName}/${file.config.name}"
|
||||||
|
else if file.config.neededFor == "services" then
|
||||||
|
"/run/secrets/${file.config.generatorName}/${file.config.name}"
|
||||||
|
else if file.config.neededFor == "activation" then
|
||||||
|
"${config.clan.password-store.secretLocation}/${file.config.generatorName}/${file.config.name}"
|
||||||
else
|
else
|
||||||
"/run/secrets/${file.config.generatorName}/${file.config.name}";
|
throw "unknown neededFor ${file.config.neededFor}";
|
||||||
|
|
||||||
};
|
};
|
||||||
secretModule = "clan_cli.vars.secret_modules.password_store";
|
secretModule = "clan_cli.vars.secret_modules.password_store";
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -27,6 +27,9 @@ in
|
|||||||
# Before we generate a secret we cannot know the path yet, so we need to set it to an empty string
|
# Before we generate a secret we cannot know the path yet, so we need to set it to an empty string
|
||||||
fileModule = file: {
|
fileModule = file: {
|
||||||
path = lib.mkIf file.config.secret (
|
path = lib.mkIf file.config.secret (
|
||||||
|
if file.config.neededFor == "activation" then
|
||||||
|
"/var/lib/sops-nix/${file.config.generatorName}/${file.config.name}"
|
||||||
|
else
|
||||||
config.sops.secrets.${"vars/${file.config.generatorName}/${file.config.name}"}.path
|
config.sops.secrets.${"vars/${file.config.generatorName}/${file.config.name}"}.path
|
||||||
or "/no-such-path"
|
or "/no-such-path"
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -16,7 +16,9 @@ in
|
|||||||
collectFiles =
|
collectFiles =
|
||||||
vars:
|
vars:
|
||||||
let
|
let
|
||||||
relevantFiles = generator: flip filterAttrs generator.files (_name: f: f.secret && f.deploy);
|
relevantFiles =
|
||||||
|
generator:
|
||||||
|
flip filterAttrs generator.files (_name: f: f.secret && f.deploy && (f.neededFor != "activation"));
|
||||||
allFiles = flatten (
|
allFiles = flatten (
|
||||||
flip mapAttrsToList vars.generators (
|
flip mapAttrsToList vars.generators (
|
||||||
gen_name: generator:
|
gen_name: generator:
|
||||||
@@ -24,8 +26,9 @@ in
|
|||||||
fname: file: {
|
fname: file: {
|
||||||
name = fname;
|
name = fname;
|
||||||
generator = gen_name;
|
generator = gen_name;
|
||||||
|
neededForUsers = file.neededFor == "users";
|
||||||
inherit (generator) share;
|
inherit (generator) share;
|
||||||
inherit (file) owner group neededForUsers;
|
inherit (file) owner group;
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -160,11 +160,20 @@ class SecretStore(StoreBase):
|
|||||||
for generator in self.machine.vars_generators:
|
for generator in self.machine.vars_generators:
|
||||||
dir_exists = False
|
dir_exists = False
|
||||||
for file in generator.files:
|
for file in generator.files:
|
||||||
|
if file.needed_for == "activation":
|
||||||
|
(output_dir / generator.name / file.name).parent.mkdir(
|
||||||
|
parents=True,
|
||||||
|
exist_ok=True,
|
||||||
|
)
|
||||||
|
(output_dir / generator.name / file.name).write_bytes(
|
||||||
|
self.get(generator, file.name)
|
||||||
|
)
|
||||||
|
continue
|
||||||
if not file.deploy:
|
if not file.deploy:
|
||||||
continue
|
continue
|
||||||
if not file.secret:
|
if not file.secret:
|
||||||
continue
|
continue
|
||||||
if not dir_exists and not file.needed_for_users:
|
if not dir_exists and file.needed_for == "services":
|
||||||
tar_dir = tarfile.TarInfo(name=generator.name)
|
tar_dir = tarfile.TarInfo(name=generator.name)
|
||||||
tar_dir.type = tarfile.DIRTYPE
|
tar_dir.type = tarfile.DIRTYPE
|
||||||
tar_dir.mode = 0o511
|
tar_dir.mode = 0o511
|
||||||
@@ -176,7 +185,7 @@ class SecretStore(StoreBase):
|
|||||||
tar_file.mode = file.mode
|
tar_file.mode = file.mode
|
||||||
tar_file.uname = file.owner
|
tar_file.uname = file.owner
|
||||||
tar_file.gname = file.group
|
tar_file.gname = file.group
|
||||||
if file.needed_for_users:
|
if file.needed_for == "users":
|
||||||
user_tar.addfile(tarinfo=tar_file, fileobj=io.BytesIO(content))
|
user_tar.addfile(tarinfo=tar_file, fileobj=io.BytesIO(content))
|
||||||
else:
|
else:
|
||||||
tar.addfile(tarinfo=tar_file, fileobj=io.BytesIO(content))
|
tar.addfile(tarinfo=tar_file, fileobj=io.BytesIO(content))
|
||||||
|
|||||||
@@ -173,6 +173,16 @@ class SecretStore(StoreBase):
|
|||||||
sops_secrets_folder(self.machine.flake_dir) / key_name,
|
sops_secrets_folder(self.machine.flake_dir) / key_name,
|
||||||
)
|
)
|
||||||
(output_dir / "key.txt").write_text(key)
|
(output_dir / "key.txt").write_text(key)
|
||||||
|
for generator in self.machine.vars_generators:
|
||||||
|
for file in generator.files:
|
||||||
|
if file.needed_for == "activation":
|
||||||
|
(output_dir / generator.name / file.name).parent.mkdir(
|
||||||
|
parents=True,
|
||||||
|
exist_ok=True,
|
||||||
|
)
|
||||||
|
(output_dir / generator.name / file.name).write_bytes(
|
||||||
|
self.get(generator, file.name)
|
||||||
|
)
|
||||||
|
|
||||||
def upload(self) -> None:
|
def upload(self) -> None:
|
||||||
with TemporaryDirectory(prefix="sops-upload-") as tempdir:
|
with TemporaryDirectory(prefix="sops-upload-") as tempdir:
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ class Var:
|
|||||||
owner: str = "root"
|
owner: str = "root"
|
||||||
group: str = "root"
|
group: str = "root"
|
||||||
mode: int = 0o400
|
mode: int = 0o400
|
||||||
needed_for_users: bool = False
|
needed_for: str = "services"
|
||||||
|
|
||||||
# TODO: those shouldn't be set here
|
# TODO: those shouldn't be set here
|
||||||
_store: "StoreBase | None" = None
|
_store: "StoreBase | None" = None
|
||||||
@@ -78,5 +78,5 @@ class Var:
|
|||||||
owner=data.get("owner", "root"),
|
owner=data.get("owner", "root"),
|
||||||
group=data.get("group", "root"),
|
group=data.get("group", "root"),
|
||||||
mode=int(data.get("mode", "400"), 8),
|
mode=int(data.get("mode", "400"), 8),
|
||||||
needed_for_users=data.get("neededForUsers", False),
|
needed_for=data.get("neededFor", "services"),
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user