oddlama / agenix-rekey

An agenix extension adding secret generation and automatic rekeying using a YubiKey or master-identity
MIT License
197 stars 16 forks source link

agenix edit produces error about "not producing attribute." #27

Closed YaroKasear closed 3 months ago

YaroKasear commented 3 months ago

I am having trouble getting started using this. I managed to set up my identity information and pubkeys for one of my systems.

I try to create a test secret, but when I run agenix edit I get the following:

error: flake 'git+file:///home/yaro/flakes' does not provide attribute 'apps.x86_64-linux.agenix-rekey.x86_64-linux.edit', packages.x86_64-linux.agenix-rekey.x86_64-linux.edit', 'legacyPackages.x86_64-linux.agenix-rekey.x86_64-linux.edit' or 'agenix-rekey.x86_64-linux.edit'

I don't see anything in the readme about this attribute, so I'm really confused that this means. I admit I don't know much about agenix, as I'm coming from sops-nix.

oddlama commented 3 months ago

Oh I'm sorry, that was kind of my mistake 😅 I've added support for flake-parts today and in between there was a broken commit that you seem to have run into.

If you update your inputs the error should go away.

YaroKasear commented 3 months ago

This seems to have worked. Now I'm just figuring out how this all works! Thank you.

YaroKasear commented 3 months ago

Actually, I'd like to reopen this issue even if I'm having a new problem. I don't think I'd like to clutter your issues tracker.

The agenix rekey command doesn't seem to be looking relative to root but relative to the file I configured this system's localStorageDir, causing it to look in a place that doesn't exist:

error: Cannot determine true origin of /nix/store/d6l43phvk6n2dnhpzcqv0ac68a24maqh-modules/nixos/common/systems/x86_64-linux/loki/secrets which doesn't seem to be a direct subpath of the flake directory /nix/store/mbr2d9dvkmmmgpi5yal101lxldvy4935-source. Did you make sure to specifyage.rekey.localStorageDirrelative to the root of your flake?

I configured this in a module in ./modules/nixos/common/default.nix:

age.rekey = {
  localStorageDir = ./. + "/systems/${pkgs.system}/${config.networking.hostName}/secrets";
  masterIdentities = [ ./files/yubikey.pub ];
  storageMode = "local";
};

But if I understand this error correctly, putting aside the non-matching hash in the name, it's trying to look in ./modules/nixos/common/systems/x86_64-linux/loki/secrets to place the file instead of where I assume it should be doing based on the documentation's instructions: ./systems/x86_64-linux/loki/secrets.

Do I have this wrong?

YaroKasear commented 3 months ago

Okay, I "fixed" this by changing localStorageDir to inputs.self + "/systems/${pkgs.system}/${config.networking.hostName}/secrets"

I'm not sure if this is because I'm using snowfall-lib or not.

YaroKasear commented 3 months ago

Yeah, I'm really struggling to make this work. I can't use any relative paths with this because the agenix command will look in the wrong output folder for the secret instead of my flake root, and agenix generate took a lot of coercing to generate the file, which agenix rekey immediately deleted, saying it was an "orphan."

I'd really like to be able to replace sops-nix with this, but following the documentation doesn't seem to be working for me.

oddlama commented 3 months ago

The paths seem a little fragile unfortunately, because the script must be able to know where your secrets are placed relative to your flake root (otherwise it cannot generate the files or place the new files there).

