rebase, complete implementation

This commit is contained in:
Jeremy Fleischman 2024-11-05 11:46:26 -06:00 committed by mergify[bot]
parent bb7d636211
commit aa5caa129b
5 changed files with 149 additions and 208 deletions

View file

@ -16,6 +16,7 @@ writeTextFile {
ageSshKeyPaths = cfg.age.sshKeyPaths;
useTmpfs = cfg.useTmpfs;
templates = cfg.templates;
placeholderBySecretName = cfg.placeholder;
userMode = false;
logging = {
keyImport = builtins.elem "keyImport" cfg.log;

View file

@ -1,40 +1,21 @@
{ config, pkgs, lib, options, ... }:
with lib;
with lib.types;
with builtins;
let
cfg = config.sops;
secretsForUsers = lib.filterAttrs (_: v: v.neededForUsers) cfg.secrets;
inherit (lib)
mkOption
mkDefault
mapAttrs
types
;
users = config.users.users;
useSystemdActivation = (options.systemd ? sysusers && config.systemd.sysusers.enable) ||
(options.services ? userborn && config.services.userborn.enable);
renderScript = ''
echo Setting up sops templates...
${concatMapStringsSep "\n" (name:
let
tpl = config.sops.templates.${name};
substitute = pkgs.writers.writePython3 "substitute" { }
(readFile ./subs.py);
subst-pairs = pkgs.writeText "pairs" (concatMapStringsSep "\n"
(name:
"${toString config.sops.placeholder.${name}} ${
config.sops.secrets.${name}.path
}") (attrNames config.sops.secrets));
in ''
mkdir -p "${dirOf tpl.path}"
(umask 077; ${substitute} ${tpl.file} ${subst-pairs} > ${tpl.path})
chmod "${tpl.mode}" "${tpl.path}"
chown "${tpl.owner}:${tpl.group}" "${tpl.path}"
'') (attrNames config.sops.templates)}
'';
in {
options.sops = {
templates = mkOption {
description = "Templates for secret files";
type = attrsOf (submodule ({ config, ... }: {
type = types.attrsOf (types.submodule ({ config, ... }: {
options = {
name = mkOption {
type = singleLineStr;
type = types.singleLineStr;
default = config._module.args.name;
description = ''
Name of the file used in /run/secrets/rendered
@ -42,32 +23,32 @@ in {
};
path = mkOption {
description = "Path where the rendered file will be placed";
type = singleLineStr;
type = types.singleLineStr;
default = "/run/secrets/rendered/${config.name}";
};
content = mkOption {
type = lines;
type = types.lines;
default = "";
description = ''
Content of the file
'';
};
mode = mkOption {
type = singleLineStr;
type = types.singleLineStr;
default = "0400";
description = ''
Permissions mode of the rendered secret file in octal.
'';
};
owner = mkOption {
type = singleLineStr;
type = types.singleLineStr;
default = "root";
description = ''
User of the file.
'';
};
group = mkOption {
type = singleLineStr;
type = types.singleLineStr;
default = users.${config.owner}.group;
defaultText = lib.literalExpression ''config.users.users.''${cfg.owner}.group'';
description = ''
@ -88,40 +69,21 @@ in {
default = { };
};
placeholder = mkOption {
type = attrsOf (mkOptionType {
type = types.attrsOf (types.mkOptionType {
name = "coercibleToString";
description = "value that can be coerced to string";
check = strings.isConvertibleWithToString;
merge = mergeEqualOption;
check = lib.strings.isConvertibleWithToString;
merge = lib.mergeEqualOption;
});
default = { };
visible = false;
};
};
config = optionalAttrs (options ? sops.secrets)
(mkIf (config.sops.templates != { }) {
config = lib.optionalAttrs (options ? sops.secrets)
(lib.mkIf (config.sops.templates != { }) {
sops.placeholder = mapAttrs
(name: _: mkDefault "<SOPS:${hashString "sha256" name}:PLACEHOLDER>")
(name: _: mkDefault "<SOPS:${builtins.hashString "sha256" name}:PLACEHOLDER>")
config.sops.secrets;
systemd.services.sops-render-secrets = let
installServices = [ "sops-install-secrets.service" ] ++ optional (secretsForUsers != { }) "sops-install-secrets-for-users.service";
in lib.mkIf (cfg.templates != { } && useSystemdActivation) {
wantedBy = [ "sysinit.target" ];
requires = installServices;
after = installServices;
unitConfig.DefaultDependencies = "no";
script = renderScript;
serviceConfig = {
Type = "oneshot";
RemainAfterExit = true;
};
};
system.activationScripts.renderSecrets = mkIf (cfg.templates != { } && !useSystemdActivation)
(stringAfter ([ "setupSecrets" ] ++ optional (secretsForUsers != { }) "setupSecretsForUsers")
renderScript);
});
}

View file

@ -1,26 +0,0 @@
from sys import argv
def substitute(target: str, subst: str) -> str:
with open(target) as f:
content = f.read()
with open(subst) as f:
subst_pairs = f.read().splitlines()
for pair in subst_pairs:
placeholder, path = pair.split()
if placeholder in content:
with open(path) as f:
content = content.replace(placeholder, f.read())
return content
def main() -> None:
target = argv[1]
subst = argv[2]
print(substitute(target, subst))
main()