aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArpit Chakladar <arpitchakladar+git@gmail.com>2026-07-29 23:36:51 +0530
committerArpit Chakladar <arpitchakladar+git@gmail.com>2026-07-29 23:36:51 +0530
commit357d69f4ce7da70e746c465c8fa32c8d6dbe815e (patch)
treef8e6fa3084259df55b48da65d9a7c845017d44ff
parent37fb12eee6be551f0ef9b31e2547e115bdeef8e9 (diff)
downloadhome-manager-config-357d69f4ce7da70e746c465c8fa32c8d6dbe815e.tar.gz
home-manager-config-357d69f4ce7da70e746c465c8fa32c8d6dbe815e.zip
feat(ssh): lazy-loading ssh keys from gopass
- Loading ssh keys from gopass only when ssh command runs for the first time
-rw-r--r--modules/security/gopass/default.nix97
-rw-r--r--modules/security/ssh/default.nix16
2 files changed, 63 insertions, 50 deletions
diff --git a/modules/security/gopass/default.nix b/modules/security/gopass/default.nix
index 23692bf..d6848d8 100644
--- a/modules/security/gopass/default.nix
+++ b/modules/security/gopass/default.nix
@@ -5,6 +5,43 @@
pkgs,
...
}:
+let
+ gopass-ssh-load = pkgs.writeShellScriptBin "gopass-ssh-load" ''
+ export SSH_AUTH_SOCK="$(${pkgs.gnupg}/bin/gpgconf --list-dirs agent-ssh-socket)"
+
+ if [ -z "$SSH_AUTH_SOCK" ] || [ ! -S "$SSH_AUTH_SOCK" ]; then
+ echo "Error: SSH_AUTH_SOCK is not set or valid." >&2
+ exit 1
+ fi
+
+ if ${pkgs.openssh}/bin/ssh-add -l 2>/dev/null | grep -qE "(ED25519|RSA|ECDSA)"; then
+ exit 0
+ fi
+
+ for key in github gitlab bitbucket codeberg sourcehut; do
+ if ${config.security.gopass.package}/bin/gopass cat "ssh/$key" > /dev/null 2>&1; then
+ tmpdir=$(mktemp -d)
+ keyfile="$tmpdir/key"
+ ${config.security.gopass.package}/bin/gopass cat "ssh/$key" > "$keyfile" 2>/dev/null
+ chmod 600 "$keyfile"
+
+ if ! ${pkgs.openssh}/bin/ssh-add "$keyfile" 2>/dev/null; then
+ passphrase=$(${config.security.gopass.package}/bin/gopass cat "ssh/$key/passphrase" 2>/dev/null)
+ if [ -n "$passphrase" ]; then
+ tmpcopy=$(mktemp)
+ cp "$keyfile" "$tmpcopy"
+ chmod 600 "$tmpcopy"
+ if ${pkgs.openssh}/bin/ssh-keygen -p -P "$passphrase" -N "" -f "$tmpcopy" 2>/dev/null; then
+ ${pkgs.openssh}/bin/ssh-add "$tmpcopy" 2>/dev/null
+ fi
+ rm -f "$tmpcopy"
+ fi
+ fi
+ rm -rf "$tmpdir"
+ fi
+ done
+ '';
+in
{
options.security.gopass = {
enable = lib.mkEnableOption "Enables gopass.";
@@ -16,9 +53,16 @@
};
ssh-agent = {
enable = lib.mkEnableOption "gopass-backed SSH keys for git";
+ script = lib.mkOption {
+ type = lib.types.package;
+ description = "The package containing the gopass-ssh-load script.";
+ };
};
};
+
config = lib.mkIf config.security.gopass.enable {
+ security.gopass.ssh-agent.script = gopass-ssh-load;
+
programs.password-store = {
enable = true;
package = config.security.gopass.package;
@@ -26,58 +70,13 @@
PASSWORD_STORE_DIR = "${config.home.homeDirectory}/.local/share/pass";
};
};
+
home.sessionVariables = {
PASSWORD_STORE_DIR = config.programs.password-store.settings.PASSWORD_STORE_DIR;
};
- systemd.user.services.gopass-ssh-load = lib.mkIf config.security.gopass.ssh-agent.enable {
- Unit = {
- Description = "Load SSH keys from gopass into SSH agent for git";
- After = [
- "gpg-agent.socket"
- "graphical-session.target"
- ];
- Requires = [
- "gpg-agent.socket"
- ];
- PartOf = [
- "graphical-session.target"
- ];
- };
- Service = {
- Type = "oneshot";
- ExecStart = "${pkgs.writeShellScript "gopass-ssh-load" ''
- export SSH_AUTH_SOCK="$(${pkgs.gnupg}/bin/gpgconf --list-dirs agent-ssh-socket)"
-
- if [ -z "$SSH_AUTH_SOCK" ] || [ ! -S "$SSH_AUTH_SOCK" ]; then
- exit 1
- fi
- for key in github gitlab bitbucket codeberg sourcehut; do
- if ${config.security.gopass.package}/bin/gopass cat "ssh/$key" > /dev/null 2>&1; then
- tmpdir=$(mktemp -d)
- keyfile="$tmpdir/key"
- ${config.security.gopass.package}/bin/gopass cat "ssh/$key" > "$keyfile" 2>/dev/null
- chmod 600 "$keyfile"
- if ! ${pkgs.openssh}/bin/ssh-add "$keyfile" 2>/dev/null; then
- passphrase=$(${config.security.gopass.package}/bin/gopass cat "ssh/$key/passphrase" 2>/dev/null)
- if [ -n "$passphrase" ]; then
- tmpcopy=$(mktemp)
- cp "$keyfile" "$tmpcopy"
- chmod 600 "$tmpcopy"
- if ${pkgs.openssh}/bin/ssh-keygen -p -P "$passphrase" -N "" -f "$tmpcopy" 2>/dev/null; then
- ${pkgs.openssh}/bin/ssh-add "$tmpcopy" 2>/dev/null
- fi
- rm -f "$tmpcopy"
- fi
- fi
- rm -rf "$tmpdir"
- fi
- done
- ''}";
- };
- Install = {
- WantedBy = [ "graphical-session.target" ];
- };
- };
+ home.packages = lib.mkIf config.security.gopass.ssh-agent.enable [
+ config.security.gopass.ssh-agent.script
+ ];
};
}
diff --git a/modules/security/ssh/default.nix b/modules/security/ssh/default.nix
index 4b4180f..62186c4 100644
--- a/modules/security/ssh/default.nix
+++ b/modules/security/ssh/default.nix
@@ -15,7 +15,21 @@
config = lib.mkIf config.security.ssh.enable {
programs.ssh = {
enable = true;
- package = pkgs.openssh;
+
+ package =
+ if (config.security.gopass.enable or false && config.security.gopass.ssh-agent.enable or false) then
+ pkgs.symlinkJoin {
+ name = "openssh-gopass-wrapper";
+ paths = [ pkgs.openssh ];
+ buildInputs = [ pkgs.makeWrapper ];
+ postBuild = ''
+ wrapProgram $out/bin/ssh \
+ --run "${config.security.gopass.ssh-agent.script}/bin/gopass-ssh-load"
+ '';
+ }
+ else
+ pkgs.openssh;
+
enableDefaultConfig = false;
extraOptionOverrides = {
AddKeysToAgent = "yes";