As the nix store is world-readable, we want to avoid writing secrets during evaluation.
We can roughly break the entire process, from nix to kube, down to
eval -> deploy -> run
eval time #
This is the process of taking nix configuration and generating a JSON manifest.
The generated manifest is written to the nix store; so inlining (unencrypted) secrets is entirely possible but not ideal.
deploy time #
The simplest option is to inject secrets during deploy; that is, after manifests have been generated but prior to running kubectl apply (or equivalent).
example #
We can pipe manifests through vals prior to apply. Such that using the file provider might look like
default.nix
{ kubenix ? import ../../../.. }:
kubenix.evalModules.${builtins.currentSystem} {
module = { kubenix, ... }: {
imports = [ kubenix.modules.k8s ];
kubernetes.resources.secrets.example.stringData = {
password = "ref+file:///path/to/secret";
};
};
}
NOTE: the creation of /path/to/secret is out of scope but we recommend checking out one of the secret managing schemesThen the apply might look something like
pkgs.writeShellScript "apply" ''
cat manifest.json | ${pkgs.vals}/bin/vals eval | ${pkgs.kubectl}/bin/kubectl -f -
''
NOTE: the builtin kubenix CLI uses this approach so it’s not necessary to implement yourselfruntime #
A more robust option is to resolve secrets from within the cluster itself.
This can be done with tools that either
reference external sources
similar to the deploy time example; instead, resolving secrets with a controller running inside the cluster (e.g., external-secrets)
decrypt inline secrets
values can be decrypted by a controller within the cluster itself (e.g., sealed-secrets) or using external keys (e.g., sops)