agenix

repository·main·Indexed 25 days ago

https://github.com/ryantm/agenix

A Nix library for managing and deploying secrets using age-encryption and existing SSH key infrastructure. It provides a CLI for encrypting secrets into .age files and NixOS/Home Manager modules to automatically decrypt and mount these secrets on target machines.

Tokens
7.8K
Snippets
32
Records
43
Agent score
80%

What's inside agenix

  1. What is agenix?

    main

    agenix is a Nix library designed for securely managing and deploying secrets in NixOS using age encryption and existing SSH key infrastructure. It consists of two main components:

    1. agenix CLI: A command-line application used to encrypt secrets into .age files. These encrypted files can be safely stored in the Nix store.
    2. agenix NixOS Module: A module that integrates with NixOS to:
      • Add encrypted .age files to the Nix store.
      • Automatically decrypt secrets on target machines using the local private SSH keys.
      • Automatically mount decrypted secrets at a predictable path, typically /run/agenix/....
  2. Store encrypted secrets in the Nix store

    main
    Encrypted secrets are stored directly in the Nix store. This design eliminates the need for a separate distribution mechanism for your secret files, as they are managed alongside your Nix configuration.
  3. Understand the security implications of unauthenticated secrets in agenix

    main

    Because agenix relies on age, secrets are not authenticated. This means that any attacker with write access to your secret files can modify the contents of those secrets because public keys are exposed.

    While this allows for secret modification, the risk is mitigated in practice because:

    1. Modifying a secret (like a large RSA key) is harder to do unnoticed than modifying configuration files.
    2. Reviewing configuration changes is generally easier than reviewing the integrity of raw secret blobs.

    Unlike GPG or sops-nix, age does not use a Message Authentication Code (MAC) to prevent tampering, a design choice made for simplicity.

  4. Encrypt secrets using SSH keys

    main
    agenix uses age for encryption, allowing you to secure secrets using SSH keys instead of GPG. You can use system public keys (retrieved via ssh-keyscan) or public keys hosted on platforms like GitHub (e.g., https://github.com/ryantm.keys) to define which identities can decrypt the secrets.
  5. How agenix manages secrets in NixOS

    main

    In NixOS, the Nix store is globally readable, making it unsuitable for cleartext secrets. agenix addresses this by encrypting secrets using age and your existing SSH key infrastructure.

    Instead of managing secrets out-of-band (which complicates deployment and auditing), agenix allows you to store encrypted secrets directly in the Nix store. These secrets are decrypted during NixOS system activation using an SSH host private key, ensuring that secrets are part of your reproducible Nix configuration while remaining secure.

  6. Install the agenix NixOS module via Flakes

    main

    To use agenix as a NixOS module in a Flake-based configuration, add the agenix input to your flake.nix and include agenix.nixosModules.default in your modules list.

    Note: You can optionally force agenix to follow your existing nixpkgs input by setting inputs.agenix.inputs.nixpkgs.follows = "nixpkgs";.

    {
      inputs.agenix.url = "github:ryantm/agenix";
      # optional, not necessary for the module
      #inputs.agenix.inputs.nixpkgs.follows = "nixpkgs";
    
      outputs = { self, nixpkgs, agenix }: {
        # change `yourhostname` to your actual hostname
        nixosConfigurations.yourhostname = nixpkgs.lib.nixosSystem {
          # change to your system:
          system = "x86_64-linux";
          modules = [
            ./configuration.nix
            agenix.nixosModules.default
          ];
        };
      };
    }
  7. Install the agenix CLI binary

    main

    To install the agenix command-line tool as a system package, use pkgs.callPackage pointing to the package definition within the channel. Add this to your environment.systemPackages in configuration.nix:

    { environment.systemPackages = [ (pkgs.callPackage <agenix/pkgs/agenix.nix> {}) ]; }
    {
      environment.systemPackages = [ (pkgs.callPackage <agenix/pkgs/agenix.nix> {}) ];
    }
  8. Install the agenix NixOS module via niv

    main

    After adding agenix to niv, you can import the NixOS module into your system configuration. This assumes you have a nix/sources.nix file that imports the niv generated sources. Add the path to modules/age.nix to your imports list in configuration.nix.

    { imports = [ "${(import ./nix/sources.nix).agenix}/modules/age.nix" ]; }
  9. Configure and use agenix secrets in NixOS

    main

    Once your secrets are created, you must register them in your NixOS configuration to ensure they are decrypted during deployment.

    1. Register the secret file in your NixOS module configuration using the age.secrets.<name>.file option:
    {
      age.secrets.secret1.file = ../secrets/secret1.age;
    }
    1. Access the decrypted secret in your configuration using config.age.secrets.<name>.path. By default, secrets are decrypted to /run/agenix/<name>.

    Example: Using a secret for a user's hashed password:

    {
      users.users.user1 = {
        isNormalUser = true;
        hashedPasswordFile = config.age.secrets.secret1.path;
      };
    }
  10. Install the agenix CLI via Flakes

    main

    To install the agenix CLI as a system package in a Flake-based NixOS configuration, add the package from the agenix input to your environment.systemPackages. Ensure you select the correct architecture for your system (e.g., x86_64-linux).

    {
      environment.systemPackages = [ agenix.packages.x86_64-linux.default ];
    }
  11. Use agenix in NixOS configuration

    main

    To use agenix in NixOS, add your .age files to the age.secrets attribute set. The agenix module will automatically decrypt and mount these secrets at /run/agenix/<secret_name>.

    1. Define the secret in your NixOS configuration:
    { 
      age.secrets.secret1.file = ../secrets/secret1.age; 
    }
    1. Reference the secret using config.age.secrets.<name>.path to access the unencrypted mount path:
    { 
      users.users.user1 = { 
        isNormalUser = true; 
        hashedPasswordFile = config.age.secrets.secret1.path; 
      };
    }
    {
      age.secrets.secret1.file = ../secrets/secret1.age;
    }
    
    {
      users.users.user1 = {
        isNormalUser = true;
        hashedPasswordFile = config.age.secrets.secret1.path;
      };
    }