Agenix cli error in pure evaluation mode
I've recently enabled pure evaluation mode in nix.conf. Now when I try to run agenix -e mysecret.age I get an error that states that access to absolute path '/nixos-config/secrets/secrets.nix' is forbidden in pure eval mode (use '--impure' to override) and I cannot proceed.
I don't know if this is intended (keeping the evaluation pure), but the fix would be to add the --impure flag to nix-instantiate in agenix.sh.
Personally I think that this would not have drawbacks, reading from a file is an impure operation and thus should be marked as such.
I'd like to keep my evaluation pure and see others solutions to do so with agenix usage.
I use pure evaluation mode (flakes are pure by default) and have never seen this error.
Have you set pure eval to true in nix.conf?
$ nix show-config | grep pure-eval
pure-eval = true
Thanks. I realized I was using it incorrectly trying to readFile an age secret.
$ nix show-config | grep pure-eval pure-eval = true
Yes but it looks like nix-instantiate is looking at /etc/nix/nix.conf. It happens only when I set pure-eval = true there.
Huh, you're right.
It's a pain for me to modify nix.conf because it is declaratively managed in my setup, but once I do:
$ agenix -e influxdb.age
error:
… while calling the 'import' builtin
at «string»:1:14:
1| (let rules = import ./secrets.nix; in rules."influxdb.age".publicKeys)
| ^
… while realising the context of path '/Users/n8henrie/git/nixos/secrets/secrets.nix'
at «none»:0: (source not available)
error: access to absolute path '/Users/n8henrie/git/nixos/secrets/secrets.nix' is forbidden in pure eval mode (use '--impure' to override)
I suspect the discrepancy in what show-config displays may be because I use the new-style calls and flakes are pure by default, but the internal call to nix-instantiate doesn't have this default.
Are you on nixos?
Yes (with flakes), I just set nix.settings.pure-eval = true; in my config.
So I think the issues are here and here, where we are parsing secrets.nix at runtime in bash (using nix to run bash to run nix) to evaluate a nix file.
We are just extracting keys / values, so could consider using something other than nix to do this, but it certainly seems that nix is the most appropriate tool for the job, and it doesn't really help with purity to use a different tool to do the exact same thing.
For this to be pure in the nix sense, one would have to have nix parse the secrets.nix from the nix store, requiring one to have their config (including the new secret to be edited) already in the store (not currently a requirement). That seems unwieldy.
Alternatively, I don't think secrets.nix necessarily has to be a nix file[^1]. In fact, I'm not entirely sure why it is nix. If memory serves, sops-nix uses toml or yaml or something -- I don't see why an alternative config file format (that could easily be parsed by other tooling) wouldn't work as well or better. For example json, since we're already using jq in the parsing of secrets.nix.
[^1]: Per the readme: "This secrets.nix file is not imported into your NixOS configuration. It's only used for the agenix CLI tool (example below) to know which public keys to use for encryption."
For this to be pure in the nix sense, one would have to have nix parse the
secrets.nixfrom the nix store, requiring one to have their config (including the new secret to be edited) already in the store (not currently a requirement). That seems unwieldy.
While it might be beneficial to eventually make agenix pure, I think the right thing to do at the moment is just acknowledge the impurity by passing --impure to nix-instantiate. To make it more explicit, an --impure flag could be added to agenix, to be passed along to nix-instantiate. In a pure env, this flag would be necessary for agenix to work (I don’t think there’s anything it can currently do purely other than --help).
@SamueleFacenda can you work around the issue for now by using NIX_CONFIG="pure-eval = false" agenix -e mysecret.age?
Alternatively, I don't think
secrets.nixnecessarily has to be a nix file1. In fact, I'm not entirely sure why it is nix. If memory serves,sops-nixuses toml or yaml or something -- I don't see why an alternative config file format (that could easily be parsed by other tooling) wouldn't work as well or better. For example json, since we're already usingjqin the parsing ofsecrets.nix.
I’m in agreement earlier part of your comment (“it certainly seems that nix is the most appropriate tool for the job”), so just to bolster that (and to vent a personal gripe): I get frustrated when Nix-based tools use some other config format[^1]. IMO, Nix is a better config format than JSON, YAML, TOML, and pretty much anything else. So a tool that is Nix-centric choosing some other format baffles me.
In this particular case, my secrets.nix would be degraded, as it currently looks like
let
keys = import ../nix/keys.nix;
in {
"cachix.dhall.age".publicKeys = keys.user.greg;
…
"wireless-networks.env.age".publicKeys = keys.platform.NixOS ++ keys.admin;
}
where keys.nix is also used by users.users, programs.ssh.knownHosts, etc. None of the above-named alternative formats support imports, AFAIK. And keys.nix also has other simple bindings to group keys by user, machine, platform, etc. Other than Dhall, I don’t think there’s a config format that’s better (especially since agenix is already tied to Nix).
[^1]: I get that there are extenuating circumstances – in many repos I end up reading some JSON or YAML into Nix because I need to share values with non-Nix tools and it’s just the least-complicated solution, but if anything, Nix should be working to making parsing Nix expressions easier outside of the Nix infra so that other tools start choosing it over worse formats.
Fair enough. My main point was that using nix ... --impure to read / parse something outside of the nix store certainly doesn't make any less sense than using jq .... to read / parse something outside of the nix store. Just because one of those says --impure shouldn't bias our thinking on the level of purity.
Adding it to the nix-instantiate call should allow users to ensure everything else / as much as possible is pure (as opposed to having to --impure the top-level invocation), which seems like a good thing -- I like your point.
Any plans to "purify" agenix? Maybe something like home-manager's config.lib.file.mkOutOfStoreSymlink to link /run/agenix into the store?