agenix icon indicating copy to clipboard operation
agenix copied to clipboard

Documentation improvements

Open ruro opened this issue 3 years ago • 3 comments

I find the current documentation to be a bit lacking. There is no link to further documentation in the README, so I am assuming that the README is the full documentation.

Here are some questions that are (imho) not fully addressed in the readme:

  1. agenix has a CLI and a NixOS module. What's the purpose of each component? It seems, that the CLI handles encryption and the NixOS module handles the decryption, but this is not clear.

    It is mentioned in the first line of the documentation, but later parts of the documentation just use "agenix" to refer both to the CLI and the NixOS module, so it can be confusing, which component is being described.

  2. Assuming that my understanding of (1) is correct, what does the CLI provide over plain age/rage? Can I just encrypt my secrets with plain age (or with something like git-agecrypt) and then decrypt them at system startup with the agenix.nixosModule?

    Also, the first line of the documentation seems to imply, that the NixOS module is a secondary part of the project. This seems a bit backwards to me. If my understanding is correct, the CLI would be basically useless without the NixOS module.

  3. The tutorial suggests, that you should "Make a directory to store secrets and secrets.nix", but it is not clear

    • Is creating this directory merely a suggestion, or does the NixOS module explicitly rely on this layout (even though age.secrets.<name>.file seems to accept arbitrary paths)?

    • Where should you create this directory? In the system flake repository? On the development machine (that will encrypt the secrets)? On the deployment machine (that will decrypt the secrets)?

    • Is this directory used by the agenix CLI or the NixOS module, or both?

  4. The documentation states that SSH keys are supported as identity files, but GPG isn't. age also has its own key mechanism (AGE-SECRET-KEY-... and age1...). Is this type of key supported?

  5. At which point in the boot process are the secrets decrypted?


P.S. The Installation section takes up way too much space and for most users 75% of it won't be actually useful to them. Consider using <details><summary>blah</summary>contents</details> in some parts of the documentation. Something like this:

Install via niv

First add it to niv:

$ niv add ryantm/agenix

Install module via niv

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

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

Install CLI via niv

To install the agenix binary:

{
  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

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

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

Install CLI via nix-channel

To install the agenix binary:

{
  environment.systemPackages = [ (pkgs.callPackage <agenix/pkgs/agenix.nix> {}) ];
}

Install via fetchTarball

Install module via fetchTarball

Add the following to your configuration.nix:

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

Install CLI via fetchTarball

To install the agenix binary:

{
  environment.systemPackages = [ (pkgs.callPackage "${builtins.fetchTarball "https://github.com/ryantm/agenix/archive/main.tar.gz"}/pkgs/agenix.nix" {}) ];
}

Install via Flakes

Install module via Flakes

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

Install CLI via Flakes

You don't need to install it,

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

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

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

ruro avatar Jan 17 '23 14:01 ruro

I'll answer your questions here, but I intend to incorporate this into the docs too eventually.

  • agenix has a CLI and a NixOS module. What's the purpose of each component? It seems, that the CLI handles encryption and the NixOS module handles the decryption, but this is not clear.

This project provides a NixOS module age for adding age-encrypted secrets into the Nix store and decrypting them on NixOS at boot or rebuild time. It also provides a commandline tool agenix which can be used to edit and rekey the secrets and manage who can decrypt them. The documentation mostly assumes you are encrypting the secrets with your SSH keys, but all age methods can be used.

  • Assuming that my understanding of (1) is correct, what does the CLI provide over plain age/rage? Can I just encrypt my secrets with plain age (or with something like git-agecrypt) and then decrypt them at system startup with the agenix.nixosModule?

Yes, you can encrypt your secrets with plain age. You need to make sure you encrypt it such that both your user and system age identities can decrypt them.

Also, the first line of the documentation seems to imply, that the NixOS module is a secondary part of the project. This seems a bit backwards to me. If my understanding is correct, the CLI would be basically useless without the NixOS module.

Correct, the module is critical and the cli is technically optional.

  • The tutorial suggests, that you should "Make a directory to store secrets and secrets.nix", but it is not clear

    • Is creating this directory merely a suggestion, or does the NixOS module explicitly rely on this layout (even though age.secrets.<name>.file seems to accept arbitrary paths)?

Merely a suggestion. The module does not rely on this layout.

  • Where should you create this directory? In the system flake repository? On the development machine (that will encrypt the secrets)? On the deployment machine (that will decrypt the secrets)?

I typically make the secrets directory next to my configuration. So I guess the default vanilla way would be to put it at /etc/nixos/secrets.

  • Is this directory used by the agenix CLI or the NixOS module, or both?

The agenix CLI uses it, in the sense that you must run the cli from a directory that contains a secrets.nix file, but the encrypted secrets don't need to be in that directory. The module doesn't care about the secrets.nix at all.

  • The documentation states that SSH keys are supported as identity files, but GPG isn't. age also has its own key mechanism (AGE-SECRET-KEY-... and age1...). Is this type of key supported?

All default age identities are supported.

  • At which point in the boot process are the secrets decrypted?

The age module's activation scripts run after the "specialfs" activation scripts, and don't finish until after the "users" and "groups" activation scripts have finished.

ryantm avatar Jan 29 '23 22:01 ryantm

Add-on Q:

Currently the documentation emphasizes, re: secrets/secrets.nix:

This file is not imported into your NixOS configuration

The bold makes me think this is an important point -- is it? It's literally just a mapping of (non-secret) public keys to filenames, I wouldn't think it would matter if it were imported to the configuration (and hence the store).

I use a flake which defines several systems; for purity this requires all referenced files to be in the git repo, so my current setup is:

flake.nix
...
secrets/secrets.nix
secrets/secret1.age

All of which will be included in my repo, which is fine because none of it is ~"secret"~ secret and unencrypted. Is that correct?

If so, I might propose some clarification that makes it explicit:

The contents of secrets/*.age are encrypted and secrets/secrets.nix are public, so secrets can reasonably be checked into VCS if it contains no other private files.

n8henrie avatar Jan 30 '23 15:01 n8henrie

You need to make sure you encrypt it such that both your user and system age identities can decrypt them.

By "system identity" I assume you mean the ones specified in age.identityPaths, but what is the "user identity" in this case and why is it needed?

Where should you create this directory? In the system flake repository? On the development machine (that will encrypt the secrets)? On the deployment machine (that will decrypt the secrets)?

I typically make the secrets directory next to my configuration. So I guess the default vanilla way would be to put it at /etc/nixos/secrets.

So, please correct me if I am wrong, the "minimal" usage with separate build/target systems would be

  1. [on the build system] Encrypt some secret file foo and store the resulting file bar.age somewhere (inside the repo in case of flakes)

  2. [on the build system] Build the NixOS system derivation with age.secrets.foo.file = ./path/to/bar.age; (optionally set age.identityPaths = [ /custom/path/to/identity ];)

  3. [on the target system] Ensure that /etc/ssh/ssh_host_*_key (or /custom/path/to/identity if identityPaths were set) exist and can decrypt bar.age

  4. [on the target system] Push the derivation to target system and switch/reboot into it

Crucially, the build system doesn't need to be able to decrypt the secrets (no /etc/ssh/ssh_host_*_key or /custom/path/to/identity) and the target system doesn't need to have bar.age stored anywhere (no /etc/nixos/path/to/bar.age for example). Is this correct?

ruro avatar Jan 30 '23 16:01 ruro