Can't make gpg-agent work with ssh on a non-gui system

I have gpg-agent running by systemd unit with the following config:

# home-manager configuration
  programs.gpg = {
    enable = true;
    package = pkgs.unstable.gnupg;
  };

  services.gpg-agent = {
    enable = true;
    enableExtraSocket = true;
    enableSshSupport = true;
    updateStartupTty = false;

    defaultCacheTtl = 60 * 60 * 6;
    defaultCacheTtlSsh = 60 * 60 * 6;

    pinentryFlavor = "tty";

    verbose = true;

    extraConfig = ''
      debug-pinentry
      debug-level 1024

      # I don't use smart cards
      disable-scdaemon
    '';
  };

  # to avoid The `busctl monitor` error
  # "name org.freedesktop.secrets was not provided by any .service files"
  programs.password-store = {
    enable = true;
    package = pkgs.pass; #.withExtensions (ext: [ ext.pass-otp ]);
    settings = {
      PASSWORD_STORE_DIR = "${config.home.homeDirectory}/.password-store";
    };
  };

  services.pass-secret-service.enable = true;
  systemd.user.services.pass-secret-service = {
    Service = {
      Type = "dbus";
      BusName = "org.freedesktop.secrets";
      ExecStart = lib.mkForce "${pkgs.pass-secret-service}/bin/pass_secret_service --path ${config.programs.password-store.settings.PASSWORD_STORE_DIR}";
    };
  };

# relevant part of nixos configuration
  environment.systemPackages = with pkgs; [
    pass-secret-service
  ];
  services.dbus = {
    packages = [
      pkgs.pass-secret-service
    ];
  };
  services.pcscd.enable = true;

I set GPG_TTY in .zshrc:

GPG_TTY="$(tty)"
export GPG_TTY

And SSH_AUTH_SOCK is correctly defined:

❯ echo $SSH_AUTH_SOCK
/run/user/1000/gnupg/S.gpg-agent.ssh
❯ stat $SSH_AUTH_SOCK
  File: /run/user/1000/gnupg/S.gpg-agent.ssh
  Size: 0               Blocks: 0          IO Block: 4096   socket
Device: 0,47    Inode: 19          Links: 1
Access: (0600/srw-------)  Uid: ( 1000/      user)   Gid: (  100/   users)
Access: 2023-01-17 18:55:06.856000047 +0000
Modify: 2023-01-17 18:54:37.992000033 +0000
Change: 2023-01-17 18:54:37.992000033 +0000
 Birth: -

And additionally check that $GPG_TTY is indeed the current tty before I execute ssh or git. However, with this config gpg itself works and caches password:

gpg --use-agent -s somefile
# exit code 0

But ssh does not:

❯ ssh git@github.com
sign_and_send_pubkey: signing failed for ED25519 "/home/user/.ssh/id_ed25519" from agent: agent refused operation
git@github.com: Permission denied (publickey).

Here is gpg-agent journal:

