Flakes + secret configs

I have a public repo for my nixos configuration. I’m switching to nix-flakes. Previously I’ve put configs which where private in .gitignore. With flake this configs get ignored.

What is a good way to keep some configs private with flakes? I tried nix-sops, but if I understand it right it is only usable for options which expect a path.

2 Likes

I use a combination of agenix and git-crypt: GitHub - chvp/nixos-config: Configuration of my machines (main development happens at https://git.chvp.be/chvp/nixos-config these days)

2 Likes

why both? I used to use git-crypt, but moved to agenix since git-crypt doesn’t play nicely if I want to eval my flake from a remote, i.e. nix build github:someFlake#mySystem

2 Likes

There’s some configuration in my repo that I can’t or won’t share publically that would be very hard to move into agenix. E.g. some ports that are opened or the command in the systemd service that I use to connect to my work’s VPN.

1 Like

When I was switching to flakes I was also wondering about this issue so I opened a thread here which evolved into a wiki page. Maybe that can help you decide.

Currently I am using git-crypt to store my wifi passwords in the git repo of my system flake.


EDIT mid 2022: I have since switched to agenix because flakes and git-crypt did not work well together.

2 Likes

I’ve been wondering about this too. I’m attempting to convert my Home Manager configuration to flakes and the main issue I have right now is how to manage private Nix expressions.

My current pre-flake approach is to have home.nix in my public repository import all code in ~/.config/nixpkgs/home.d alongside those in the repository itself. This way, I can obtain a single usable Home Manager configuration on any online computer and also mix private configuration when needed. But the downside is, it’s fundamentally impure and thus incompatible with flakes.

The current solution I have in mind is to create a private flake that takes as input my public flake, but it’s bit of chore to maintain two separate flakes. Other solutions I’ve seen so far either can’t encrypt Nix expressions or require decryption of private configuration even when you don’t want them. So I’m curious if there’s an alternative approach.

just brainstorming here, but maybe a clean solution to this would be to have NixOS become aware of a second level of evaluation specifically for secret expressions, the first phase would decrypt these expressions using something like agenix, and if they are not available, it can continue, but with a warning mentioning that none of your secrets configs will be evaluated?

1 Like

Interesting, would this approach be feasible with Nix the language in its current form? I’d imagine it would require an error handling mechanism built in to the language itself.

Perhaps all that is need would be access the the recursive nix experimental feature so that, probably during the activation script, the nixos build can call nix again to evaluate secret modules after any secrets have been decrypted.

I just want to throw it out there. I am 100% happy with Nix being a build and package management and configuration language. I would rather see NixOS modules have a standardized interface with which things like agenix or sops-nix can work.

(And a solution that just re-evals at activation time will still wind up encoding secrets into the world-readable store, again ending up at “a non-Nix solution is needed for the last mile”. And I pretty strongly agree with that - having Nix do actual secret management means teaching another C codebase how to do encryption, etc, idk, feels like a tough sell to me)

2 Likes

I dunno if Nix would necessarily need to encrypt anything itself. I always figured a simple native solution would be to create something like a /nix/secret/store that is just like /nix/store but with stricter file permissions (not world readable). one could start with an encrypted file and write some clever derivation to decrypt it here during a build.

The whole second level of evaluation thing was an attempt to address the case where people want to keep the Nix expressions themselves secret, while still being evaluable. I don’t think there would be a way to keep a nix expression out of the nix store, but it would at least keep it out of a world readable public repository.

Anyway, it was just a completely off-the-cuff idea :sweat_smile:

1 Like

Yes, it’s the private Nix expressions that I’m mostly concerned about. It’s not secret in a cryptographic sense, and it’s also not a concern if it ends up on the Nix store. There are some parts of my personal setup that I wish to put in a public repository so that I can use it outside of home, and other parts which I wish to keep from public view.

2 Likes

I have been banging my head over this for past two days but is there any minimal example of how to use secrets in a Flakes-enabled NixOS module home-manager configuration?

To give an example, I am specifically trying to use a secret value in this field - https://nix-community.github.io/home-manager/options.html#opt-programs.firefox.profiles._name_.settings .

I think you need to use git-crypt for this. agenix only works for options which expect a file path. Do somentic like

firefox.profile.name.settings = import ./settings.nix;

and then in settings.nix so was wie

''
setting1=true
setting2=false
''

That should be a valid nix string

Then you can encrypt settings.nix with git-crypt

Note that those secrets will be accessible with ugo+r permissions in the nix store if you use git-crypt, so don’t use this for anything actually secret.

Thanks, good to know.

This would only matters if it needs to be “secret on your machine” though and your threat model was “bad actor with local machine access” right?

I think the most common case is “I can push this to github and people can’t see my secret”.

Absolutely, yes. It’s also usually easier to get non-root privilege escalation, though, so your threat model should probably contain malware.

I can’t imagine Firefox profile settings being particularly confidential even in a malware case, but when setting a password option for something that has an open port on the firewall you might want to think twice. Things like sops-nix can help for those use cases, though.

Another aspect is that I have a public cache - so I am guessing the git-crypt solution will make the secrets available nonetheless.

1 Like

That’s an interesting edge case. I believe you need to know the hash of the artifact you want to retrieve, which would be difficult to get from an encrypted string (unless you share that sha with logs somewhere).

I don’t think there is a “download all artifacts” option, anyway. I’m very curious how hard it would be to exfiltrate secrets from a public nix cache. Probably still not advisable, too easy to accidentally publish logs.