age-encrypted secrets for NixOS
Find a file
Ryan Mulligan c89ed72dc6 rename public_keys to publicKeys
more idiomatic
2020-09-03 21:13:10 -07:00
example rename public_keys to publicKeys 2020-09-03 21:13:10 -07:00
example_keys add README and examples 2020-09-03 13:16:44 -07:00
modules fix description of secretType.path 2020-09-03 13:41:45 -07:00
pkgs rename public_keys to publicKeys 2020-09-03 21:13:10 -07:00
default.nix add flake and default .nix files; add agenix command 2020-09-03 11:24:33 -07:00
flake.lock add flake and default .nix files; add agenix command 2020-09-03 11:24:33 -07:00
flake.nix add flake and default .nix files; add agenix command 2020-09-03 11:24:33 -07:00
LICENSE initial prototype 2020-08-31 21:37:26 -07:00
README.md rename public_keys to publicKeys 2020-09-03 21:13:10 -07:00

agenix

age-encrypted secrets for NixOS.

It consists of a NixOS module age, and a CLI tool called agenix used for editing and rekeying the secret files.

Features

  • Secrets are encrypted with SSH keys
  • No GPG
  • Very little code, so it should be easy for you to audit
  • Encrypted secrets are stored in the Nix store, so a separate distribution mechanism is not necessary

Installation

Choose one of the following methods:

niv (Current recommendation)

First add it to niv:

$ niv add ryantm/agenix

Module

Then add the following to your configuration.nix in the imports list:

{
  imports = [ "${(import ./nix/sources.nix).agenix}/modules/age" ];
}

nix-channel

As root run:

$ nix-channel --add https://github.com/ryantm/agenix/archive/master.tar.gz agenix
$ nix-channel --update

Than add the following to your configuration.nix in the imports list:

{
  imports = [ <agenix/modules/age> ];
}

fetchTarball

Add the following to your configuration.nix:

{
  imports = [ "${builtins.fetchTarball "https://github.com/ryantm/agenix/archive/master.tar.gz"}/modules/age" ];
}

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";
      # replace this with an actual hash
      sha256 = "0000000000000000000000000000000000000000000000000000";
    }}/modules/age"
  ];
}

Flakes

Module

{
  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.age
      ];
    };
  };
}

CLI

You don't need to install it:

nix run github:ryantm/agenix -- --help

if you want to (change the system based on your system):

{
  environment.systemPackages = [ agenix.defaultPackage.x86_64-linux ];
}

Tutorial

  1. Make a directory to store secrets and secrets.nix file for listing secrets and their public keys:

    $ mkdir secrets
    $ cd secerts
    $ touch secrets.nix
    
  2. Add public keys to secrets.nix file (hint: use ssh-keyscan or GitHub (for example, https://github.com/ryantm.keys)):

    let
      user1 = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIL0idNvgGiucWgup/mP78zyC23uFjYq0evcWdjGQUaBH";
      system1 = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPJDyIr/FSz1cJdcoW69R+NrWzwGK/+3gJpqD1t8L2zE";
    in
    {
      "secret1.age".publicKeys = [ user1 system1 ];
      "secret2.age".publicKeys = [ user1 ];
    }
    
  3. Edit secret files (assuming your SSH private key is in ~/.ssh/):

    $ agenix -e secret1.age
    
  4. Add secret to NixOS module config:

    age.secrets.secret1.file = ../secrets/secret1.age;
    
  5. NixOS rebuild or use your deployment too like usual.

Rekeying

If you change the public keys in secrets.nix, you should rekey your secrets:

$ agenix --rekey

To rekey a secret, you have to be able to decrypt it. Because of randomness in age's encryption algorithms, the files always change when rekeyed, even if the identities do not. This eventually could be improved upon by reading the identities from the age file.

Threat model/Warnings

This project has not be audited by a security professional.

People unfamiliar with age might be surprised that secrets are not authenticated. This means that every attacker that has write access to the repository can modify secrets because public keys are exposed. This seems like not a problem on the first glance because changing the configuration itself could expose secrets easily. However it is easier to review configuration changes rather than random secrets (for example 4096-bit rsa keys). This would be solved by having a message authentication code (MAC) like other implementations like GPG or sops have, however this was left out for simplicity in age.

Acknowledgements

This project is based off of sops-nix created Mic92. Thank you to Mic92 for inspiration and help with making this.