Jan 17 19:38:24 nixosdev gpg-agent[1575]: DBG: agent_cache_housekeeping
Jan 17 19:38:28 nixosdev gpg-agent[1575]: DBG: agent_cache_housekeeping
Jan 17 19:38:30 nixosdev gpg-agent[1575]: ssh handler 0xffff7dc60120 for fd 8 started
Jan 17 19:38:30 nixosdev gpg-agent[1575]: ssh request handler for extension (27) started
Jan 17 19:38:30 nixosdev gpg-agent[1575]: ssh-agent extension 'session-bind@openssh.com' received
Jan 17 19:38:30 nixosdev gpg-agent[1575]: ssh-agent extension 'session-bind@openssh.com' not supported
Jan 17 19:38:30 nixosdev gpg-agent[1575]: ssh request handler for extension (27) ready
Jan 17 19:38:30 nixosdev gpg-agent[1575]: ssh request handler for request_identities (11) started
Jan 17 19:38:30 nixosdev gpg-agent[1575]: new connection to /nix/store/049qrpx6v8sqzn17nwx0pgpnqxv1sqbg-gnupg-2.3.7/libexec/scdaemon daemon established (reusing)
Jan 17 19:38:30 nixosdev gpg-agent[1575]: DBG: chan_10 -> SERIALNO --all
Jan 17 19:38:30 nixosdev gpg-agent[1575]: DBG: chan_10 <- ERR 100696144 No such device <SCD>
Jan 17 19:38:30 nixosdev gpg-agent[1575]: error getting list of cards: No such device
Jan 17 19:38:30 nixosdev gpg-agent[1575]: ssh request handler for request_identities (11) ready
Jan 17 19:38:30 nixosdev gpg-agent[1575]: ssh request handler for sign_request (13) started
Jan 17 19:38:30 nixosdev gpg-agent[1575]: DBG: agent_get_cache 'EE03DF21FC4EE33FA1D026589CD4ACF7DDF16C3F'.0 (mode 4) ...
Jan 17 19:38:30 nixosdev gpg-agent[1575]: DBG: ... miss
Jan 17 19:38:30 nixosdev gpg-agent[1575]: starting a new PIN Entry
Jan 17 19:38:30 nixosdev gpg-agent[1575]: DBG: chan_9 <- OK Pleased to meet you, process 1575
Jan 17 19:38:30 nixosdev gpg-agent[1575]: DBG: connection to PIN entry established
Jan 17 19:38:30 nixosdev gpg-agent[1575]: DBG: chan_9 -> OPTION grab
Jan 17 19:38:30 nixosdev gpg-agent[1575]: DBG: chan_9 <- OK
Jan 17 19:38:30 nixosdev gpg-agent[1575]: DBG: chan_9 -> OPTION allow-external-password-cache
Jan 17 19:38:30 nixosdev gpg-agent[1575]: DBG: chan_9 <- OK
Jan 17 19:38:30 nixosdev gpg-agent[1575]: DBG: chan_9 -> OPTION default-ok=_OK
Jan 17 19:38:30 nixosdev gpg-agent[1575]: DBG: chan_9 <- OK
Jan 17 19:38:30 nixosdev gpg-agent[1575]: DBG: chan_9 -> OPTION default-cancel=_Cancel
Jan 17 19:38:30 nixosdev gpg-agent[1575]: DBG: chan_9 <- OK
Jan 17 19:38:30 nixosdev gpg-agent[1575]: DBG: chan_9 -> OPTION default-yes=_Yes
Jan 17 19:38:30 nixosdev gpg-agent[1575]: DBG: chan_9 <- ERR 83886254 Unknown option <Pinentry>
Jan 17 19:38:30 nixosdev gpg-agent[1575]: DBG: chan_9 -> OPTION default-no=_No
Jan 17 19:38:30 nixosdev gpg-agent[1575]: DBG: chan_9 <- ERR 83886254 Unknown option <Pinentry>
Jan 17 19:38:30 nixosdev gpg-agent[1575]: DBG: chan_9 -> OPTION default-prompt=PIN:
Jan 17 19:38:30 nixosdev gpg-agent[1575]: DBG: chan_9 <- OK
Jan 17 19:38:30 nixosdev gpg-agent[1575]: DBG: chan_9 -> OPTION default-pwmngr=_Save in password manager
Jan 17 19:38:30 nixosdev gpg-agent[1575]: DBG: chan_9 <- OK
Jan 17 19:38:30 nixosdev gpg-agent[1575]: DBG: chan_9 -> OPTION default-cf-visi=Do you really want to make your passphrase visible on the screen?
Jan 17 19:38:30 nixosdev gpg-agent[1575]: DBG: chan_9 <- OK
Jan 17 19:38:30 nixosdev gpg-agent[1575]: DBG: chan_9 -> OPTION default-tt-visi=Make passphrase visible
Jan 17 19:38:30 nixosdev gpg-agent[1575]: DBG: chan_9 <- OK
Jan 17 19:38:30 nixosdev gpg-agent[1575]: DBG: chan_9 -> OPTION default-tt-hide=Hide passphrase
Jan 17 19:38:30 nixosdev gpg-agent[1575]: DBG: chan_9 <- OK
Jan 17 19:38:30 nixosdev gpg-agent[1575]: DBG: chan_9 -> OPTION default-capshint=Caps Lock is on
Jan 17 19:38:30 nixosdev gpg-agent[1575]: DBG: chan_9 <- OK
Jan 17 19:38:30 nixosdev gpg-agent[1575]: DBG: chan_9 -> OPTION touch-file=/run/user/1000/gnupg/S.gpg-agent
Jan 17 19:38:30 nixosdev gpg-agent[1575]: DBG: chan_9 <- OK
Jan 17 19:38:30 nixosdev gpg-agent[1575]: DBG: chan_9 -> OPTION owner=164119/1000 nixosdev
Jan 17 19:38:30 nixosdev gpg-agent[1575]: DBG: chan_9 <- OK
Jan 17 19:38:30 nixosdev gpg-agent[1575]: DBG: chan_9 -> GETINFO flavor
Jan 17 19:38:30 nixosdev gpg-agent[1575]: DBG: chan_9 <- D tty
Jan 17 19:38:30 nixosdev gpg-agent[1575]: DBG: chan_9 <- OK
Jan 17 19:38:30 nixosdev gpg-agent[1575]: DBG: chan_9 -> GETINFO version
Jan 17 19:38:30 nixosdev gpg-agent[1575]: DBG: chan_9 <- D 1.2.0-unknown
Jan 17 19:38:30 nixosdev gpg-agent[1575]: DBG: chan_9 <- OK
Jan 17 19:38:30 nixosdev gpg-agent[1575]: DBG: chan_9 -> GETINFO ttyinfo
Jan 17 19:38:30 nixosdev gpg-agent[1575]: DBG: chan_9 <- D - - - - 1000/100 0
Jan 17 19:38:30 nixosdev gpg-agent[1575]: DBG: chan_9 <- OK
Jan 17 19:38:30 nixosdev gpg-agent[1575]: DBG: chan_9 -> GETINFO pid
Jan 17 19:38:30 nixosdev gpg-agent[1575]: DBG: chan_9 <- D 164121
Jan 17 19:38:30 nixosdev gpg-agent[1575]: DBG: chan_9 <- OK
Jan 17 19:38:30 nixosdev gpg-agent[1575]: DBG: chan_9 -> SETKEYINFO s/EE03DF21FC4EE33FA1D026589CD4ACF7DDF16C3F
Jan 17 19:38:30 nixosdev gpg-agent[1575]: DBG: chan_9 <- OK
Jan 17 19:38:30 nixosdev gpg-agent[1575]: DBG: chan_9 -> SETDESC Please enter the passphrase for the ssh key%0A  SHA256:0XhqDW8dp3otr9eYxvDgjfzfnzADd5nuirToRd7wQdg%0A  (user@nixos)
Jan 17 19:38:30 nixosdev gpg-agent[1575]: DBG: chan_9 <- OK
Jan 17 19:38:30 nixosdev gpg-agent[1575]: DBG: chan_9 -> SETPROMPT Passphrase:
Jan 17 19:38:30 nixosdev gpg-agent[1575]: DBG: chan_9 <- OK
Jan 17 19:38:30 nixosdev gpg-agent[1575]: DBG: chan_9 -> [[Confidential data not shown]]
Jan 17 19:38:30 nixosdev gpg-agent[1575]: DBG: chan_9 <- [[Confidential data not shown]]
Jan 17 19:38:31 nixosdev gpg-agent[1575]: DBG: error calling pinentry: Operation cancelled <Pinentry>
Jan 17 19:38:31 nixosdev gpg-agent[1575]: DBG: chan_9 -> BYE
Jan 17 19:38:31 nixosdev gpg-agent[1575]: failed to unprotect the secret key: Operation cancelled
Jan 17 19:38:31 nixosdev gpg-agent[1575]: failed to read the secret key
Jan 17 19:38:31 nixosdev gpg-agent[1575]: ssh sign request failed: Operation cancelled <Pinentry>
Jan 17 19:38:31 nixosdev gpg-agent[1575]: ssh request handler for sign_request (13) ready
Jan 17 19:38:31 nixosdev gpg-agent[1575]: DBG: chan_10 -> RESTART
Jan 17 19:38:31 nixosdev gpg-agent[1575]: DBG: chan_10 <- OK
Jan 17 19:38:31 nixosdev gpg-agent[1575]: ssh handler 0xffff7dc60120 for fd 8 terminated

