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

Selectively disabling copying generated secrets to host #43

Open
dantefromhell opened this issue Sep 15, 2024 · 3 comments
Open

Selectively disabling copying generated secrets to host #43

dantefromhell opened this issue Sep 15, 2024 · 3 comments

Comments

@dantefromhell
Copy link

My idea is to auto-generate and archive unique root passwords per machine using agenix-rekey.

I was able to setup some generators to get this to work using nicely.

age.rekey = {
  generatedSecretsDir = inputs.self.outPath + "/secrets/agenix/generated/${config.networking.fqdn}";
  localStorageDir = inputs.self.outPath + "/secrets/agenix/rekeyed/${config.networking.fqdn}";
  storageMode = "local";
};

random32 = { pkgs, ...  }: "''${pkgs.pwgen}/bin/pwgen --capitalize --numerals --symbols --secure --ambiguous 32 1";

hashedLinuxPassword = { decrypt, deps, lib, pkgs, ...}: let
  dep = builtins.head deps;
  in ''
    echo " -> Deriving yescrypt hash from "${lib.escapeShellArg dep.host}":"${lib.escapeShellArg dep.name}"" >&2
    ${decrypt} ${lib.escapeShellArg dep.file} \
      | tr -d '\n' \
      | ${pkgs.mkpasswd}/bin/mkpasswd --method=yescrypt --stdin \
      || die "Failure while generating yescrypt password hash"
  '';

age.secrets = {
  user-pw-root = { generator.script = "random32"; mode = "000"; };
  user-pw-root-hashed = {
    generator.dependencies = [ config.age.secrets.user-pw-root ];
    generator.script = "hashedLinuxPassword";
  };
};
users.users.root.hashedPasswordFile = config.age.secrets.user-pw-root-hashed.path;

With this setup the unencrypted root password will be stored in /run/agenix.d/1/user-pw-root which is not ideal from a security perspective and superfluous since the hash is also available.

It would be great to have an option to prevent user-pw-root from being copied to the machine, maybe something like:

user-pw-root = { generator.script = "random32"; copy=false; };
@oddlama
Copy link
Owner

oddlama commented Sep 18, 2024

This is a pretty great idea, I've would have had use for this myself already, but it requires changes to agenix to work properly since agenix installs anything in config.age.secrets without verifying any conditions beforehand.

So our only way to achieve this right now would be to replace the age.secrets.<name>.file with an empty dummy secret. This is kind of hacky but I guess would be an OK workaround for now. I'm not sure on the naming of the option yet, maybe we should call it intermediary or something like that to communicate that this is a secret not associated to the host at all.

@dantefromhell
Copy link
Author

I'm not sure on the naming of the option yet

Yeah I struggled with that one too - my suggestion above was the best I could come up with in the moment.

something like that to communicate that this is a secret not associated to the host at all

Yeah that was my though too.

only way to achieve this right now would be to replace the age.secrets..file with an empty dummy secret

I'm not sure I get this right, would you be able to provide an example?

@oddlama
Copy link
Owner

oddlama commented Sep 19, 2024

I'm not sure I get this right, would you be able to provide an example?

When you define a secret, you set age.secrets.mysecret.rekeyFile = ./something.age; and maybe some other attributes. agenix-rekey then automatically set age.secrets.mysecret.file = ./something-but-rekeyed-for-the-host.age. The file option is mandatory and must be set, since agenix itself decrypts ALL secrets in age.secets when the host's activation script runs. There is no way to tell agenix to ignore one of these entries.

So to have an option age.secrets.mysecret.copy = false; that works, it would have to remove itself (mysecret) from age.secrets, because agenix will try to decrypt anything in that attrset. But you cannot undefine an option while also using it's own value to say it should be removed (would cause infinite recursion). So to introduce a copy option we need something that is either respected by agenix directly (which then would require upstream changes to agenix) or we can use a fake file = ./dummy.age that can be decrypted on the host but doesn't actually contain the secret.

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