Access NixOS SOPS Secret via Home Manager

Description

I’ve setup sops-nix in my flakes NixOS configuration. I can access secrets from my NixOS configuration files. How do I access a secret from Home Manager without having to pass in the --impure option?

Accessing SOPS Secrets via Home Manager

The Home Manager file that needs access to a secret:

{ config, osConfig, pkgs, ... }: {
  home = {
    packages = with pkgs; [ element-desktop ];
    file."${config.xdg.userDirs.documents}/Secrets/Element/security-key.txt".source = osConfig.sops.secrets."app/element-desktop/message-key".path;
  };
}

Current version of the above file here.

This works when I rebuild my system with sudo nixos-rebuild switch --flake ./ --impure, however, I’d like to pass in the value(s) in sops.secrets... into Home Manager via my flake.nix file so Nix knows that it’s an external dependency (and presumably will not require the use of --impure).

Stripped Down Version of My flake.nix

{
  inputs = {
    ...
    sops-nix.url = "github:Mic92/sops-nix";
  };

  outputs = inputs@{ self, home-manager, nixpkgs, sops-nix, ... }: {
    nixosConfigurations.<hostName> = inputs.nixpkgs.lib.nixosSystem {
      specialArgs = { inherit inputs pkgs; };
      modules = [
        home-manager.nixosModules.home-manager
        <pathToNixOsConfig>      <----- This would be the NixOS file that
        {                         \---- configures sops-nix and currently
          home-manager = {         \--- accessed secrets w/o the --impure option.
            extraSpecialArgs = { inherit inputs pkgs; };
            users.<userName>.imports = [
              <pathToUserHomeManagerConfig>    <----- This would be the Home
            ];                                  \---- Manager file that is
          };                                     \--- attempting to access
        }                                         \-- the sops secret.
      ];
    };
  };
}

Real flake.nix file here.

Note(s)

Here is my full NixOS + Home Manager configuration.

In your home-manager flake user imports add inputs.sops-nix.homeManagerModule.

Then in your HM configuration file add:

{
  sops-nix,
  ...
}:{
  sops = {
    age.keyFile = ...
    defaultSopsFile = ...
  };
  <config>
}

Hopefully that works for you!

The Good

It imported sops-nix and config.sops.secrets.<bla> exist.

The Bad

The path that’s returned is incorrect. Specificly, it’s %r/secrets/app/element-desktop/message-key when it should be /run/user/1000/secrets/app/element-desktop/message-key (because it’s a Home Manager modules rather than a NixOS one).

The Ugly

There exists no /run/user/1000/secrets/ directory, so the path is wrong, but even if it was correct, it doesn’t exist. It also doesn’t exist in the location it would be at if it was configured as a NixOS module (/run/secrets/app/element-desktop/message-key).

New Home Manager File

{ config, pkgs, sops-nix, user, ... }: {
  sops = {
    defaultSopsFile = <pathToSecretsYamlFile>;
    defaultSopsFormat = "yaml";
    age.keyFile = <pathToSopsAgeKeysFile>;
    secrets."app/element-desktop/message-key" = { };
  };
  home = {
    packages = with pkgs; [ element-desktop ];
    file."${config.xdg.userDirs.documents}/Secrets/Element/security-key.txt".source = config.sops.secrets."app/element-desktop/message-key".path;
  };
}

Note

When I change .source to .text it writes this %r/secrets/app/element-desktop/message-key to the file and /run/user/1000/secrets/ still don’t exist.

Error Output

error:
       … while calling the 'head' builtin

         at /nix/store/5hwz775f3grzikafj1sbwx4lqkjwqswb-source/lib/attrsets.nix:922:11:

          921|         || pred here (elemAt values 1) (head values) then
          922|           head values
             |           ^
          923|         else

       … while evaluating the attribute 'value'

         at /nix/store/5hwz775f3grzikafj1sbwx4lqkjwqswb-source/lib/modules.nix:807:9:

          806|     in warnDeprecation opt //
          807|       { value = builtins.addErrorContext "while evaluating the option `${showOption loc}':" value;
             |         ^
          808|         inherit (res.defsFinal') highestPrio;

       (stack trace truncated; use '--show-trace' to show the full trace)

       error: A definition for option `home-manager.users.reedclanton.home.file."/home/reedclanton/Documents/Secrets/Element/security-key.txt".source' is not of type `path'. Definition values:
       - In `/nix/store/z1ggqi8k3xhgcwc32702m2glhkr4k7qm-source/users/reedclanton/home/modules/applications/gui/element-desktop.nix': "%r/secrets/app/element-desktop/message-key"

I think it needs to be something like:

sops.secrets.element-message-key = {};
home = {
  file."${config......" = config.sops.secrets.element-message-key.path;
};

And then your file contents in the secrets file set something like:

element-message-key: |
  abcdefgh12345

Unfortunately, no luck. The value changes, but only to mach the new name (i.e. %r/secrets/app-element-desktop-message-key rather than %s/secrets/app/element-desktop/message-key).

Also, the same value I had works when I use --impure (as described in the original post), so I don’t think it’s an issue associated with how the secrets key is formatted. Plus, that secrets file has multiple other secrets in it that are currently functioning in the NixOS portion of the configuration.

Sorry, I’m running up against the end of my knowledge! I don’t see why you’re not getting the files created in /run/user/1000/secrets.

Don’t be sorry! Thanks for the help. I learned some about importing modules from your responses.

Perhaps the issue relate to how sops-nix is imported. Maybe importing both NixOS and Home Manager modules system wide (i.e. from the flake) causes a conflict.

Still haven’t solved this. Suggestions welcome.

FWIW I’m having the ame issue - did you ever solve this?

Unfortunately no. I’ve just been using the NixOS module in Home Manager. This requires that --impure be passed in (and is ugly and I hate it).

Hey, I actually was able to work around it. There’s a github issue for this from a while back, and it seems the solution is to append the following options to your sops config:

sops = {
  # ... all the other stuff ...
  defaultSymlinkPath = "/run/user/1000/secrets";
  defaultSecretsMountPoint = "/run/user/1000/secrets.d";
};

Reason being that sops-nix apparently has no way of knowing your UUID at build time. (I’m not really happy with this solution because I would rather not hardcode the UUID, if you happen to know a way around that, please do tell!)

Hope this is helpful!