I have gpg-agent running by systemd unit with the following config:

❯ cat ~/.gnupg/gpg-agent.conf
enable-ssh-support
grab
default-cache-ttl 21600
default-cache-ttl-ssh 21600
pinentry-program /nix/store/z40fbs3mqw0vm12csshbbrxjich16q02-pinentry-1.2.0-tty/bin/pinentry
debug-pinentry
debug-level 1024

❯ cat ~/.gnupg/gpg.conf
cert-digest-algo SHA512
charset utf-8
default-preference-list SHA512 SHA384 SHA256 AES256 AES192 AES ZLIB BZIP2 ZIP Uncompressed
fixed-list-mode
keyid-format 0xlong
list-options show-uid-validity
no-comments
no-emit-version
no-symkey-cache
personal-cipher-preferences AES256 AES192 AES
personal-compress-preferences ZLIB BZIP2 ZIP Uncompressed
personal-digest-preferences SHA512 SHA384 SHA256
require-cross-certification
s2k-cipher-algo AES256
s2k-digest-algo SHA512
use-agent
verify-options show-uid-validity
with-fingerprint

❯ systemctl --user cat gpg-agent.service
# /home/user/.config/systemd/user/gpg-agent.service
[Service]
Environment=GNUPGHOME=/home/user/.gnupg
ExecReload=/nix/store/049qrpx6v8sqzn17nwx0pgpnqxv1sqbg-gnupg-2.3.7/bin/gpgconf --reload gpg-agent
ExecStart=/nix/store/049qrpx6v8sqzn17nwx0pgpnqxv1sqbg-gnupg-2.3.7/bin/gpg-agent --supervised --verbose

