Secrets management is a tricky problem in infrastructure as code, especially when your deployment tool emphasizes immutability and reproducibility, like NixOS. Agenix tackles this by combining the age encryption tool with Nix’s declarative model, allowing secrets to coexist safely in the Nix store and be decrypted automatically during system activation. This approach addresses the common pain point of storing secrets encrypted yet making them available seamlessly and reproducibly on NixOS machines.
integrating age encryption with nixos for secret management
Agenix is a Nix library and command-line tool designed explicitly for managing secrets securely within NixOS environments. It leverages SSH public-private key pairs alongside the age encryption tool to encrypt secrets into .age files. These encrypted secrets are then stored safely in the Nix store.
The core architectural idea is that during NixOS system activation, the secrets are decrypted automatically on the target machine using its private SSH keys. The decrypted secrets are then mounted to a well-known location on the filesystem, making them accessible to services or configuration without exposing them in the store or config files in plaintext.
This design tightly integrates with Nix’s declarative configuration and package management model. Since the secrets are stored as encrypted artifacts in the Nix store, they benefit from the store’s immutability and content-addressed paths. The decryption step on activation ensures that secrets are never exposed in plaintext outside the target machine’s volatile runtime environment.
From a technology stack perspective, Agenix is implemented in Nix language and uses the age encryption tool, known for its simplicity and strong cryptographic guarantees. It relies on SSH keys for authentication, which is natural given NixOS’s typical system administration practices.
architectural clarity and tradeoffs in the codebase
What stands out technically is how Agenix treats secrets as first-class citizens in the Nix deployment pipeline without compromising security principles. This is not trivial since the Nix store is inherently immutable and often globally readable by design.
The codebase, while written in Nix language, is surprisingly clean and modular. It provides modules to be imported into NixOS configurations as well as a CLI for encrypting secrets conveniently. This dual interface caters well to both declarative system management and interactive secret creation.
One tradeoff is the reliance on SSH keys and the age ecosystem. While this fits well within the NixOS admin workflow, it may not suit setups that use other secret management backends or key management systems. Additionally, the decrypted secrets exist on the target machine only at runtime and must be handled with care by consuming services.
Another consideration is that while the approach avoids plaintext secrets in the store, it requires managing private keys securely on all target machines. This is standard practice but worth highlighting.
Overall, the code quality and documentation provide a decent developer experience (DX). The Nix modules abstract away complexity, and the CLI commands are straightforward, making it accessible for Nix users familiar with the ecosystem.
quick start with agenix
Installation
Install via niv
$ niv add ryantm/agenix
Install module via niv
{
imports = [ "${(import ./nix/sources.nix).agenix}/modules/age.nix" ];
}
Install home-manager module via niv
{
imports = [ "${(import ./nix/sources.nix).agenix}/modules/age-home.nix" ];
}
Install CLI via niv
{
environment.systemPackages = [ (pkgs.callPackage "${(import ./nix/sources.nix).agenix}/pkgs/agenix.nix" {}) ];
}
Install via nix-channel
As root run:
$ sudo nix-channel --add https://github.com/ryantm/agenix/archive/main.tar.gz agenix
$ sudo nix-channel --update
Install module via nix-channel
{
imports = [ <agenix/modules/age.nix> ];
}
Install home-manager module via nix-channel
{
imports = [ <agenix/modules/age-home.nix> ];
}
Install CLI via nix-channel
{
environment.systemPackages = [ (pkgs.callPackage <agenix/pkgs/agenix.nix> {}) ];
}
Install via fetchTarball
Install module via fetchTarball
{
imports = [ "${builtins.fetchTarball "https://github.com/ryantm/agenix/archive/main.tar.gz"}/modules/age.nix" ];
}
or with pinning:
{
imports = let
# replace this with an actual commit id or tag
commit = "298b235f664f925b433614dc33380f0662adfc3f";
in [
"${builtins.fetchTarball {
url = "https://github.com/ryantm/agenix/archive/${commit}.tar.gz";
# update hash from nix build output
sha256 = "";
}}/modules/age.nix"
];
}
Install home-manager module via fetchTarball
Add the relevant import similarly as above.
verdict: a solid fit for nixos users who want reproducible secret management
Agenix offers a practical and elegant solution for managing secrets securely in NixOS environments. By combining age encryption with SSH keys and integrating directly into the Nix declarative system, it resolves a common pain point around secret distribution and lifecycle.
It is best suited for users already invested in NixOS and familiar with Nix language and SSH key management. The approach requires trust and good practices around private key security on target machines, which is standard but crucial.
While it won’t replace full-featured secret management systems that integrate with cloud providers or hardware security modules, Agenix fills a niche where secrets need to be packaged and deployed alongside system configuration in a reproducible, auditable way.
For anyone running NixOS in production or managing multiple machines declaratively, Agenix is worth a look. The code quality and documentation strike a good balance between flexibility and usability, and the design aligns well with NixOS principles.
Related Articles
- Syncthing: secure, decentralized continuous file synchronization in Go — Syncthing is an open-source Go tool for continuous, secure, decentralized file synchronization across devices, emphasizi
- Browser Harness: a self-healing LLM agent for browser automation via Chrome DevTools — Browser Harness enables LLMs to automate browsers by dynamically generating helper functions using the Chrome DevTools P
- OpenAI Codex CLI: local-first AI coding assistant with ChatGPT integration — OpenAI Codex CLI brings AI coding assistance local to your terminal, integrating with ChatGPT plans for powerful hybrid
- Polaris: A provider-agnostic feature flag and config management tool in Go — Polaris is a Go library that abstracts feature flag and configuration management across providers via clean interfaces.
- PinchTab: Token-efficient Chrome automation for AI agents with Go — PinchTab is a Go HTTP server enabling AI agents to control Chrome instances efficiently by extracting structured text, c
→ GitHub Repo: ryantm/agenix ⭐ 2,320 · Nix