How exactly does `environment.etc` work regarding secrets?

The documentation (I found (option description)) regarding environment.etc is a bit scarce. It does not work as I expected.

I’m trying to set up an OpenVPN config using agenix. The problem is that this takes 2 or 3 separate, interlinked, secret files. Let’s assume two and call them main and auth where in main, we have

auth-path <path to auth>

I don’t want to assume anything about agenix internals, so I don’t want to

auth-path /run/agenix/auth

Instead, I want to use

auth-path /etc/secrets/auth

and make sure that /etc/secrets/auth reflects the content of the decrypted agenix managed secret file (which currently should be /run/agenix/auth). I was thinking let’s just create a symlink. So I used

{
  environment.etc = {
    "secrets/auth" = {
      source = config.age.secrets.auth.path;
      mode = "0400";
    };
  };
}

To my surprise, this did not create symlink. It created a file with the same content as the decrypted secret. So I’m curious about the exact mechanism (and philosophy) here.

Did I leak a secret to the store? I think not, because the decrypted secret is only available at runtime, but I want to be sure. When exactly does this file creation happen? Will it detect changes in the source file?

I think a symlink would still be cleaner. Is that what environment.etc.target does?

First of all, you’d not be assuming age internals if you just used config.age.secrets.auth.path in the OpenVPN configuration directly, so I’d recommend just generating the config from Nix, so you can use path interpolation.

Regarding your question, see the documentation for mode:

       environment.etc.<name>.mode
           If set to something else than ‘symlink’, the file is copied
           instead of symlinked, with the given file mode.

           Type: string

           Default: "symlink"

           Example: "0600"

           Declared by:
               <nixpkgs/nixos/modules/system/etc/etc.nix>

Your secrets should not have been leaked to the store, instead it should be a hardlink.

The philosophy here is that it doesn’t make sense to set the permission of a symlink on Linux (I think chmod doesn’t allow it and the permissions of the symbolic link itself are never considered, but I may be wrong on the details) and the permissions of the linked to file are not (and should not) managed by the code backing environment.etc.

Ah great explanation, makes a lot of sense, thank you!

I agree that using path interpolation would be nice, but it’s not possible, because the other file also is a secret. It would become very complex stitching that together using a template and then inserting all sorts of secret stuff into it.

Anyway, the last point of interest would be the when question. When is this link created in the “generation-switch-boot-etc” lifecycles? Not really important, but nice to know

With default settings, a perl script is executed on activation that writes all necessary files under /etc. Activation is done after switch to a configuration, but also on system boot (since you may always boot into a different generation of your system).

1 Like