Skip to content

Instantly share code, notes, and snippets.

@TimJDFletcher
Forked from surhudm/GNUPG_agent_forwarding.md
Last active November 25, 2024 14:10
Show Gist options
  • Save TimJDFletcher/85fafd023c81aabfad57454111c1564d to your computer and use it in GitHub Desktop.
Save TimJDFletcher/85fafd023c81aabfad57454111c1564d to your computer and use it in GitHub Desktop.
GnuPG agent forwarding

Forward GnuPG agent from macOS to Linux

On the remote machine

Run gpg once as your to create the directory structure

gpg --list-keys

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:

Edit /etc/ssh/sshd_config to include the line:

StreamLocalBindUnlink yes

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

gpgconf --create-socketdir

On the local machine

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 gpgtunnel
    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 gpgtunnel
    hostname systemd-host.example.com
    User yourusername
    RemoteForward /run/user/<remote UID>/gnupg/S.gpg-agent /Users/<user>/.gnupg/S.gpg-agent.extra

Copy the public half of your keys to the remote machine:

scp $HOME/.gnupg/pubring.gpg gpgtunnel:$HOME/.gnupg/

You only have to copy the public half of the private key you are going to use, if you have that handy you can just copy it over and then use gpg --import mypublickey.pub

Now test that the gpg-agent works on the local machine:

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

Now ssh to remote machine

scp output gpgtunnel:
ssh gpgtunnel
gpg --decrypt output

The gpg-agent should be able to use your authentication on the local machine.

References

@themightyoarfish
Copy link

This doesn't work from macos to ubuntu 18.04

$ journalctl -xe
...
Mar 11 14:55:32 pact-cube sshd[4446]: error: bind: Address already in use
Mar 11 14:55:32 pact-cube sshd[4446]: error: unix_listener: cannot bind to path: /run/user/1001/gnupg/S.gpg-agent.extra

because systemd has already bound the socket?

@themightyoarfish
Copy link

Also $HOME/.gnupg/pubring.gpg does not seem to exist on macOS.

@TimJDFletcher
Copy link
Author

You will need to import the public key on the local mac first to create the pubring file, and there is a fix for that error in the ssh config option

@sebastianwebber
Copy link

You will need to import the public key on the local mac first to create the pubring file, and there is a fix for that error in the ssh config option

can you add details about how to do it?

I've tried to export the pub key (with gpg --export -a $MYKEYID ) in the mac, copied to the linux host with scp, imported with gpg --import /tmp/public.gpg.key and the decrypt didn't work, aborting with the gpg: decryption failed: No secret key error.

btw, awesome guide! :D

@cyrilMargaria
Copy link

I got it to work between OSX 11.5 and ubuntu 18.04. gpg && gpg-agent 2.3.2 (remote: 2.2.4)
The , should be replaced by the actual values.

On OSX, the pinentry-mac should be installed
Disclaimer: its possibly not the minimal requited configuration, I could not change the StreamLocalBindUnlink of the the remote system. So systemd part might not be needed.

Local configuration:

GPG agent:~/.gnupg/gpg-agent.conf

allow-loopback-pinentry
extra-socket /Users/<user>/.gnupg/S.gpg-agent.extra
pinentry-program /usr/local/bin/pinentry-mac

ssh (~/.ssh/config)

Host remote-host
   Hostname remote-host.donain.org
   RemoteForward /run/user/<uid>/gnupg/S.gpg-agent /Users/<user>/.gnupg/S.gpg-agent.extra

Remote configuration:

Remote gpg: ~/.gnupg/gpg.conf

use-agent
default-key <public key>

No interference from systemd.
I am not sure if its needed or has any effect.

systemctl --user disable gpg-agent-browser.socket gpg-agent-extra.socket gpg-agent-ssh.socket gpg-agent.socket
mkdir -p ~/.config/systemd/user/
cd ~/.config/systemd/user/
ln -s /dev/null gpg-agent-browser.socket 
ln -s /dev/null gpg-agent-extra.socket
ln -s /dev/null gpg-agent.socket
ln -s /dev/null gpg-agent-ssh.socket
systemctl --user daemon-reload

Initialize gpg

gpg --list-keys

Export public key from local machine to remote machine

On local machine: Export public key to remote host
gpg --export -a Public-key | ssh remote-host 'gpg --import -'

Verification

On remote machine:

gpg --decrypt output

That should prompt the pin entry on the local machine

@samveen
Copy link

samveen commented Mar 13, 2024

Worked between 2 aarch64 Raspberry PIs running Debian GNU/Linux 12 (bookworm) with the following caveats:

  • GPG was not setup on local host laptop.
  • Host with gpg-agent (key-host) was accessed via SSH with secure display forwarding ssh -Y from laptop
  • Remote Host git-dev-host was accessed using ssh from key-host.
  • pinentry alternative was set to pinentry-fltk as default pinentry-curses doesn't mix well with remote execution.
  • After complete configuration, both key-host and git-dev-host were restarted to get clean startup state.

The use case was to sign git commits on git-dev-host using the keys in key-host but accessed from the laptop.

I started with https://wiki.archlinux.org/title/GnuPG and used this gist when troubleshooting my issues.

NOTE: pinentry will always run on the machine where gpg-agent is running, so gpg's tty selection settings need to be set before sshing to the remote host:

me@key-host:~$ export GPG_TTY=$(tty)
me@key-host:~$ gpg-connect-agent updatestartuptty /bye
$ ssh -A me@git-dev-host

Ref. https://lists.gnutls.org/pipermail/gnupg-users/2020-November/064293.html

@WieeRd
Copy link

WieeRd commented Aug 2, 2024

Is it possible to forward gpg agent from local windows machine to remote linux server?

@TimJDFletcher
Copy link
Author

Is it possible to forward gpg agent from local windows machine to remote linux server?

No idea I've not used a Windows system in a long time

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