[Unit]
After=gpg-agent.socket
Description=GnuPG cryptographic agent and passphrase cache
Documentation=man:gpg-agent(1)
RefuseManualStart=true
Requires=gpg-agent.socket

❯ systemctl --user cat gpg-agent-ssh.socket
# /home/user/.config/systemd/user/gpg-agent-ssh.socket
[Install]
WantedBy=sockets.target

[Socket]
DirectoryMode=0700
FileDescriptorName=ssh
ListenStream=%t/gnupg/S.gpg-agent.ssh
Service=gpg-agent.service
SocketMode=0600

[Unit]
Description=GnuPG cryptographic agent (ssh-agent emulation)
Documentation=man:gpg-agent(1) man:ssh-add(1) man:ssh-agent(1) man:ssh(1)

I set GPG_TTY in .zshenv:

GPG_TTY="$(tty)"
export GPG_TTY

And SSH_AUTH_SOCK is correctly defined:

❯ echo $SSH_AUTH_SOCK
/run/user/1000/gnupg/S.gpg-agent.ssh
❯ stat $SSH_AUTH_SOCK
  File: /run/user/1000/gnupg/S.gpg-agent.ssh
  Size: 0               Blocks: 0          IO Block: 4096   socket
Device: 0,47    Inode: 19          Links: 1
Access: (0600/srw-------)  Uid: ( 1000/      user)   Gid: (  100/   users)
Access: 2023-01-17 18:55:06.856000047 +0000
Modify: 2023-01-17 18:54:37.992000033 +0000
Change: 2023-01-17 18:54:37.992000033 +0000
 Birth: -

And additionally check that $GPG_TTY is indeed the current tty before I execute ssh or git. However, with this config gpg itself works and caches password:

gpg --use-agent -s somefile
# exit code 0

But ssh does not:

❯ ssh git@github.com
sign_and_send_pubkey: signing failed for ED25519 "/home/user/.ssh/id_ed25519" from agent: agent refused operation
git@github.com: Permission denied (publickey).

Here is gpg-agent journal:

