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

home-manager integration? #50

Open
Radvendii opened this issue Jul 5, 2021 · 27 comments
Open

home-manager integration? #50

Radvendii opened this issue Jul 5, 2021 · 27 comments

Comments

@Radvendii
Copy link

Is it possible to use agenix from inside a home-manager module? I don't see anything talking about this, so I'm guessing it's not possible, but I figured I'd check.

I realize I can use an agenix secret from inside a home-manager module by just accessing the /run/secrets/blah file, but I'd like to keep the file generation (i.e. age.secrets.blah.file = "${self}/secrets/blah";) close to the point of use, rather than off in it's own NixOS module.

@ryantm
Copy link
Owner

ryantm commented Jul 5, 2021

I don't think it will work by default. We'll need to update the module to work with it. This is definitely in scope for this project.

@Pacman99
Copy link
Contributor

A few of us came to a similar conclusion a while ago: divnix/digga#319. Thanks for actually opening the issue here.

@Radvendii
Copy link
Author

This seems to have been attempted: https://github.com/jordanisaacs/homeage

I wonder if it would be possible / desireable to merge that into agenix, or better to leave it separate.

@Gerschtli
Copy link

Because both project try to achieve the same result except different build environments, these should at some point be merged. Ping @jordanisaacs for your opinion on that.

@jordanisaacs
Copy link

The reason I wrote mine separately as I see my project being primarily a module for home-manager. My vision for homeage doesn't involve a CLI (interested only in the module) and its on pace to become more intimately tied to home-manager. So while both are similar, I see them as fitting different use cases: agenix for the system and CLI, homeage for declarative use with home-manager

@Gerschtli
Copy link

I think it would create a more consistent experience if the modules for NixOS and home-manager work the same (from a UX point of view). I agree, that agenix currently only supports system configuration, but a home-manager integration is possible. Also I think there are many common logic parts or scripts (like module options, the shell script for linking/copying, the cleanup logic, etc.) that could be shared between NixOS and home-manager implementation. That would improve the quality of both project because the actual logic only needs to be written once.

And the CLI seems to be replaced by agenix-cli in the future anyway.

Opinions @jordanisaacs @ryantm?

@Nebucatnetzer
Copy link

Would be nice if agenix would work with home-manager as well.
Just for the sake of uniformity in the config.

@aouerf
Copy link

aouerf commented Jun 25, 2023

This can probably be closed because of #180 ?

@Nebucatnetzer
Copy link

Nebucatnetzer commented Jun 25, 2023 via email

@sellout
Copy link

sellout commented Jun 25, 2023

Yeah, I think it's reasonable to keep this open pending docs. I've used it already, so I can probably write it up today or tomorrow.

@Nebucatnetzer
Copy link

Nebucatnetzer commented Jun 25, 2023 via email

@Brawl345
Copy link

