How to effectively manage secrets

Hello everyone.

I wanted to self host firefox sync, and found the appropriate code snippet for a minimal configuration on the NixOS 23.05 manual:

services.mysql.package = pkgs.mariadb;

services.firefox-syncserver = {
  enable = true;
  secrets = builtins.toFile "sync-secrets" ''
    SYNC_MASTER_SECRET=this-secret-is-actually-leaked-to-/nix/store
  '';
  singleNode = {
    enable = true;
    hostname = "localhost";
    url = "http://localhost:5000";
  };
};

At the bottom of the manual section there is a warning which looks like this:

This configuration should never be used in production. It is not encrypted and stores its secrets in a world-readable location.

My question now is where and how do I securely store secrets?

4 Likes

The state of the art are basically sops-nix and agenix. They’re both conceptually pretty similar, you configure some public keys as being used to encrypt secrets, and run a command to generate a file encrypted with that public key which can be decrypted with the corresponding private key. agenix only supports age, which uses SSH keys (the public key in your config, the private key put on the nixos system by some other mechanism), while sops-nix supports age or gpg.

5 Likes

Do you use sops or agenix?

And do I really need one of these libraries. Is there not a built in nix way to achieve the same or something similar?

@tonyfinn

1 Like

I just started using sops-nix, as it has support for home manager.

And yes, there is current#y no alternative.

I used agenix for some stuff, and wrote about it a few months ago! Maybe you might find this useful. :smiley:

4 Likes

@NobbZ how did you Manager your secrets before using sops?

I manually copied them in place and hoped to not forget about them on a redeploy.

Similarily, I now hope to not forget to add them to the configuration.

1 Like

@NobbZ does it make sense to use sops if it is only for user and root passwords? At the moment I just use passwd with a password manager (Bitwarden)

1 Like

Personally I do use mutable users, as I use my machine for the family, and have to leave a room for them to change their passwords on their behalf.

Whether or not it makes sense depends on your usecase…

Though as far as I understand, the situation is like this:

  • agenix: Even though they set a users password in the example in the README, that doesn’t really seem to work and at least in the discord there are users asking for support because of that regularly.
  • sops-nix: Eplixitely states in their README, that you need to specify explicitely when you need a secret for user creation and warns that it hen has to be world readable. This means, you would still need to use hashed password files. (GitHub - Mic92/sops-nix: Atomic secret provisioning for NixOS based on sops)

My question now is where and how do I securely store secrets?

It depends on what are your goals.

For example, are you happy with just filesystem permissions protecting the secrets or you’d rather use some form of encryption?
In the former you can just put them in so location like /var/my-secrets with appropriate permissions, say 600 and owned by the user that needs them. In the latter you need some software to encrypt/decrypt the secrets on demand, which is a lot more complicated but probably safer.

Also, do you want to configure machine remotely? If so, should the secret be ephemeral (reprovision on every boot) or persistent? etc.

Here’s a(n incomplete) comparison of some solutions.

1 Like

Been using agenix together with pass for a while now. sops-nix is neat, but since it only supports age and gpg, I haven’t found it to be much more useful than agenix. When bootstrapping a new machine, I just boot up nixos, let it create a host ssh key, encrypt all the necessary secrets using age, add it to my dotfiles flake repo, and run

nixos-rebuild switch ".#machine" --target-host <ip> --build-host <ip> 

It works OK. It wouldn’t work on a too massive scale, I’m managing about 10 machines using this approach, and it’s fine for that. Updating passwords is a make rule which looks something like

pass path/to/secret | head -1 | age --encrypt --armor -R path/to/host_key.pub -o path/to/encrypted/secret.age

I use a yubikey to encrypt passwords in pass, so in the end, you either need root access on the target machine, or you need the yubikey.

It’s not perfect, nothing in security is, it’s a bit fiddly, and rotating secrets is not the easiest, but I’m pretty happy with it. It works on both my ec2 servers and my laptops, which hashicorp vault doesnt, and it works for keys needed at boot on servers, which yubikey gpg encrypted stuff doesnt.

5 Likes

May I just say, that nix definitely needs a batteries-included, easy, built-in way to mange secrets? It’s so important, I don’t know how it’s not one of the top priorities. Security needs to be easy, usable and as readily available as can be, because people are lazy and this question comes up way too often.

11 Likes

I use agenix to manage my user passwords. It works for that. I suspect people are asking for help with that because the tutorial is pointing them toward that and they have other problems.

1 Like

Secrets paths have been discussed for a very long time. The problem is that encryption or ACLs are pretty much incompatible with the current model of world-readable Nix store and reproducibility, so they’re far from easy to implement.

1 Like