Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
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

themightyoarfish commented Mar 11, 2021

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

themightyoarfish commented Mar 11, 2021

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

@TimJDFletcher
Copy link
Author

TimJDFletcher commented Mar 27, 2021

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

sebastianwebber commented Aug 5, 2021

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

cyrilMargaria commented Aug 31, 2021

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

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