any updates on this? Struggling to get it to work, tried adding agenix.homeManagerModules.age in my home-manager config to ìmports` but it keeps erroring out with "infinite recursion encountered" :/

@sellout
Copy link

sellout commented Jul 13, 2023

Sorry, I apologize for not getting to this yet. I’ve only used it via flakes, where you do

    {
      homeConfigurations = {
        "user@host" = inputs.home-manager.lib.homeManagerConfiguration {
          modules = [
            inputs.agenix.homeManagerModules.age # ← the important bit
          ];
        };
      };
    };

for a non-flake config (like it sounds like you have, @Brawl345), I think you should instead do something like

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

that assumes you’re using nix channels, but the instructions here should translate from NixOS to home-manager with a few substitutions:

  • configuration.nix → home.nix
  • age.nix -> age-home.nix
  • nixosModules -> homeManagerModules

@Nebucatnetzer @Brawl345 – let me know if this short explanation solved your issues, so I know if my writeup will be correct.

@Brawl345
Copy link

I use flakes with nix-darwin and home-manager as a nix-darwin module. I had some mistake in my (spaghetti) config and now everything works! Here is a minimal flake:

{
  description = "sample";

  inputs = {
    nixpkgs = {
      url = "github:NixOS/nixpkgs/nixpkgs-unstable";
    };

    darwin = {
      url = "github:lnl7/nix-darwin/master";
      inputs.nixpkgs.follows = "nixpkgs";
    };

    home-manager = {
      url = "github:nix-community/home-manager";
      inputs.nixpkgs.follows = "nixpkgs";
    };

    agenix = {
      url = "github:ryantm/agenix";
      inputs.nixpkgs.follows = "nixpkgs";
    };
  };

  outputs = { self, nixpkgs, darwin, home-manager, agenix, ... } @ inputs:
    {
      darwinConfigurations = {
        someuser = darwin.lib.darwinSystem {
          system = "aarch64-darwin";
          specialArgs = { inherit inputs; };
          modules = [
            agenix.darwinModules.default
            home-manager.darwinModules.home-manager
            {
              home-manager.useGlobalPkgs = true;
              home-manager.useUserPackages = true;
              home-manager.users.someuser = { config, pkgs, ... }: {
                programs.home-manager.enable = true;
                home.stateVersion = "22.11";
                manual.manpages.enable = false;
                manual.html.enable = false;
                manual.json.enable = false;
                programs.bash.enable = true;

                imports = [
                  agenix.homeManagerModules.default
                ];

                age.identityPaths = [ "/Users/someuser/.ssh/id_default_ed25519" ];
                age.secrets.secret1.file = ./secrets/secret1.age;
                home.sessionVariables = {
                  SECRET_VALUE = ''
                    $(${pkgs.coreutils}/bin/cat ${config.age.secrets.secret1.path})
                  '';
                };
              };
            }
          ];
        };
      };
    };
}

The age.identityPaths is very important or else nothing gets decrypted and you won't get an error. On NixOS it uses config.services.openssh.hostKeys.

@Nebucatnetzer
Copy link

I reckon with the examples by @sellout and @Brawl345 I should be able to integrate it.

@Nebucatnetzer
Copy link

Hm I'm a bit confused.
When I do offlineimap -o I get cat: '$XDG_RUNTIME_DIR/agenix/personalEmailKey': No such file or directory but when I run the command manually I see the password.
The config is basically the same just with the new module.
Here is a diff of the new config:
https://git.2li.ch/Nebucatnetzer/nixos/pulls/3/files

@ldicarlo
Copy link

ldicarlo commented Sep 8, 2023

Hi, and thank you for this awesome package.
So I see the same error as @Nebucatnetzer.
It seems that
age.secrets.github_token.file = ./secrets/github_token.age; results in
${config.age.secrets.github_token.path} being evaluated to /agenix/github_token

Since it results in the log /agenix/github_token: No such file or directory during switch.

(I use a flake).

/agenix/ folder does not exists on my computer. What is the folder supposed to be when using Home Manager Agenix Module?
Thank you

[EDIT]
Also when I update the secret I don't see any new generation in /run/agenix.d. I though I would see a new generation, but I am no expert in this package.

@ldicarlo
Copy link

ldicarlo commented Sep 9, 2023

I managed to do it.
I think there are 2 problems:

  • in my case it seems that $XDG_RUNTIME_DIR was not interpolated as my home folder and was empty, so the secrets would be looked for in /agenix/ instead of / run/user/1000/agenix but i did not fix neither understand rightly this problem.
  • I think the user systemd service agenix.service was run only once and then not reran. Because once I did run it again then the secrets were updated and it worked.

Currently on a non-darwin system, this is what I have (and work):

  • (nowhere agenix.nixosModules.default )
  • In my home configuration (home-manager.users.luca) :

imports =
    [
      inputs.agenix.homeManagerModules.default
    ];
 age.secrets.secret1.file = ./secrets/sec1.age;

home.packages = [ 
    (pkgs.writeShellScriptBin "echo-secret" ''
      ${pkgs.coreutils}/bin/cat ${config.age.secrets.secret1.path}
    '')
];

secrets.nix with basic info like in the tutorial.

[EDIT]
Just to confirm, each time I run agenix -e ... and then nixos-rebuild switch ... I still need to run systemctl --user start agenix.service after.

@Nebucatnetzer
Copy link

I can’t remember it from the top of my head but I think there is a way to force a restart of a service after a rebuild.
Might be a useful workaround for this.
I hadn’t had time yet to try a second time but I hope to be able to test it soon.

@shymega
Copy link

shymega commented Sep 18, 2023

I'm having a similar issue with Home Manager+Agenix, and the $XDG_RUNTIME_DIR.

I'm basically storing my Taskwarrior sync CA/certificate/key, and credentials in Age-encrypted files.

My home manager configuration is fairly simple. The secrets can be decrypted, but the produced file for Taskwarrior keeps the $XDG_RUNTIME_DIR path in the config. This is invalid for Taskwarrior, and I'm a little unsure of how to proceed. I think this is something that could be extended in Agenix to have an output with the full, expanded path to the decrypted secret.

I really like Agenix, and I'm happy with it thus far. I just don't want to use solutions involving cat or builtin.readFile for the security risks involved there.

My configuration extract for Taskwarrior is listed below, as well as the produced configuration by Home Manager:

    taskwarrior = {
      enable = true;
      config = {
        confirmation = false;
        report = {
          minimal.filter = "status:pending";
          active.columns = [ "id" "start" "entry.age" "priority" "project" "due" "description" ];
          active.labels = [ "ID" "Started" "Age" "Priority" "Project" "Due" "Description" ];
        };
        taskd = {
          certificate = config.age.secrets.taskwarrior_sync_cert.path;
          key = config.age.secrets.taskwarrior_sync_key.path;
          ca = config.age.secrets.taskwarrior_sync_ca.path;
          server = "inthe.am:53589";
          credentials = config.age.secrets.taskwarrior_sync_cred.path;
        };
      };
    };
  };
data.location=/home/dzrodriguez/.local/share/task


confirmation=false
report.active.columns=id,start,entry.age,priority,project,due,description
report.active.labels=ID,Started,Age,Priority,Project,Due,Description
report.minimal.filter=status:pending
taskd.ca=$XDG_RUNTIME_DIR/agenix/taskwarrior_sync_ca
taskd.certificate=$XDG_RUNTIME_DIR/agenix/taskwarrior_sync_cert
taskd.credentials=$XDG_RUNTIME_DIR/agenix/taskwarrior_sync_cred
taskd.key=$XDG_RUNTIME_DIR/agenix/taskwarrior_sync_key
taskd.server=inthe.am:53589

@shymega
Copy link

shymega commented Sep 18, 2023

I can’t remember it from the top of my head but I think there is a way to force a restart of a service after a rebuild. Might be a useful workaround for this. I hadn’t had time yet to try a second time but I hope to be able to test it soon.

That would be really useful to know. If you do remember, maybe a PR to the documentation would be great!

@Nebucatnetzer
Copy link

Maybe extending home.activation helps. https://nix-community.github.io/home-manager/options.html#opt-home.activation
IIRC what I was using was the userActivationScript from NixOS.
Doesn't sound like the most optimal solution however.

@Deadbyrd12
Copy link

I solved the issue of restarting the service on my system by adding this line:
systemd.user.startServices = "sd-switch";
to my home-manager config.

This changes the general behavior when it comes to starting/stopping services after switching generations. That means it might cause some weird side effects. The default is "suggest" which prints some suggestions as to which services should be restarted manually. "sd-switch" uses a 3rd-party app to start/stop the required services (requires a user dbus session). It seems this is going to become the default at some point. See the systemd home-manager module.

@jackwilsdon
Copy link

jackwilsdon commented Feb 5, 2024

I'm currently using the following workaround for machines which do not have a dbus session (and therefore can't use systemd user units):

# In home-manager.users.your-name-here
home.activation.agenix = lib.hm.dag.entryAnywhere config.systemd.user.services.agenix.Service.ExecStart;

It's a bit of a hack as agenix doesn't expose the user activation script anywhere, but it appears to work well enough. It seems to me like agenix might be better off using an activation script with home-manager too (like it already does with the system-wide version, as suggested by @Nebucatnetzer), instead of systemd/launchd as it currently uses.

@jackwilsdon
Copy link

jackwilsdon commented Feb 5, 2024

The above only seems to work at boot if you change the secretsDir and secretsMountPoint to be outside of $XDG_RUNTIME_DIR, as this isn't set (and the directory likely doesn't even exist) at boot:

# In home-manager.users.your-name-here
age = {
  secretsDir = "${config.home.homeDirectory}/.agenix/agenix";
  secretsMountPoint = "${config.home.homeDirectory}/.agenix/agenix.d";
};

@kukovecz
Copy link

kukovecz commented Apr 2, 2024

Hello,

I am really new in learning nix and using some base ubuntu (linux mint precisely) with nix as package manager and home manager to setup my config.

It was a little bit painful to setup agenix in this way, but it works, thanks for all the help in the documentation and people responses in this issue.

I want to leave the working configuration here if it might help anyone.

I am using flakes and I've put this to my flake.nix:

homeConfigurations."username" = home-manager.lib.homeManagerConfiguration {
  inherit pkgs;

  modules = [
    # <other modules>
    agenix.homeManagerModules.age
    {
      age = {
        secrets = {
          "mysecret1" = {
            file = path/to/mysecret1.age;
            # owner = "username";  <-- This is not working
          };
        };
        secretsDir = "<home of username>/.agenix/agenix";
        secretsMountPoint = "<home of username>/.agenix/agenix.d";
        identityPaths = [ "<path/to/private/key/for/mysecret1.age>" ];
      };
    }
    # <other modules>
  ];
};

The owner setting is not working for the secret, despite stating in the documentation.

By not working, I mean

error: The option `age.secrets."mysecret1".owner' does not exist.