Jan 17 19:38:24 nixosdev gpg-agent[1575]: DBG: agent_cache_housekeeping
Jan 17 19:38:28 nixosdev gpg-agent[1575]: DBG: agent_cache_housekeeping
Jan 17 19:38:30 nixosdev gpg-agent[1575]: ssh handler 0xffff7dc60120 for fd 8 started
Jan 17 19:38:30 nixosdev gpg-agent[1575]: ssh request handler for extension (27) started
Jan 17 19:38:30 nixosdev gpg-agent[1575]: ssh-agent extension 'session-bind@openssh.com' received
Jan 17 19:38:30 nixosdev gpg-agent[1575]: ssh-agent extension 'session-bind@openssh.com' not supported
Jan 17 19:38:30 nixosdev gpg-agent[1575]: ssh request handler for extension (27) ready
Jan 17 19:38:30 nixosdev gpg-agent[1575]: ssh request handler for request_identities (11) started
Jan 17 19:38:30 nixosdev gpg-agent[1575]: new connection to /nix/store/049qrpx6v8sqzn17nwx0pgpnqxv1sqbg-gnupg-2.3.7/libexec/scdaemon daemon established (reusing)
Jan 17 19:38:30 nixosdev gpg-agent[1575]: DBG: chan_10 -> SERIALNO --all
Jan 17 19:38:30 nixosdev gpg-agent[1575]: DBG: chan_10 <- ERR 100696144 No such device <SCD>
Jan 17 19:38:30 nixosdev gpg-agent[1575]: error getting list of cards: No such device
Jan 17 19:38:30 nixosdev gpg-agent[1575]: ssh request handler for request_identities (11) ready
Jan 17 19:38:30 nixosdev gpg-agent[1575]: ssh request handler for sign_request (13) started
Jan 17 19:38:30 nixosdev gpg-agent[1575]: DBG: agent_get_cache 'EE03DF21FC4EE33FA1D026589CD4ACF7DDF16C3F'.0 (mode 4) ...
Jan 17 19:38:30 nixosdev gpg-agent[1575]: DBG: ... miss
Jan 17 19:38:30 nixosdev gpg-agent[1575]: starting a new PIN Entry
Jan 17 19:38:30 nixosdev gpg-agent[1575]: DBG: chan_9 <- OK Pleased to meet you, process 1575
Jan 17 19:38:30 nixosdev gpg-agent[1575]: DBG: connection to PIN entry established
Jan 17 19:38:30 nixosdev gpg-agent[1575]: DBG: chan_9 -> OPTION grab
Jan 17 19:38:30 nixosdev gpg-agent[1575]: DBG: chan_9 <- OK
Jan 17 19:38:30 nixosdev gpg-agent[1575]: DBG: chan_9 -> OPTION allow-external-password-cache
Jan 17 19:38:30 nixosdev gpg-agent[1575]: DBG: chan_9 <- OK
Jan 17 19:38:30 nixosdev gpg-agent[1575]: DBG: chan_9 -> OPTION default-ok=_OK
Jan 17 19:38:30 nixosdev gpg-agent[1575]: DBG: chan_9 <- OK
Jan 17 19:38:30 nixosdev gpg-agent[1575]: DBG: chan_9 -> OPTION default-cancel=_Cancel
Jan 17 19:38:30 nixosdev gpg-agent[1575]: DBG: chan_9 <- OK
Jan 17 19:38:30 nixosdev gpg-agent[1575]: DBG: chan_9 -> OPTION default-yes=_Yes
Jan 17 19:38:30 nixosdev gpg-agent[1575]: DBG: chan_9 <- ERR 83886254 Unknown option <Pinentry>
Jan 17 19:38:30 nixosdev gpg-agent[1575]: DBG: chan_9 -> OPTION default-no=_No
Jan 17 19:38:30 nixosdev gpg-agent[1575]: DBG: chan_9 <- ERR 83886254 Unknown option <Pinentry>
Jan 17 19:38:30 nixosdev gpg-agent[1575]: DBG: chan_9 -> OPTION default-prompt=PIN:
Jan 17 19:38:30 nixosdev gpg-agent[1575]: DBG: chan_9 <- OK
Jan 17 19:38:30 nixosdev gpg-agent[1575]: DBG: chan_9 -> OPTION default-pwmngr=_Save in password manager
Jan 17 19:38:30 nixosdev gpg-agent[1575]: DBG: chan_9 <- OK
Jan 17 19:38:30 nixosdev gpg-agent[1575]: DBG: chan_9 -> OPTION default-cf-visi=Do you really want to make your passphrase visible on the screen?
Jan 17 19:38:30 nixosdev gpg-agent[1575]: DBG: chan_9 <- OK
Jan 17 19:38:30 nixosdev gpg-agent[1575]: DBG: chan_9 -> OPTION default-tt-visi=Make passphrase visible
Jan 17 19:38:30 nixosdev gpg-agent[1575]: DBG: chan_9 <- OK
Jan 17 19:38:30 nixosdev gpg-agent[1575]: DBG: chan_9 -> OPTION default-tt-hide=Hide passphrase
Jan 17 19:38:30 nixosdev gpg-agent[1575]: DBG: chan_9 <- OK
Jan 17 19:38:30 nixosdev gpg-agent[1575]: DBG: chan_9 -> OPTION default-capshint=Caps Lock is on
Jan 17 19:38:30 nixosdev gpg-agent[1575]: DBG: chan_9 <- OK
Jan 17 19:38:30 nixosdev gpg-agent[1575]: DBG: chan_9 -> OPTION touch-file=/run/user/1000/gnupg/S.gpg-agent
Jan 17 19:38:30 nixosdev gpg-agent[1575]: DBG: chan_9 <- OK
Jan 17 19:38:30 nixosdev gpg-agent[1575]: DBG: chan_9 -> OPTION owner=164119/1000 nixosdev
Jan 17 19:38:30 nixosdev gpg-agent[1575]: DBG: chan_9 <- OK
Jan 17 19:38:30 nixosdev gpg-agent[1575]: DBG: chan_9 -> GETINFO flavor
Jan 17 19:38:30 nixosdev gpg-agent[1575]: DBG: chan_9 <- D tty
Jan 17 19:38:30 nixosdev gpg-agent[1575]: DBG: chan_9 <- OK
Jan 17 19:38:30 nixosdev gpg-agent[1575]: DBG: chan_9 -> GETINFO version
Jan 17 19:38:30 nixosdev gpg-agent[1575]: DBG: chan_9 <- D 1.2.0-unknown
Jan 17 19:38:30 nixosdev gpg-agent[1575]: DBG: chan_9 <- OK
Jan 17 19:38:30 nixosdev gpg-agent[1575]: DBG: chan_9 -> GETINFO ttyinfo
Jan 17 19:38:30 nixosdev gpg-agent[1575]: DBG: chan_9 <- D - - - - 1000/100 0
Jan 17 19:38:30 nixosdev gpg-agent[1575]: DBG: chan_9 <- OK
Jan 17 19:38:30 nixosdev gpg-agent[1575]: DBG: chan_9 -> GETINFO pid
Jan 17 19:38:30 nixosdev gpg-agent[1575]: DBG: chan_9 <- D 164121
Jan 17 19:38:30 nixosdev gpg-agent[1575]: DBG: chan_9 <- OK
Jan 17 19:38:30 nixosdev gpg-agent[1575]: DBG: chan_9 -> SETKEYINFO s/EE03DF21FC4EE33FA1D026589CD4ACF7DDF16C3F
Jan 17 19:38:30 nixosdev gpg-agent[1575]: DBG: chan_9 <- OK
Jan 17 19:38:30 nixosdev gpg-agent[1575]: DBG: chan_9 -> SETDESC Please enter the passphrase for the ssh key%0A  SHA256:0XhqDW8dp3otr9eYxvDgjfzfnzADd5nuirToRd7wQdg%0A  (user@nixos)
Jan 17 19:38:30 nixosdev gpg-agent[1575]: DBG: chan_9 <- OK
Jan 17 19:38:30 nixosdev gpg-agent[1575]: DBG: chan_9 -> SETPROMPT Passphrase:
Jan 17 19:38:30 nixosdev gpg-agent[1575]: DBG: chan_9 <- OK
Jan 17 19:38:30 nixosdev gpg-agent[1575]: DBG: chan_9 -> [[Confidential data not shown]]
Jan 17 19:38:30 nixosdev gpg-agent[1575]: DBG: chan_9 <- [[Confidential data not shown]]
Jan 17 19:38:31 nixosdev gpg-agent[1575]: DBG: error calling pinentry: Operation cancelled <Pinentry>
Jan 17 19:38:31 nixosdev gpg-agent[1575]: DBG: chan_9 -> BYE
Jan 17 19:38:31 nixosdev gpg-agent[1575]: failed to unprotect the secret key: Operation cancelled
Jan 17 19:38:31 nixosdev gpg-agent[1575]: failed to read the secret key
Jan 17 19:38:31 nixosdev gpg-agent[1575]: ssh sign request failed: Operation cancelled <Pinentry>
Jan 17 19:38:31 nixosdev gpg-agent[1575]: ssh request handler for sign_request (13) ready
Jan 17 19:38:31 nixosdev gpg-agent[1575]: DBG: chan_10 -> RESTART
Jan 17 19:38:31 nixosdev gpg-agent[1575]: DBG: chan_10 <- OK
Jan 17 19:38:31 nixosdev gpg-agent[1575]: ssh handler 0xffff7dc60120 for fd 8 terminated

