Skip to content

Instantly share code, notes, and snippets.

@samveen
Forked from TimJDFletcher/GNUPG_agent_forwarding.md
Last active September 3, 2025 13:24
Show Gist options
  • Select an option

  • Save samveen/70df8317b819b65500fd9db3eee1df7f to your computer and use it in GitHub Desktop.

Select an option

Save samveen/70df8317b819b65500fd9db3eee1df7f to your computer and use it in GitHub Desktop.
GnuPG agent forwarding

Forward GnuPG agent from key-host to signing-host

On the signing host

Run gpg once as your to create the directory structure

gpg --list-keys

For all types of signing hosts

Make the public key of the signing key available on the signing host after completing all the key host steps (last command in that section).

For headless systemd based hosts

Disable gpg-agent startup via systemd by masking the sockets:

sudo systemctl --global mask gpg-agent.service gpg-agent.socket gpg-agent-ssh.socket gpg-agent-extra.socket gpg-agent-browser.socket
killall gpg-agent

For interactive systemd hosts

If you want to maintain the auto start and stop of gpg-agent on the host you need to do the following:

Create a file /etc/ssh/sshd_config.d/gpg-cleanup.conf to include the line:

StreamLocalBindUnlink yes

Add this line to your user's $HOME/.bashrc:

gpgconf --create-socketdir

On the key host

Add this line to the file: $HOME/.gnupg/gpg-agent.conf

extra-socket $HOME/.gnupg/S.gpg-agent.extra

Reload your current gpg-agent:

gpg-connect-agent reloadagent /bye

Edit $HOME/.ssh/config to forward the gpg-agent socket. Note this doesn't support ssh config variables so you need to use the full path.

Forwarding from macOS to Linux:

host signinghost
    hostname remotehost.example.com
    User yourusername
    RemoteForward /home/<user>/.gnupg/S.gpg-agent /Users/<user>/.gnupg/S.gpg-agent.extra

Forwarding from macOS to systemd based Linux, use id -u on the remote system to find your UID:

host signinghost
    hostname systemd-host.example.com
    User yourusername
    RemoteForward /run/user/<remote UID>/gnupg/S.gpg-agent /Users/<user>/.gnupg/S.gpg-agent.extra

Forwarding from one systemd based Linux to another, use id -u on the both systems to find your UIDs:

host signinghost
    hostname systemd-host.example.com
    User yourusername
    RemoteForward /run/user/<SIGN-HOST-UID>/gnupg/S.gpg-agent /run/user/<KEY-HOST-UID>/gnupg/S.gpg-agent.extra

Additionally, for linux based key hosts, run the following (or add it to ~/.bashrc or equivalent shell rc), to tell gpg-agent the terminal where pinentry should pop up the keyphrase dialog:

$ export GPG_TTY=$(tty)
$ gpg-connect-agent updatestartuptty /bye

On the signing host after doing all the steps on the key host

Make the public key available on the signing host

Copy the GPG public keyring to the signing host (now named signinghost via .ssh/config):

scp ~/.gnupg/pubring.kbx signinghost:.gnupg/

Instead of copying the public keyring, you can instead import the public key of your GPG signing key on the signing host, if you have that handy:

gpg --import mypublickey.pub

Trust the key

Get the key ID of the key from the server

gpg --list-keys

Trust the signing key

gpg --edit-key $KEYID_FROM_LIST_KEY_OUTPUT
....................
..Key details here..
....................

gpg> trust
....................
..Key details here..
....................

Please decide how far you trust this user to correctly verify other users' keys
(by looking at passports, checking fingerprints from different sources, etc.)

  1 = I don't know or won't say
  2 = I do NOT trust
  3 = I trust marginally
  4 = I trust fully
  5 = I trust ultimately
  m = back to the main menu

Your decision? 5
Do you really want to set this key to ultimate trust? (y/N) y

gpg> quit

Testing

Key host test

Now test that the gpg-agent works on the key host:

echo "test" | gpg --encrypt -r $MYKEYID 
echo "test" | gpg --encrypt -r $MYKEYID > output
gpg --decrypt output

Signing host test

copy the encryted file to the signing host (now named signinghost via .ssh/config) and try decrypting there:

scp output signinghost:
ssh $SIGNING_HOST
gpg --decrypt output

The gpg-agent should be able to use the key from the key host on the signing host.

Testing environments

  • Debian 12 key host, with Debian 12 signing host
  • Debian 11 key host, with Debian 12 signing host

References

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment