Age (and its rust implementation Rage) combined with agenix[0] and age.el[1] has made my self-hosted deployment and management so, so easy without compromising security. That, when combined with general NixOS conveniences is why I'm able to self-host at all. If not for these, just the anxiety of having to setup new server in case of whatever loss and the associated time/opportunity loss kept me from dong the same for years.
Anyway, just want to say that Age is great!
P.S. The author also did an analysis of Restic the backup tool [2] which also prompted me to setup nice backup solution for my machines. Pretty cool.
[0]: https://github.com/ryantm/agenix
Server deployment/management tools like Ansible have their own file encryption and string encryption tools builtin.
But then you'd have to use YAML
More notably, then you'd have to use Ansible.
any suggestions on a better config management tool?
NixOS
yea... don't really want to have to change OS for a CM tool
If the thing accepts YAML it often also accepts a equivalent JSON.
yaml is a superset of json, so by definition anything that accepts yaml _must_ accept json
I concur, that is an unfortunate side-effect. The only thing you can then do is to treat yaml as a thing that is constantly out to get you. Make all values strings and use things like > or >- to write strings without having to escape quotes, don't rely on any referencing, except for Ansible's templating itself. Do not code in yaml. Or, if you really want to, perhaps you could even write yaml like json, since json should be accepted format for yaml files.
Coming from Ansible I can understand the distrust in yaml. But I haven't seen half as much yaml weirdness in Kubernetes (and i associate age/sops with k8s). At least not since I stopped making my own helm charts.
Can you elaborate on how age (and the downstream packages) has made a difference in your workflows?
With agenix, you can encrypt your secrets, such as API keys, and have them stored in your git repo alongside the system configuration (which in nixos is just a bunch of text files). Then you only need to provision the server with the ed25519 private key corresponding to the pubkey the files were encrypted with, and agenix will automatically decrypt the files on boot and place them in /run/agenix, with the specified access permissions.
So like SOPS, but specific to nix somehow? What is the advantage of the nixy integration here vs the universality of SOPS? Better native integration with NixOS?
To clarify maybe, NixOS puts all configuration and program files it handles in a world-readable object store on disk. If you want to manage secrets on NixOS securely, you have two choices:
- Manage it out of band. That negates all of the benefits of NixOS, at least for those files. (I.e. you would need additional deployment steps, rollback wouldn't work, you would have to stop and migrate system services that depend on those secrets yourself, etc.)
- Encrypt it and only decrypt it on activation (which happens when switching to a new config or on boot). agenix and nix-sops (the premier SOPS/NixOS integration) are two libraries that you can include in your config to do that. With this, the world-readable store only contains encrypted secrets.
Of course with #2 you still have to manage your private keys (age or whatever SOPS uses) out-of-band but that is significantly less work since those aren't expected to change nearly as much. You can also generally decouple that from your day-to-day deployment workflow.
I see. So you do need one of these libraries if you want to do things The Nix Way with secrets
Similar to sops in a sense that both allow encryption/decryption with SSH keys.
In terms of NixOS integration, both are on equal footing.
I'm just unfond of yaml is all.
So you still need a secret when provisioning, and you need to handle change management for that, and storing it securely outside of the git repo. And agenix did not change that workflow, or did it?
Yes and no.
I only need to care about my SSH key(s). Which I had to anyway. But now the secrets for all the services (except SSH) lie right besides their config. Any change in one or other is directly visible in git log.
In short, age cut down on the number and types of secrets that I have to manage out of band. Which is very good. It's always easier to be able to remember 2 things (config + SSH keys) than 2+n things (config + SSH keys + whatever secret mechanism any service uses, times number of services).
You could also include SSH keys as public secrets.
https://github.com/Foxboron/ssh-tpm-agent
I use git-crypt for this, and love it.
I’ve used git-crypt[0] with great success. It uses git smudge so you never commit secrets if you set it up properly the first time.
Unfortunately, it doesn’t support groups.
For a solution that scales to teams, check out SOPS[1]. You have to do a little more work to be sure that secrets are ignored in the repo but it works reasonably well and is well known.
Transparent support at the editor level (age.el) sounds really nice though.
[0] https://github.com/AGWA/git-crypt
[1] https://github.com/getsops/sops
These?
[0] https://github.com/AGWA/git-crypt
[1] https://github.com/getsops/sops
Yes! Thank you :)
You forgot to include the links.
I have been using agenix and it is very helpful. I am also looking into writing a system module that makes it easy to generate secrets on the fly.
A lot of secrets are just things like, backend and frontend of some service need to be configured with matching keys, but are both running on the same device. In that case you could have a systemd service which just generates a new random key if it doesn't already exist, and then ensure that the dependent services wait for that service to complete. That way you don't have to store anything in git for those at least.
Check out agenix-rekey[https://github.com/oddlama/agenix-rekey], it has the ability to set up secret generators.