When I launch pinentry-tty manually and repeat commands from log followed by GETPIN – it works. Furthermore if I call gpg-connect-agent UPDATESTARTUPTTY /bye ssh starts asking for password:

❯ git push
Please enter the passphrase for the ssh key
  SHA256:0XhqDW8dp3otr9eYxvDgjfzfnzADd5nuirToRd7wQdg
  (user@nixos)
Passphrase:

 *** Bad Passphrase (try 2 of 3) ***

However the correct password is never accepted! While ssh-add ~/.ssh/id_ed25519 works correctly with the very same password. Also I see the added key with:

❯ ssh-add -l
256 SHA256:0XhqDW8dp3otr9eYxvDgjfzfnzADd5nuirToRd7wQdg user@nixos (ED25519)

But anyway UPDATESTARTUPTTY is not an option for me because I usually use tmux and call ssh/git from different panes (but problem persists even without tmux).

I also noticed that when I call gpg --use-agent gpg-agent log explicitly set tty:

Jan 17 19:54:20 nixosdev gpg-agent[179312]: DBG: chan_9 -> OPTION ttyname=/dev/pts/4
Jan 17 19:54:20 nixosdev gpg-agent[179312]: DBG: chan_9 <- OK

while with ssh it doesn’t (until I do UPDATESTARTTY, but when I do, it doesn’t accept correct ssh key password anyway).

  programs.gnupg.agent.pinentryFlavor = "gtk2";

