Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Error while handling error of rekeyed file missing #15

Closed
LoganBarnett opened this issue Apr 3, 2024 · 6 comments
Closed

Error while handling error of rekeyed file missing #15

LoganBarnett opened this issue Apr 3, 2024 · 6 comments

Comments

@LoganBarnett
Copy link
Contributor

Hi! Thanks for your work on this repository :)

If I have a NixOS module with content like this:

{
  age.secrets.foo = {
    rekeyFile = ./some/bad/path.age;
  };
}

Where ./some/bad/path.age does not point to an existing file, I get:

       error: attribute 'name' missing

       at /nix/store/5rhp2fj4jrxr4cjd2j81v1fkqj7xcp0i-source/modules/agenix-rekey.nix:68:64:

           67|     assert assertMsg (secret.rekeyFile != null -> builtins.pathExists secret.rekeyFile) ''
           68|       host ${config.networking.hostName}: age.secrets.${secret.name}.rekeyFile (${toString secret.rekeyFile}) doesn't exist. ${generateHint}
             |                                                                ^
           69|     '';

I can kind of glean that I need to fix my path from this, but it also got me thinking maybe I am missing a name, so I have also tried:

{
  age.secrets.foo = {
    rekeyFile = ./some/bad/path.age;
    name = "foo";
  };
}

But I get the same error. I realize name is not in the documentation, but figured I'd try anyways. agenix itself has a name in its documentation, and it seems to get populated by inspecting its own arguments here. From there I'm not sure what additional threads to pull.

My flake.lock is pinned with these versions:

nixpkgs acdc68ae37415027dd38747b9bee5d10cbf57c0f
agenix 8cb01a0e717311680e0cbca06a76cbceba6f3ed6
agenix-rekey 5a4a617

If I ensure the path points to a file correctly, this error goes away. I am greeted with another error, but I believe it is unrelated to this and I have more work to do on that front.

Thanks for your time!

@oddlama
Copy link
Owner

oddlama commented Apr 3, 2024

I'm not entirely sure why this is happening. You are right, it should not be necessary to set name explicitly. As you already pointed out, the agenix snippet set's this to the attribute name of the secret (so foo in your case). But either way it should exist afterwards because it is a normal option in agenix with a default value.

I don't get that error when I try to reproduce this with

