ryantm / agenix

age-encrypted secrets for NixOS and Home manager
https://matrix.to/#/#agenix:nixos.org
Creative Commons Zero v1.0 Universal
1.57k stars 120 forks source link

Better support for identities on yubikeys #115

Open antifuchs opened 2 years ago

antifuchs commented 2 years ago

I was trying to use age-plugin-yubikey with rage to create a key that doesn't live on my file system. This works, but not completely conveniently all the way: agenix happily encrypts to the identity on my yubikey, but then fails to decrypt when editing the existing secret unless you create an "identity" file containing the handle that lives on the yubikey.

I'm opening this (effectively non-)issue to help others along who are trying to use yubikeys with agenix.

Guide

You'll need:

Here's an example secrets.nix:

let
  machines = {
    monitor = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINmveI8P/aqICzkZ+2nTxbV7RB5/ZEsgsxZmC3IajYxL root@ubuntu-s-1vcpu-1gb-nyc3-01"; # A normal SSH ed25519 key.
  };

  users = {
    personal-4c = "age1yubikey1q0m3cprmex0d2thamkx9pwvhsqwcm2gel50rdxmeclvkgqtem9dxz4smpwv"; # the public key
  };
in
{
  "test.age".publicKeys = [ users.personal-4c machines.monitor ];
}

Then, write the identity to a file in your secrets folder. I named it secrets/identities/personal-4c.txt:

$ mkdir -p identities && echo AGE-PLUGIN-YUBIKEY-3XXXXXXXXXX3XX3XXXXXX > identities/personal-4c.txt

Then, you can edit the secret like so:

$ agenix -e test.age --identity identities/personal-4c.txt

As explained in https://github.com/str4d/age-plugin-yubikey/issues/73, these yubikey identities are "key grips", encoding a serial number of the yubikey and some other identifiers, but no secret bits. It's fine to store them in the repo, but here's the ask I have for agenix: Would it be possible to use age-plugin-yubikey --list-all or --identity to retrieve any connected identities, if they correspond to any public keys that are connected to the machine, so that we don't have to explicitly pass the --identity flag?

kolpav commented 1 year ago

Just to make sure in the permutation tesseract of how to easily manage secrets in nixos project where columns would be something like

| rage/age/agenix/sops-nix | flake |gpg/[open]ssh/ssh-to-gpg | yubikey + piv | pgp | fido2 | otp | ecdsa | ecdsask | ed25519 | ed25519sk

I am row agenix, flake, ssh, yubikey, fido2, sk-ssh-ed25519 which is not supported right?

~ nix run github:ryantm/agenix -- -e test.age --identity secrets/identities/personal-4c.txt
Error: Unsupported SSH key: ⁨⁩

Unsupported SSH Key Type
------------------------
OpenSSH supports various different key types, but rage only supports a
subset of these for backwards compatibility, specifically the 'ssh-rsa'
and 'ssh-ed25519' key types. This SSH key uses the unsupported key type
'⁨sk-ssh-ed25519⁩'.

Are there more pages (nix wiki, all projects I mentioned, yubikey docs) I need to read or tools to install to make this work or I am out of luck?

dghubble commented 10 months ago

Like the OP, I used an age public key and noticed the identity file has to be passed on every invocation of agenix. Maybe it would be better if we could add something like the module's identityPaths, but to the secrets.nix file. A way to tell agenix to always consider a particular identity without having to set it on the command line. Right now the rules parser isn't really setup for this, but it might look like:

# hypothetical syntax
let
  myself = "age1yubikey...";
in
{
  "foo.age".publicKeys = [ myself ];
  identityPaths = [ "../identity.txt" ];
}
TRPB commented 5 days ago

Thanks for this. I must be missing something here.

I've set up my identity and encrypted I've added my key using ssh-add -K to load the key, configured the public key using the age1yubikey... value and I can successfully decrypt and re-encrypt the age file using agenix -e test.age --identity identities/yubikey1.txt

But, when I nixos-rebuild switch I get no identity matched any of the recipient. Do I need to somehow pass the identity at this stage as well?

edit: RTFM, I need to set `age.identityPaths = [ "/path/to/yubikey1.txt" ]

But, when I do that I get:

age: error: yubikey plugin: couldn't start plugin: age-plugin-yubikey resolves to executable in current directory

I have age-plugin-yubikey installed via envrionment.systemPackages so I don't understand what this error means

resolved by this post: https://discourse.nixos.org/t/agenix-ragenix-issues-with-age-plugin-yubikey-and-the-mysterious-age-plugin-yubikey-resolves-to-executable-in-current-directory-error/46890

But now I'm getting A PIN is required for YubiKey with serial

agenix is asking for the pin but I can't enter it

so... if I:

  1. agenix -e test.age --identity identities/yubikey1.txt
  2. Enter the pin and press the yubikey
  3. Leave the edtior open
  4. nixos-rebuild switch

It builds successfully and the secret is available.

I checked the pin policy and it's set to once:

PIN policy: Once   (A PIN is required once per session, if set)

It seems to be that nixos-rebuild doesn't support being dropped to user input to allow entering the pin

edit: And the answer to that one is to make sure you use age, not rage:

  age.ageBin = "PATH=$PATH:${lib.makeBinPath [ pkgs.age-plugin-yubikey ]} ${pkgs.age}/bin/age";

it asks for the pin and waits for the yubikey to be pressed when running nixos-rebuild switch