The crucial part to make this work is to never use toString on a path, and this includes string interpolations. So "${somePath}/a/b" would call toString somePath which is bad, because the path will then be copied to the nix store again under a new name. If you need to concatenate, always use `somePath + "/relative/path" as this will not trigger a re-copy.

So the rekeyFile should always be either a normal relative path like rekeyFile = ./a/b/something.age or a compound where you use somePath + "/relative/part". Of course you may string interpolate other stuff like the hostName.

oddlama commented 3 months ago

I've found your flake in your profile. From what I can tell you are using the path concatenation correctly. But your secrets are getting cleaned by the orphaned file remover because you are using the same local storage directory for two distinct hosts (loki and loki-xorg).

You are telling agenix-rekey to rekey files for both of them, because they are two distinct hosts in nixosConfigurationsm which is passed to agenix-rekey. So agenix-rekey must be able to assume that their local storage directories are different too.

You can now either A) tell agenix-rekey about only one of them, if they are indeed the same host with the same ssh private key or B) just make sure that the localStorageDir is set to a different value for each of them.

B is probably the simpler and more robust solution.

YaroKasear commented 3 months ago

These are all helpful. I'm going to shore up my localStorageDir and probably get rid of loki-xorg. Same machine, different profile for gaming due to using nVidia on Wayland, but with new stuff coming down to Wayland I might not need it anymore.

Thanks for bearing with me.

YaroKasear commented 3 months ago

I think it works! Just want to confirm, is this what I want to see?

Screenshot_20240530_085718

EDIT: I'm not sure it is, because trying to run the flake after this causes it to complain it can't find test.age, so I think I'm still getting something wrong here. It says it's removing the original test.age as an orphan, then puts that file down. Was it supposed to be renaming it?

oddlama commented 3 months ago

The localStorageDir must not be the same as the one where you are storing your original secrets

YaroKasear commented 3 months ago

The localStorageDir must not be the same as the one where you are storing your original secrets

I just discovered that and was about to comment. I'm going to adjust my flake here. Again, thanks for bearing with me.

oddlama commented 3 months ago

No worries, maybe a warning should be in place there. Your original secrets are the only thing that should be important to you, the local storage dir is more or less a implementation detail. Maybe I should add a sensible default for it.

YaroKasear commented 3 months ago

No worries, maybe a warning should be in place there. Your original secrets are the only thing that should be important to you, the local storage dir is more or less a implementation detail. Maybe I should add a sensible default for it.

Looks like I got it working. I took a look inside its dedicated mount and found the decrypted secret there. Does this support home-manager at all? I'm sure it's not a big deal if it doesn't since I'm sure I can make changes to ownership/permissions on secrets if needed.

oddlama commented 3 months ago

Currently there's only a NixOS module, but if you are using home manager together with nixos you can definitely just set the correct owner on the NixOS secret and use it inside home manager.

Home-manager only configurations would be a problem right now, that's definitely something we'd need to address in the future.

YaroKasear commented 3 months ago

Thanks, I've got this working. I have one last question.

I notice you encourage one doesn't put their rekeyed age files in their git repository. This becomes a problem since Nix refuses to evaluate any files in a Flake NOT in a git repo. I tried putting a .gitignore file in there so it won't go up to Github from my main machine whenever I use agenix rekey, but now Nix complains about not finding the rekeyed files because they can't be added to Git.

Is there a solution to this or am I going to have to maintain my Flake separately from my deployment of that Flake on the same machine, which is a bit of a pain?

oddlama commented 3 months ago

I notice you encourage one doesn't put their rekeyed age files in their git repository.

Oh, I did? Can you tell me where? I should probably revise that because it's not inherently a bad thing. There is technically a solution to this, but it is usually a bad tradeoff.

I would even say that I would explicitly encourage people to track the rekeyed files in git, since they are still properly encrypted at all times. This would only become a problem if only of one of your private ssh host keys leaks, in which case an attacker can decrypt the published secrets. But if the attacker has access to your private ssh host key, they must have had root access to your machine anyway, and could've read all secrets from /run/agenix. So this only puts secrets at risk that were once used at a previous point in time but are no longer used at the time of the attack. So not a lot of additional risk. Also classical agenix also requires you to do that, and the workaround explained below still stores them in the world readable nix store. So the benefits are very very slim :P

Anyhow: The local storage mode explicitly wants you to track your files in git, because crucially this allows anyone to build your system derivation without having access to your yubikey, as long as the secrets are not changed. This makes a lot of things easy and predictable. It is now trivially possible to update your system and build it in a CI without needing any kind of private key, because all rekeyed secrets are already there. Other users can clone your flake and view all outputs. The downside is just that there is that theoretical scenario in which an attacker could gain access to old secrets as explained above. But emphasis is on theoretical, I don't think this is a practical attack vector.

If you deem that scenario to be a legit threat for whatever reason, there is a second "derivation" storage mode (see readme) which, as the name suggests, uses a derivation to store the rekeyed secrets (thus circumventing git entirely). But this has two big caveats:

  1. Rekeying is inherently an impure operation (it requires USB access), and thus you need to build the rekeying derivation without a sandbox. agenix rekey automatically does that if that storage mode is selected, but this means it cannot happen automatically as part of nix build. It also has the side effect that you now have to specify the architecture of the system on which you rekey (e.g. x86_64-linux) because a bash script derivation that produces the same output has different store paths depending on the architecture (because the bash input would be different). So if you have two development machines with different architectures, you will have a problem that cannot be solved right now (we would need CA-derivations to solve this).
  2. Since only your local system can create the derivations, you will run into problems when using remote builders. You always have to rekey and copy the resulting derviations to your builder beforehand to prevent it from trying to build it itself (as that would fail because your builder has no access to your yubikey).

If you have a very simple setup and only develop on one type of machine, then the derivation storage mode is just as easy to use, but you will be restricted in certain aspectes. This is really just borderline possible with nix and can lead to problems down the line, which is why the local storage mode got added.

(Oh a third solution would of course be to use a second private git repository that contains your secrets and is cloned as a subdirectory. That would still break flake evaluation for others but at least doesn't have the impurity downsides)

So if you have a choice I'd always recommend sticking to the local storage mode. Feel free to ask more questions if you have any :)

YaroKasear commented 3 months ago

My bad, I think I misinterpreted something, now that I can't seem to find it in the README.

It does rekey and deploy secrets! Hooray! Except it fails on boot, so I'm trying to find why. My leading hunch is impermanence is putting persistent data in after agenix-rekey is supposed to be decrypting the secrets, so there's no private key yet for agenix-rekey to use. Unless you think it could be something else.

oddlama commented 3 months ago

Yeah, if you use impermanence you probably want something like this: https://github.com/oddlama/nix-config/blob/1424778bc2bc5213f8d66e48464b153658be4323/config/impermanence.nix#L18-L19 (not related to rekeying though :) )

YaroKasear commented 3 months ago

That fixed it. I'm now properly using agenix-rekey. Thanks for guiding me here.