Take the 2-minute tour ×

I can use the ssh configuration file to enable the forwarding of ssh keys added to ssh-agent. How can I do the same with gpg keys?

share|improve this question
add comment

2 Answers

up vote 10 down vote accepted

SSH is only capable of forwarding tcp connections within the tunnel.

You can, however, use a program like socat to relay the unix socket over TCP, with something like that (you will need socat both on the client and the server hosts):

# Get the path of gpg-agent socket:
GPG_SOCK=$(echo "$GPG_AGENT_INFO" | cut -d: -f1)

# Forward some local tcp socket to the agent
(while true; do
    socat TCP-LISTEN:12345,bind= UNIX-CONNECT:$GPG_SOCK;
done) &

# Connect to the remote host via ssh, forwarding the TCP port
ssh -R12345:localhost:12345 host.example.com

# (On the remote host)
(while true; do
    socat UNIX-LISTEN:$HOME/.gnupg/S.gpg-agent,unlink-close,unlink-early TCP4:localhost:12345;
done) &

Test if it works out with gpg-connect-agent. Make sure that GPG_AGENT_INFO is undefined on the remote host, so that it falls back to the $HOME/.gnupg/S.gpg-agent socket.

Now hopefully all you need is a way to run all this automatically!

share|improve this answer
Well the ssh agent keys are forwarded automatically when the forwarding is set in the configuration file. I will try this out. –  txwikinger Jul 19 '10 at 14:18
You're right, ssh-agent uses a unix socket too, but has special support for it (little bit tired here :) Nevertheless, the solution should still work. –  b0fh Jul 19 '10 at 14:32
For this solution, my gpg-agent would be publicy accessible via port 12345 if I was not behind a firewall/NAT. This should be mentioned in the answer please. –  Jonas Wielicki Apr 30 '12 at 14:46
I'm guessing your last edit fixed that issue, Jonas? it's only binding to localhost now. –  jmtd May 1 '12 at 8:19
This fails for me with the following argument from the remote host's gpg-connect-agent: can't connect to server: ec=31.16383 gpg-connect-agent: error sending RESET command: Invalid value passed to IPC. The remote socat then dies. The local socat dies and utters socat[24692] E connect(3, AF=1 "", 2): Invalid argument. This page leads me to believe that this will never work, because the agent doesn't store the key (just the passphrase). Has this been confirmed to work by anyone? –  jmtd May 1 '12 at 8:24
show 2 more comments

I had to do the same, and based my script on the solution by b0fh, with a few tiny modifications: It traps exits and kills background processes, and it uses the "fork" and "reuseaddr" options to socat, which saves you the loop (and makes the background socat cleanly kill-able).

The whole thing sets up all forwards in one go, so it probably comes closer to an automated setup.

Note that on the remote host, you will need:

  1. The keyrings you intend to use to sign/en/decrypt stuff.
  2. Depending on the version of gpg on the remote, a fake GPG_AGENT_INFO variable. I prefill mine with ~/.gnupg/S.gpg-agent:1:1 - the first 1 is a PID for the gpg agent (I fake it as "init"'s, which is always running), the second is the agent protocol version number. This should match the one running on your local machine.

#!/bin/bash -e


trap '[ -z "$LOCAL_SOCAT" ] || kill -TERM $LOCAL_SOCAT' EXIT

if [ -z "$GPG_SOCK" ] ; then
    echo "No GPG agent configured - this won't work out." >&2
    exit 1

socat TCP-LISTEN:$FORWARD_PORT,bind=,reuseaddr,fork UNIX-CONNECT:$GPG_SOCK &

ssh -R $FORWARD_PORT:$FORWARD_PORT socat 'UNIX-LISTEN:$HOME/.gnupg/S.gpg-agent,unlink-close,unlink-early,fork,reuseaddr TCP4:localhost:$FORWARD_PORT'

I believe there's also a solution that involves just one SSH command invocation (connecting back from the remote host to the local one) using -o LocalCommand, but I couldn't quite figure out how to conveniently kill that upon exit.

share|improve this answer
add comment

Your Answer


