The NixOS Vault Service module is a NixOS module that allows easily integrating Vault with existing systemd services.
NOTE: The goal is not magic, so some services may need to be changed or patched.
# flake.nix
{
inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
inputs.vaultModule = {
url = "github:DeterminateSystems/nixos-vault-service/main";
inputs.nixpkgs.follows = "nixpkgs";
};
outputs = { self, nixpkgs, vaultModule }: {
nixosConfigurations.nixos = nixpkgs.lib.nixosSystem {
system = "x86_64-linux";
modules = [
vaultModule.nixosModule
./configuration.nix
];
};
};
}
There are many ways to make this module available in your system configuration without flakes. This is an example of just one possible method:
# vault.nix
let
vaultModuleSrc = builtins.fetchGit {
url = "https://github.com/DeterminateSystems/nixos-vault-service.git";
ref = "main";
};
vaultModule = import vaultModuleSrc;
in
{
imports = [ vaultModule.nixosModule ];
}
After you have the module imported by your system's configuration, you can now being integrating your services with Vault.
detsys.vaultAgent.defaultAgentConfig
(optional, default:{ }
) – The default configuration for all Vault agents. Defers to individual service'sagentConfig
, if set. SeeagentConfig
options for more information.detsys.vaultAgent.systemd.services.<service-name>.enable
(optional, default:false
) – Whether to enable Vault integration with the service specified by<service-name>
.detsys.vaultAgent.systemd.services.<service-name>.agentConfig
(optional, default:{ }
) – The Vault agent configuration for this service. SeeagentConfig
options for more information.detsys.vaultAgent.systemd.services.<service-name>.environment
(optional, default:{ }
) – Environment variable secret configuration.detsys.vaultAgent.systemd.services.<service-name>.environment.changeAction
(optional, default:"restart"
) – What action to take if any secrets in the environment change. One of"restart"
,"stop"
, or"none"
.detsys.vaultAgent.systemd.services.<service-name>.environment.templateFiles
(optional, default:{ }
) – Set of files containing environment variables for Vault to template.detsys.vaultAgent.systemd.services.<service-name>.environment.templateFiles.<filename>.file
(required) – The file containing the environment variable(s) for Vault to template.
detsys.vaultAgent.systemd.services.<service-name>.environment.template
(optional, default:null
) – A multi-line string containing environment variables for Vault to template.
detsys.vaultAgent.systemd.services.<service-name>.secretFiles
(optional, default:{ }
) – Secret file configuration.detsys.vaultAgent.systemd.services.<service-name>.secretFiles.defaultChangeAction
(optional, default:"restart"
) – What action to take if any secrets in any of these files change. One of"restart"
,"reload"
,"stop"
, or"none"
.detsys.vaultAgent.systemd.services.<service-name>.secretFiles.files
(optional: default{ }
) – Set of files for Vault to template.detsys.vaultAgent.systemd.services.<service-name>.secretFiles.files.<filename>.changeAction
(optional, default: thedefaultChangeAction
) – What action to take if the secret file changes. One of"restart"
,"reload"
,"stop"
, or"none"
.detsys.vaultAgent.systemd.services.<service-name>.secretFiles.files.<filename>.templateFile
(optional, default:null
) – A file containing a Vault template. Conflicts withtemplate
.detsys.vaultAgent.systemd.services.<service-name>.secretFiles.files.<filename>.template
(optional, default:null
) – A string containing a Vault template. Conflicts withtemplateFile
.detsys.vaultAgent.systemd.services.<service-name>.secretFiles.files.<filename>.perms
(optional, default:"0400"
) – The octal mode of the secret file.detsys.vaultAgent.systemd.services.<service-name>.secretFiles.files.<filename>.path
(read-only) – The path to the secret file inside<service-name>
's namespace'sPrivateTmp
.
The agentConfig
options are partially typed in order to allow us to set defaults, as well as prevent users from using obviously broken configurations.
These options apply for both detsys.vaultAgent.defaultAgentConfig
and detsys.vaultAgent.systemd.services.<service-name>.agentConfig
.
agentConfig.auto_auth
(optional, default:{ }
) – The Vault agent'sauto_auth
configuration.agentConfig.auto_auth.method
(optional, default:[ ]
) – Theauto_auth
'smethod
configuration. Note that this does not support the HCL-esque way of defining this option withmethod "aws" { ... }
-- you must specify thetype
andconfig
separately.agentConfig.auto_auth.method.[].type
(required) – Theauto_auth.method
's type.agentConfig.auto_auth.method.[].config
(required) – Theauto_auth.method
's configuration.agentConfig.template_config
(optional, default:{ }
) – The Vault agent'stemplate_config
configuration.agentConfig.template_config.exit_on_retry_failure
(optional, default:true
) – Whether or not to exit the Vault agent when it fails to retry any further. Must be true.
Any options not listed here may be manually specified, but will not be type-checked.
For example, to specify the cache.use_auto_auth_token
option, you would only need to specify agentConfig.cache.use_auto_auth_token = true;
.
{
detsys.vaultAgent.defaultAgentConfig = {
# The configuration passed to `vault agent` -- will be converted to JSON.
# This is where your `vault`, `auto_auth`, `template_config`, etc., configuration should go.
};
detsys.vaultAgent.systemd.services."service-name" = {
enable = true;
agentConfig = {
# Overrides the entirety of `detsys.vaultAgent.defaultAgentConfig`.
};
environment = {
changeAction = "restart";
templateFiles = {
"example-a".file = ./example-a.ctmpl;
"example-b".file = ./example-b.ctmpl;
};
template = ''
EXAMPLE_C={{ with secret "secret/super_secret" }}{{ .Data.c }}{{ end }}
EXAMPLE_D={{ with secret "secret/super_secret" }}{{ .Data.d }}{{ end }}
'';
};
secretFiles = {
defaultChangeAction = "restart";
files."example-e" = {
changeAction = "reload";
perms = "0440";
# NOTE: You can only use either:
templateFile = ./example-e.ctmpl;
# or:
template = ''
{{ with secret "secret/super_secret" }}{{ .Data.e }}{{ end }}
'';
# but not both.
};
files."example-f".template = ''
{{ with secret "secret/super_secret" }}{{ .Data.f }}{{ end }}
'';
};
};
}
You can set the default agentConfig
for all units by using the detsys.vaultAgent.defaultAgentConfig
interface.
NOTE: Manually-specified unit
agentConfig
s will override all of the the settings specified in thedetsys.vaultAgent.defaultAgentConfig
option.
NOTE: Some of these options must be wrapped in a list (e.g. see
auto_auth
) in order for the generated JSON to be valid. Wrapping them all in a list doesn't hurt.
{
detsys.vaultAgent.defaultAgentConfig = {
vault = { address = "http://127.0.0.1:8200"; };
auto_auth = {
method = [{
type = "approle";
config = {
remove_secret_id_file_after_reading = false;
role_id_file_path = "/role_id";
secret_id_file_path = "/secret_id";
};
}];
};
template_config = {
static_secret_render_interval = "5s";
};
};
}
All secretFiles.files.<NAME>
expose a path
attribute, so you don't need to memorize where the secrets are written to:
{ config, ... }:
{
detsys.vaultAgent.systemd.services.prometheus = {
enable = true;
secretFiles.files."vault.token".template = ''
{{ with secret "secrets/nginx-basic-auth"}}
{{ .Data.data.htpasswd }}
{{ end }}
'';
};
}
You can then access the path to the above vault.token
secret file via config.detsys.vaultAgent.systemd.services.prometheus.secretFiles.files."vault.token".path
.
By using the NixOS module system, it is possible to override the sidecar's systemd service configuration (e.g. to tune how often the service is allowed to restart):
Sidecar unit names follow the pattern of detsys-vaultAgent-${service-name}
.
{
detsys.vaultAgent.systemd.services.prometheus = {
enable = true;
secretFiles = {
defaultChangeAction = "none";
files."vault.token".templateFile = ./vault-token.ctmpl;
};
};
systemd.services.detsys-vaultAgent-prometheus = {
unitConfig = {
StartLimitIntervalSec = 300;
StartLimitBurst = 10;
};
serviceConfig = {
RestartSec = 30;
Restart = "always";
};
};
}
We have tests for the module's definition, helpers, and implementation. These can be run like so:
nix-instantiate --strict --eval --json ./default.nix -A checks.definition
nix-instantiate --strict --eval --json ./default.nix -A checks.helpers
nix-build ./default.nix -A checks.implementation
To read the secret file (e.g. to verify the contents), you will need to join the namespace of the sidecar vaultAgent unit:
systemd-run -p JoinsNamespaceOf=detsys-vaultAgent-serviceName.service -p PrivateTmp=true cat /tmp/detsys-vault/some-secret-file