Alternative way to handle secrets

When I started to learn Nix and NixOS, I found it difficult to, on top of everything else to learn, also learn how to work with tools such as sops-nix or agenix to setup the secrets. Also, I did not want to do a mistake and put passwords into the nix store before I had become more familiar with NIxOS as a whole. Secrets is also something you can not put off to learn later, you need to find a solution early on.

So I decided to copy my passwords to files and set appropriate file permissions on them using ordinary shell scripts. I still do this, but I have streamlined this process over time. My current method is to run a command like the below

(set -e; pass nixos/secrets && cat setup-secrets.sh) | ssh hostname sudo bash -s

This concatenates the secrets and their setup mechanism to a single shell script that becomes standard input to bash, effectively executing it from one host to another without any intermediate file representation.

My secrets master is my pass store (https://www.passwordstore.org). I already use this for all my other passwords so using this also for my NixOS secrets is convenient for me.

The nixos/secrets secret should contains all my secrets formatted using shell variable syntax. Example

gmailkey=“mygmailpassword”

setup-secrets.sh contains statements such as

install -m 400 <(echo “$gmailkey”) /persist/secrets/gmailkey

This stores the gmailkey value (the password) in the designated location, with the right file permissions immediately, and I feel confident that my secrets did not leak along the way.

And then I use gmailkey in msmtp like

passwordeval = “${pkgs.coreutils}/bin/cat /persist/secrets/gmailkey”;

I am curious to hear what others think about this way to handle secrets.

1 Like

I used to do something very similar to that: Secure, Declarative Key Management with NixOps, Pass, and nix-plugins

I don’t necessarily recommend this anymore. 1) NixOps is unmaintained (or at least on life support) if I understand correctly. 2) It allows all of nixpkgs to access your pass store, which is safe-ish since it’s a pure evaluation environment, plus you presumably have a level of trust in nixpkgs. But it makes me feel uneasy.

These days I’m kind of just of the mind that secrets should be generated on-device on first use, and then their resulting identity should be added to whatever they need to authenticate with through some means. For instance, I’m a big fan of SSH certificate authorities so that all you have to do is sign the public key once and now everything trusts you that needs to. Centralized secrets just leave a bad taste in my mouth in general, and I prefer to think of secrets as a stateful problem rather than a declarative one that you can solve with Nix.

6 Likes

It would be really cool if there was a good way to do this for arbitrary services, both on the user and system end. Hell, have it tied to the system’s TPM, which you use to generate a key you need to sign only once on some online service, and all other secrets the system ever wants are derived from that, with authenticity guaranteed by the online service. Only need a way to get key backups without breaking data separation entirely from there.

I imagine that this is how working in more serious devops environments feels, it’s a shame there’s no standard like this for your average joe, but it’s wishful thinking given how much legacy software we all use, and how little actually developed software seems to care about secret provenance.


I think a standalone service that manages secrets much like sops/agenix, but doesn’t encrypt the secrets at rest (instead leaving that to the user’s disk encryption), could hit the sweet spot for ease-of-use in the simple “I have a desktop on which I want to run NixOS and don’t want to faff with secrets” use case. Most desktop users probably don’t need a scheme to share their secrets via git repositories (and in fact I think the implicit encouragement of doing so by sops/agenix is harmful).

Doing that through pass is cute, but it again adds a learning curve for an unrelated tool, so it isn’t that much different from sops-nix/agenix. Any encryption of the secrets at all probably adds additional overhead for some subset of users, unnecessarily so if the secrets never leave that host via plaintext channels.

Having a module that does something like this in NixOS proper would be really cool. It could also serve as a framework for sops/agenix-alikes, centralizing the common features - they effectively just decrypt a file at boot and then write the result to /run/secrets, after all, there’s no reason that there should be multiple projects doing this in subtly different ways.

Adding sops and age on top, while certainly useful in a lot of use cases, mysticizes the whole concept. Removing encryption for simpler use cases would give people a learning path.

I’d also love to see systemd-creds tied into this ecosystem somehow. Incorporating the TPM into the scheme, and having some standard for applications to adopt over time is how we could achieve the dream scenario. It’s a shame it’s so hard to use systemd-creds for a lot of use cases.

3 Likes

Doing that through pass is cute, but it again adds a learning curve for an unrelated tool, so it isn’t that much different from sops-nix/agenix.

I think this should be seen more as a pattern than a recipe, if it makes sense. I use pass, so I integrated it with a way to deploy secrets to a NixOS system. It worked well for me. If I used another password manager, I would look for ways to integrate with that. Or just a regular encrypted text file. The main idea in this case is to touch the secrets as little as possible from their source to where they are put, to avoid temporary files leaking them if something breaks.

Fair, I understand. You’ll find that sops-nix and agenix are also variants of this pattern, just using a NixOS module to do what your setup-secrets.sh does on every boot, and an encrypted text file with a specific syntax (sops, or something custom for agenix) to replace your nixos/secrets secret in pass.

Doing this only once per install is an interesting thought, but as configuration drifts you may need to make sure files created by setup-secrets.sh are deleted. Doing that via a NixOS module that writes to a tmpfs resolves that particular problem.

I’d also love to see systemd-creds tied into this ecosystem somehow

This I really agree with. Last I looked, systemd-creds did not have support for public cryptography, and I sensed a kind of bootstrap problem to load keys into it from the outside. But it feels like a very promising tool

1 Like

You’ll find that sops-nix and agenix are also variants of this pattern, …

Also good points. I have nothing bad to say about these tools really, I am sure they are doing their job well for those that use them. I just thought they were difficult to approach when everything about Nix and NixOS were new to me. There is so much to learn before you can start to understand how they work, at least in my case. And for something like secrets, I want to understand how it works, and I chose solve my “secrets problem” with more common Linux knowledge.

Also, when I started, I was still running openSUSE, and developed my first NixOS configurations towards a VM until I finally reinstalled my server. I liked that I could deploy my secrets from a non-NixOS host, as I recall agenix and sops-nix were not packed for my distro.

1 Like

Agreed… The best approach for servers I’ve stumbled over so far seems to be gokey but correct implementation requires a bunch of other pieces, notably some form of secure boot which I’m not sure how mature the nixos support is.