This is what fixed it for me. Counterintuitive, I know. But for some reason the gtk2 flavor has the best terminal fallback for this scenario.

You haven’t set services.gpg-agent.sshKeys.

See my config here.

Thank you for suggestions!
I’ve fixed my problem by:

  1. Removing package = pkgs.unstable.gnupg; from programs.gpg (I have unstable overlay in my pkgs and it doesn’t make sense since apparently something in NixOS modules refers to pkgs.gnupg while I’ve put unstable version of it while debugging my original problem).
  2. Setting
  programs.ssh =
    {
      extraConfig = ''
        Match host * exec "gpg-connect-agent UPDATESTARTUPTTY /bye"
      '';
    };

And manually calling gpg-connect-agent UPDATESTARTUPTTY /bye each time I do ssh-add.

This way it works with pinentry-tty but I’ve tried pinentry-gtk2, no difference.

As for setting services.gpg-agent.sshKeys, I work with lots of ssh keys which I frequently add/remove and don’t want my configuration repo clogged by sshKeys change commits.

Even though the problem is solved, I find it too redundant the need to call UPDATESTARTUPTTY every time I add new key (which I do frequently) and now I’m looking for another way to cache ssh keys.
Also I don’t like it to have my home-manager configuration depending on system configuration because I’m reusing my home-manager configurations on non-nixos systems as well.

Ah, so you were managing the sshcontrol file statefully. Since you didn’t mention it at all in your post, that I saw, I thought you hadn’t done anything with it.

Yep, sorry I only mentioned ssh-add -l but didn’t mention ssh-add.

By the way, I’ve found much simpler way to cache ssh key passwords for my workflow:

# removed all gpg-agent related configuration
  programs.keychain = {
    enable = true;
    keys = [ "id_ed25519" ];
  };

Each time I need to add new key, I just type keychain path/to/key.

1 Like