age.secrets.abc.rekeyFile = ./nonexistent.age;
┃        … while calling 'assertMsg'
┃ 
┃          at /nix/store/nra828scc8qs92b9pxra5csqzffb6hpl-source/lib/asserts.nix:41:5:
┃ 
┃            40|     pred:
┃            41|     msg:
┃              |     ^
┃            42|     pred || builtins.throw msg;
┃ 
┃        error: host kroma: age.secrets.abc.rekeyFile (/nix/store/h5iinq425fl90y715j5fyqsx8cjwwf68-source/hosts/test/nonexistent.age

Is there something special about your configuration in regards to agenix?

(Probably not related to this) I think I should have used secret.id which I introduced specifically to refer to the attribute name of the secret, in case the name is overridden by the user. But this should lead to the same error for you, because the id option is exactly the same as the name option.

I've now also adjusted how I refer to the secret internally, on the off-chance that it had to to with how I have passed the secret submodule options down into some internal functions. Could you check whether the problem still persists?

@LoganBarnett
Copy link
Contributor Author

Thanks for the speedy response!

I've done a nix flake lock --update-input agenix-rekey, which puts me on 85df729 (same as main right now).

Now I see an infinite recursion issue. Perhaps this is indicative of a poor setup on my part.

Here's the error, with the leading part truncated:

Somewhat large error:
       … while calling 'rekeyedLocalSecret'

         at /nix/store/r491wmas6ld9xmzxgz5h89avaf0b2l0z-source/modules/agenix-rekey.nix:49:24:

           48|
           49|   rekeyedLocalSecret = secret: let
             |                        ^
           50|     pubkeyHash = builtins.hashString "sha256" config.age.rekey.hostPubkey;

       … from call site

         at /nix/store/r491wmas6ld9xmzxgz5h89avaf0b2l0z-source/modules/agenix-rekey.nix:67:12:

           66|   in
           67|     assert assertMsg (secret.rekeyFile != null -> builtins.pathExists secret.rekeyFile) ''
             |            ^
           68|       host ${config.networking.hostName}: age.secrets.${secret.id}.rekeyFile (${toString secret.rekeyFile}) doesn't exist. ${generateHint}

       … while calling 'assertMsg'

         at /nix/store/2z8cnf34pyhlyjngmkxxvhi9kpmrnw4k-source/lib/asserts.nix:41:5:

           40|     pred:
           41|     msg:
             |     ^
           42|     pred || builtins.throw msg;

       … while calling anonymous lambda

         at /nix/store/2z8cnf34pyhlyjngmkxxvhi9kpmrnw4k-source/lib/types.nix:569:22:

          568|       merge = loc: defs:
          569|         mapAttrs (n: v: v.value) (filterAttrs (n: v: v ? value) (zipAttrsWith (name: defs:
             |                      ^
          570|             (mergeDefinitions (loc ++ [name]) elemType defs).optionalValue

       error: infinite recursion encountered

       at /nix/store/2z8cnf34pyhlyjngmkxxvhi9kpmrnw4k-source/lib/modules.nix:857:27:

          856|     optionalValue =
          857|       if isDefined then { value = mergedValue; }
             |                           ^
          858|       else {};

But! I did some debugging of my rekeyFile, and found something very incriminating:

    ({ lib, ... }: {
      age.secrets.civitai-token = {
        rekeyFile = (builtins.trace "civitai-token.age path" (lib.debug.traceVal ./. + ../secrets/rekeyed/lithium/civitai-token.age));
      };
    })
trace: civitai-token.age path
trace: /nix/store/gy1znwi7hsksddnv2rfwvx5xkiv5cga2-source/hosts

This seems very wrong to me. I would expect it to refer to a file, not a directory (hosts is where I store my nixosConfigurations and darwinConfigurations).

To confirm something odd wasn't written there:

[logan@lithium:~/proton-nix]$ ls /nix/store/gy1znwi7hsksddnv2rfwvx5xkiv5cga2-source/hosts
lithium.nix  M-CL64PK702X.nix  nucleus.nix  scandium.nix

Okay so that's my indeed my hosts. It looks like my paths aren't as correct as I thought they were. This is very likely an error on my end. I'll try to figure it out this evening and report back with any findings.

Thanks!

@LoganBarnett
Copy link
Contributor Author

My whole ./. + ../secrets/rekeyed/lithium/civitai-token.age stuff was at fault. It's been corrected and now the path prints as the age file itself in my Nix store. I'm still seeing the infinite recursion issue when it tries to print the error message that it cannot find the secret. If I look further up the trace, I also see this:

       … while evaluating the error message for definitions for `age.secrets.civitai-token.file', which is an option that does not exist

       … while evaluating a definition from `/nix/store/2z8cnf34pyhlyjngmkxxvhi9kpmrnw4k-source/flake.nix'

I do not set file, but instead rekeyFile:

  age.secrets.civitai-token = {
    rekeyFile = (builtins.trace "civitai-token.age path" (lib.debug.traceVal ../secrets/rekeyed/${host-id}/civitai-token.age));
  };

I understand this to be the preferred way to handle pointing at the age file with agenix-rekey (as opposed to vanilla agenix, that wants file).

From looking around in your personal configuration repo, I noticed that you don't set age.rekey.secrets, and the docs don't set it either. I was setting it though, in reaction to the error I see if I omit it:

error: The option `rekey.secrets' is used but not defined.

I'll keep digging. In the mean time, this is my module to do secret configuration:

{ flake-inputs, system, host-id, host-public-key }: { pkgs, lib, ... }: {
  nixpkgs.overlays = [
    # This lets us include the agenix-rekey package.
    flake-inputs.agenix-rekey.overlays.default
  ];
  age.rekey = {
    hostPubkey = host-public-key;
    masterIdentities = [
      ../secrets/agenix-master-key.pub
    ];
    # Must be relative to the flake.nix file.
    localStorageDir = (builtins.trace "localStorageDir" (lib.debug.traceVal ../secrets/rekeyed/${host-id}));
    generatedSecretsDir = (builtins.trace "generatedSecretsDir" (lib.debug.traceVal ../secrets/generated/${host-id}));
    # These fields are labeled as missing with:
    #  The option `age.rekey.userFlake' does not exist. Definition values:
    # userFlake = flake-inputs.self;
    # nodes = flake-inputs.self.nixosConfigurations;
    storageMode = "local";
  };
  imports = [
    flake-inputs.agenix-rekey.nixosModules.default
  ];
  environment.systemPackages = [
    # This should remain out because agenix-rekey brings in agenix - or at least
    # the bits of it we are interested in.
    # flake-inputs.agenix.packages.${system}.default
    pkgs.agenix-rekey
  ];
}

and then my attempt to use it in another NixOS module (same as posted earlier):

  age.secrets.civitai-token = {
    rekeyFile = (builtins.trace "civitai-token.age path" (lib.debug.traceVal ../secrets/rekeyed/${host-id}/civitai-token.age));
  };

and my global configuration, at the root of my Flake output:

      agenix-rekey = agenix-rekey.configure {
        userFlake = self;
        nodes = self.nixosConfigurations // self.darwinConfigurations;
      };

Thanks again for taking a look - and no expectations that this is where your spare time is going :)

@oddlama
Copy link
Owner

oddlama commented Apr 4, 2024

Just had some time to look at your config. The main issue seems to be that you removed the agenix nixos module, which is still required. agenix-rekey is just an extension to agenix. So importing flake-inputs.agenix.nixosModules.default should solve the problems.

Some other things i noticed:

  • You never want to set rekey.secrets but always age.secrets. The only difference in using agenix-rekey over agenix is to always set rekeyFile instead of file (as you already correctly stated). The rekey.secrets option isn't even documented anymore and just exist as a backward compatibility option from the early days of agenix-rekey (where I didn't know that one can extend suboption declarations like age.secrets directly). So nowadays we just define a new rekeyFile option directly into the age.secret options.
  • Im not sure what the intent of age.secrets = ../secrets/secrets.nix; is exactly, since the file has an empty attrset. Either way, rekey.secrets = (import ../secrets/secrets.nix); should be deleted.
  • This will not work:
    bearer = lib.fileContents config.age.secrets.civitai-token.path;
    Has nothing to do with agenix-rekey, but generally in agenix you can only access secrets at runtime. secret.<name>.path will be a string like "/run/secrets/<name>" which will only exist on the actual machines. If you want evaluation-time secrets, you should include a private repository in your flake.nix inputs or do some unorthodox stuff like I'm doing with nix-plugins (but that's a can of worms!).

@oddlama
Copy link
Owner

oddlama commented Apr 4, 2024

Another small thing:
You are currently adding the agenix-rekey overlay & package to all your systems via environment.systemPackages = [pkgs.agenix-rekey];, but you only need the agenix command on systems where you develop your flake.nix. Usually people only add it on their development machines, or even better directly in your devshell if you have one.

@LoganBarnett
Copy link
Contributor Author

This has been a trove. Thank you!!! Once I got the agenix NixOS module back into place, everything started clicking into place.

Sorry about the secrets.nix - that and others are vestiges of when I was getting setup purely with agenix. Only later did I find agenix-rekey, and then I migrated.

I have some notes and TODO items I'd like to do to contribute back. Perhaps in the form of documentation and something to lend direction to the next person who forgets the steps that I did - if you're amenable. I'll try to put something together soon. Thanks again!

@oddlama oddlama closed this as completed May 6, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants