nixcfg/modules/nixos/services/vault-agent/default.nix
2024-01-11 10:31:04 +00:00

175 lines
6.5 KiB
Nix

{ lib, config, pkgs, inputs, ... }:
with lib;
with lib.plusultra;
let
cfg = config.plusultra.services.vault-agent;
# nixos-vault-service places generated files here:
# https://github.com/DeterminateSystems/nixos-vault-service/blob/45e65627dff5dc4bb40d0f2595916f37e78959c1/module/helpers.nix#L4
secret-files-root = "/tmp/detsys-vault";
environment-files-root = "/run/keys/environment";
create-environment-files-submodule = service-name: types.submodule ({ name, ... }: {
options = {
text = mkOpt (types.nullOr types.str) null "An inline template for Vault to template.";
source = mkOpt (types.nullOr types.path) null "The file with environment variables for Vault to template.";
path = mkOption {
readOnly = true;
type = types.str;
description = "The path to the environment file.";
default = "${environment-files-root}/${service-name}/${name}.EnvFile";
defaultText = "${environment-files-root}/<service-name>/<template-name>.EnvFile";
};
};
});
secret-files-submodule = types.submodule ({ name, ... }: {
options = {
text = mkOpt (types.nullOr types.str) null "An inline template for Vault to template.";
source = mkOpt (types.nullOr types.path) null "The file for Vault to template.";
permissions = mkOpt types.str "0400" "The octal mode of this file.";
change-action = mkOpt (types.nullOr (types.enum [ "restart" "stop" "none" ])) null "The action to take when secrets change.";
path = mkOption {
readOnly = true;
type = types.str;
description = "The path to the secret file.";
default = "${secret-files-root}/${name}";
};
};
});
services-submodule =
types.submodule
({ name, config, ... }: {
options = {
enable = mkBoolOpt true "Whether to enable Vault Agent for this service.";
settings = mkOpt types.attrs { } "Vault Agent configuration.";
secrets = {
environment = {
force = mkOpt types.bool false "Whether or not to force the use of Vault Agent's environment files.";
change-action = mkOpt (types.enum [ "restart" "stop" "none" ]) "restart" "The action to take when secrets change.";
templates = mkOpt (types.attrsOf (create-environment-files-submodule name)) { } "Environment variable files for Vault to template.";
template = mkOpt (types.nullOr (types.either types.path types.str)) null "An environment variable template.";
paths = mkOption {
readOnly = true;
type = types.listOf types.str;
description = "Paths to all of the environment files";
default =
if config.secrets.environment.template != null then
[ "${environment-files-root}/${name}/EnvFile" ]
else
(
mapAttrsToList
(template-name: value: value.path)
config.secrets.environment.templates
);
};
};
file = {
change-action = mkOpt (types.enum [ "restart" "stop" "none" ]) "restart" "The action to take when secrets change.";
files = mkOption {
description = "Secret files to template.";
default = { };
type = types.attrsOf secret-files-submodule;
};
};
};
};
});
in
{
# imports = [
# inputs.vault-service.nixosModules.nixos-vault-service
# ];
options.plusultra.services.vault-agent = {
enable = mkEnableOption "Vault Agent";
settings = mkOpt types.attrs { } "Default Vault Agent configuration.";
services = mkOption {
description = "Services to install Vault Agent into.";
default = { };
type = types.attrsOf services-submodule;
};
};
config = mkIf cfg.enable {
assertions = flatten (mapAttrsToList
(service-name: service:
(mapAttrsToList
(template-name: template:
{
assertion = (template.source != null && template.text == null) || (template.source == null && template.text != null);
message = "plusultra.services.vault-agent.services.${service-name}.secrets.environment.templates.${template-name} must set either `source` or `text`.";
}
)
service.secrets.environment.templates)
++
(mapAttrsToList
(file-name: file:
{
assertion = (file.source != null && file.text == null) || (file.source == null && file.text != null);
message = "plusultra.services.vault-agent.services.${service-name}.secrets.file.files.${file-name} must set either `source` or `text`.";
}
)
service.secrets.file.files)
)
cfg.services);
systemd.services = mapAttrs
(service-name: value: mkIf value.secrets.environment.force {
serviceConfig.EnvironmentFile = mkForce value.secrets.environment.paths;
})
cfg.services;
detsys.vaultAgent = {
defaultAgentConfig = cfg.settings;
systemd.services = mapAttrs
(service-name: value: {
inherit (value) enable;
agentConfig = value.settings;
environment = {
changeAction = value.secrets.environment.change-action;
templateFiles = mapAttrs
(template-name: value: {
file =
if value.source != null then
value.source
else
pkgs.writeText "${service-name}-${template-name}-env-template" value.text;
})
value.secrets.environment.templates;
template =
if (builtins.isPath value.secrets.environment.template) || (builtins.isNull value.secrets.environment.template) then
value.secrets.environment.template
else
pkgs.writeText "${service-name}-env-template" value.secrets.environment.template;
};
secretFiles = {
defaultChangeAction = value.secrets.file.change-action;
files = mapAttrs
(file-name: value: {
changeAction = value.change-action;
template = value.text;
templateFile = value.source;
perms = value.permissions;
})
value.secrets.file.files;
};
})
cfg.services;
};
};
}