I assume this is intentional (that option does not exist in age-home.nix), because as this being a home manager module, the owner will always be username.

@Yeshey
Copy link

Yeshey commented May 20, 2024

I was trying to write a user service that would put my secrets where I wanted, apparently you need systemd.user.services.<my_service>.Unit.After = [ "agenix.service" ]; for it to work, figured out by reading the sops-nix documentation, some similar documentation on agenix would be cool. Im not using systemd.user.startServices = "sd-switch";. With help fom @ldicarlo answer this is the service I got:

let
  inherit (pkgs.stdenv.hostPlatform) system; # for agenix pkg
  mystuff = pkgs.writeShellScriptBin "echo-secret" ''
        ${pkgs.coreutils}/bin/cat ${config.age.secrets.my_identity.path} > /home/yeshey/Downloads/ImOkay.txt
      '';
in
{
    home.packages = [
      inputs.agenix.packages.${system}.agenix
      mystuff # so now in the terminal running `echo-secret` runs the above command
    ];

    systemd.user.services."test" = {
      Unit = {
        Description = "test";
        After = [ "agenix.service" ];
      };
      Service = {
        Type = "oneshot";
        ExecStart = "${mystuff}/bin/echo-secret";
      };
      Install.WantedBy = [ "default.target" ];
    };
}

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