SSH Authentication with OpenPGP

Posted on 30 2026

The GPG agent can act as an SSH agent, using your GPG authentication subkey to handle SSH connections. This means instead of managing separate SSH keys alongside your GPG keys, your authentication subkey covers both. When combined with a Yubikey, which stores the private key on hardware, this becomes a particularly clean arrangement: a single physical device handles GPG operations and SSH authentication across every server in your network.

This page covers the software-only setup. The Yubikey integration is covered in the Yubikey section.

Why bother

The honest answer is that for a straightforward setup with one or two servers, separate SSH keys work perfectly well and are simpler to reason about. The GPG agent SSH approach earns its complexity when you have a Yubikey involved, or when you want a single unified key management story rather than two parallel systems.

If you are following this series without a Yubikey, you may prefer to skip this page and continue using dedicated SSH keys as described in the Keys section. There is no wrong answer here.

If you do have a Yubikey, or are planning to get one, read on.

Prerequisites

The GPG agent configuration from the setup page must be in place, specifically enable-ssh-support in ~/.gnupg/gpg-agent.conf. If you have not done that yet, go back and do it before continuing.

Verify the agent is running with SSH support:

gpgconf --list-dirs agent-ssh-socket

This should return a socket path. If it returns nothing, reload the agent:

gpgconf --reload gpg-agent

Pointing SSH at the GPG agent

By default, SSH looks for its agent at the socket path stored in $SSH_AUTH_SOCK. You need to point this at the GPG agent socket instead.

Add the following to your ~/.bashrc, replacing or supplementing the SSH agent socket configuration:

# Use GPG agent as SSH agent
unset SSH_AGENT_PID
if [ "${gnupg_SSH_AUTH_SOCK_by:-0}" -ne $$ ]; then
    export SSH_AUTH_SOCK="$(gpgconf --list-dirs agent-ssh-socket)"
fi

The check against gnupg_SSH_AUTH_SOCK_by prevents the socket from being overridden if another process has already set it correctly. Reload your shell:

source ~/.bashrc

Verify SSH is now talking to the GPG agent:

ssh-add -L

If the agent is configured correctly this will list any keys currently available to the agent. If no authentication subkey has been added yet, it will return an empty list rather than an error.

Adding your authentication subkey

The GPG agent does not automatically expose all GPG keys to SSH. You need to explicitly tell it which authentication subkey to use, by adding its keygrip to the sshcontrol file.

Find the keygrip of your authentication subkey:

gpg --list-keys --with-keygrip $GPGKEY

The output will show each key and subkey with a Keygrip line beneath it. Find the entry with [A] (authentication) capability and note its keygrip. It will be a 40-character hexadecimal string.

Add it to the sshcontrol file:

echo "<your-keygrip-here>" >> ~/.gnupg/sshcontrol

The optional second field on that line is a cache TTL in seconds. To use the agent’s default TTL, leave it at zero:

echo "<your-keygrip-here> 0" >> ~/.gnupg/sshcontrol

Verify it is now available to SSH:

ssh-add -L

This should now list your authentication subkey in OpenSSH public key format.

Distributing the SSH public key to servers

The output of ssh-add -L is your SSH public key in the format that goes in authorized_keys on remote servers. Copy it to each server you want to access:

ssh-add -L | ssh user@server "cat >> ~/.ssh/authorized_keys"

Or use ssh-copy-id with the key exported to a temporary file:

gpg --export-ssh-key $GPGKEY > /tmp/gpg_auth_key.pub
ssh-copy-id -f -i /tmp/gpg_auth_key.pub user@server
rm /tmp/gpg_auth_key.pub

Testing the connection

With the public key on the server and the GPG agent running locally:

ssh user@server

The GPG agent will prompt for your key passphrase via the Qt pinentry dialog. Once entered, the agent caches it for the duration of the session according to the TTL settings in gpg-agent.conf.

To confirm the connection is using your GPG authentication subkey rather than a separate SSH key:

ssh -v user@server 2>&1 | grep "Offering public key"

The output should reference the key fingerprint matching your authentication subkey.

Handling multiple identities

If you have multiple UIDs on your GPG key, or multiple keys, you can control which key is offered for a specific host by adding entries to ~/.ssh/config:

Host server.yourdomain.net
    IdentityFile /dev/null
    IdentitiesOnly yes

Setting IdentitiesOnly yes and IdentityFile /dev/null tells SSH to only use keys offered by the agent, not any key files found in ~/.ssh. This prevents SSH from trying other keys before the GPG agent key.

Reloading after changes

If you change the sshcontrol file or the agent configuration:

gpgconf --reload gpg-agent

If the agent has stopped responding entirely:

gpgconf --kill gpg-agent
gpg-agent --daemon

The agent will restart and pick up the new configuration.

KDE session startup

On Kubuntu, the KDE session manager may start its own SSH agent at login, which can conflict with the GPG agent SSH socket. If you find $SSH_AUTH_SOCK is being overridden after login, check the KDE autostart configuration:

ls ~/.config/autostart/

If there is an SSH agent autostart entry, disable it. The GPG agent handles SSH as of the configuration above, so a separate SSH agent is redundant.

The GPG agent SSH socket is session-scoped. If you log out and back in, the agent restarts and the passphrase cache clears. Keys in sshcontrol persist across sessions. Passphrase caches do not.