Nix with Flakes allows you to easily centralize project environments and setup right in your repository. Often, your README will tell the reader "get an API key for FOOSERVICE from a teammate"
Just like NixOS modules and home-manager, we can use Agenix to encrypt and store secrets without exposing them to our git repository.
1. flake-parts
The easiest way to use Agenix with devShells is to use the agenix-shell module for flake-parts.
Let's start with a basic flake using flake-parts.
{ description = "Agenix example for devShells"; inputs = { nixpkgs.url = "github:nixos/nixpkgs?ref=nixos-unstable"; + flake-parts.url = "github:hercules-ci/flake-parts"; }; - outputs = { self, nixpkgs }: + outputs = { self, nixpkgs, flake-parts }: + flake-parts.lib.mkFlake {inherit inputs;} { + imports = []; + systems = ["x86_64-linux" "aarch64-linux" "aarch64-darwin" "x86_64-darwin"]; + perSystem = { pkgs, ... }: { + devShells.default = pkgs.mkShell { + packages = []; + }; + }; + } + }; }2. Add Agenix and agenix-shell
Lets add flake-parts and the agenix-shell module.
{ description = "Agenix example for devShells"; inputs = { nixpkgs.url = "github:nixos/nixpkgs?ref=nixos-unstable"; flake-parts.url = "github:hercules-ci/flake-parts"; + agenix.url = "github:ryantm/agenix"; + agenix-shell.url = "github:aciceri/agenix-shell"; }; - outputs = { self, nixpkgs, flake-parts }: + outputs = { self, nixpkgs, flake-parts, agenix, agenix-shell }: flake-parts.lib.mkFlake {inherit inputs;} { - imports = []; + imports = [ + agenix-shell.flakeModules.default + ]; systems = ["x86_64-linux" "aarch64-linux" "aarch64-darwin" "x86_64-darwin"]; - perSystem = { pkgs, ... }: { + perSystem = { pkgs, config, lib ... }: { devShells.default = pkgs.mkShell { - packages = []; + packages = [agenix.packages.${system}.default]; + shellHook = '' + source ${lib.getExe config.agenix-shell.installationScript} + ''; }; }; } }; }3. Configure your secrets recipients
You can reference the section we described last time.
This time, we're going to encrypt a file called api-keys.age.
4. Create your secrets files
Create your secrets files by running agenix -e <key-name>.age in the same directory as secrets.nix. Fill them in with the relevant values.
# service-a-api-key.age foo5. Use your secrets{ description = "Agenix example for devShells"; inputs = { nixpkgs.url = "github:nixos/nixpkgs?ref=nixos-unstable"; flake-parts.url = "github:hercules-ci/flake-parts"; agenix.url = "github:ryantm/agenix"; agenix-shell.url = "github:aciceri/agenix-shell"; }; outputs = { self, nixpkgs, flake-parts, agenix, agenix-shell }: flake-parts.lib.mkFlake {inherit inputs;} { imports = [ agenix-shell.flakeModules.default ]; systems = ["x86_64-linux" "aarch64-linux" "aarch64-darwin" "x86_64-darwin"]; + agenix-shell = { + secrets = { + SERVICE_A_API_KEY.file = ./service-a-api-key.age; + SERVICE_B_API_KEY.file = ./service-b-api-key.age; + SERVICE_C_API_KEY.file = ./service-c-api-key.age; + }; + }; perSystem = { pkgs, config, lib ... }: { devShells.default = pkgs.mkShell { packages = [agenix.packages.${system}.default]; shellHook = '' source ${lib.getExe config.agenix-shell.installationScript} ''; }; }; } }; }
Your local project secrets are now available when you enter your devShell with nix develop.
Wrapping Up
Agenix seemed complicated to me at first, but once I got it set up up in the three usual scenarios (NixOS, home-manager, and devShells), its simplicity came to light.
I hope this series helps you take advantage of Agenix as well.