Weblog entry #68 for dkg

forwarding unix domain sockets with ssh and socat
Posted by dkg on Thu 2 Dec 2010 at 09:41
i suspect a lot of people are used to forwarding TCP sockets with SSH -- for example, to connect locally to a mysql daemon that runs only on the loopback interface of a remote machine (this is debian's default mysql-server configuration):
ssh -N -T -oExitOnForwardFailure=yes -L 3306:localhost:3306 remoteuser@mysqlserver.example

But sometimes, the remote service runs on a UNIX-domain socket, not on a TCP socket -- for example, debian's default configuration for postgresql is to have it listen only on a UNIX domain socket in /var/run/postgresql, and use SO_PEERCRED with a simple system account == psql account mapping scheme to authenticate users without needing any extra credentials. This is not quite as simple to forward over ssh, but it's doable as long as socat is installed on both your local host and on the remote postgres server.

Here's one way to do it if $SOCKET_DIR points to the full path of a directory under the user's control (this is all one command, split across lines for easier reading):

socat "UNIX-LISTEN:$SOCKET_DIR/.s.PGSQL.5432,reuseaddr,fork" \
   EXEC:'ssh remoteuser@psqlserver.example socat STDIO UNIX-CONNECT\:/var/run/postgresql/.s.PGSQL.5432'
Then, you'd connect with something like:
psql "user=remoteuser host=$SOCKET_DIR"
Each such psql connection will trigger an ssh connection to be made. Of course, this won't work well if ssh has to prompt for passwords, but you should be using ssh-agent anyway, right?

There are at least a couple nice features of being able to use postgresql from a local client like this:

  • your psql client can load files from your local machine, and can dump/export files to the local machine.
  • your ~/.psql_history stays local, so you can review what you did even when you're offline
  • you can run local RDBMS administrative GUIs like pgadmin3 with minimal network traffic and no extra packages installed on the server.
  • unlike forwarding TCP ports (where any other user account on the machine can hop onto your connection), you can control access to your local UNIX-domain socket with standard filesystem permissions on $SOCKET_DIR.
Of course, postgresql itself already comes with a nice range of high-quality network-capable authentication mechanisms you could use. But many of them (like GSSAPI or X.509 mutual key-based authentication over TLS) require additional infrastructure setup; and you probably already have sshd up and running on that machine -- so why not make use of it?

 

Comments on this Entry

Posted by Anonymous (62.210.xx.xx) on Thu 2 Dec 2010 at 12:30
Nice!

Did you know that SSH already has code to forward Unix sockets? This code is used only for the specific case of X11 forwarding, but it is there.

Unfortunately there is no interface to ask for generic socket forwarding, which would allow things like your PostgreSQL forwarding, PulseAudio forwarding and so on. Here your trick comes handy. Thanks!

[ Parent | Reply to this comment ]

Posted by Anonymous (184.88.xx.xx) on Fri 3 Dec 2010 at 05:04
Interesting. It made me think of another useful application: allowing TCP connections to your X server if it was started with "-nolisten tcp" (I always remove that, but when I upgrade my Ubuntu it always comes back :-/) and you don't want to restart X right now:

socat TCP4-LISTEN:6000,reuseaddr,fork UNIX-CONNECT:/tmp/.X11-unix/X0

[ Parent | Reply to this comment ]

Posted by dkg (216.254.xx.xx) on Fri 3 Dec 2010 at 16:52
[ View dkg's Scratchpad | View Weblogs ]
I'm not a big fan of this approach for X11, actually.

If the X server itself is listening on TCP, it knows that it is listening on the network and can apply different rules and policy based on that fact.

If you use socat proxy the network in to the X server, it assumes that each inbound connection is coming from your account. You're basically inviting anyone who decides to connect to port 6000 on your computer to execute arbitrary code as your user. This strikes me as a Bad Idea.

The reason my postgresql + ssh + socat example above is different is that ssh is authenticating the connections, and the traffic itself is encrypted and integrity-checked. So arbitrary network attackers can't DROP TABLES on me ;)

[ Parent | Reply to this comment ]

Posted by Anonymous (188.222.xx.xx) on Sat 4 Dec 2010 at 13:38
Neat. I tried to achieve this to forward gpg-agent, but I didn't really get anywhere. I'm not sure if additional sanity checks in gpg-agent scuppered me or if I just did it wrong. Perhaps your recipe will help me... - (Jon/jmtd.net)

[ Parent | Reply to this comment ]

Posted by dkg (2001:0xx:0xx:0xxx:0xxx:0xxx:xx) on Sat 4 Dec 2010 at 20:00
[ View dkg's Scratchpad | View Weblogs ]
Ah, that's an interesting suggestion too.

i'd be a little wary about forwarding gpg-agent to a remote host, though -- that would mean that anyone with control over the remote account (including the administrator of that machine) could get unfettered access to the material stored in the gpg-agent. This is could be mitigated by having the gpg-agent prompt the user for accepted use, but this appears to be a contentious issue for gpg (i think it would be a fine idea).

Note also that gpg-agent in its 1.x and 2.0.x versions doesn't actually cache the secret key material for OpenPGP certifications. It only caches passphrases, and the gpg binary itself needs to have access to the encrypted secret key, which it can unlock with the passphrase it fetches from the agent. This makes it not terribly useful for forwarding gpg-agent over the network, because you'd need to distribute your secret key to the remote system as well (yikes!)

Werner Koch has said that gpg 2.1 will move all secret key handling directly into the agent, though, which makes your proposed approach seem more useful to me.

[ Parent | Reply to this comment ]

Posted by fugit (69.112.xx.xx) on Mon 5 Sep 2011 at 16:35
[ View Weblogs ]
dkg, Thanks for the great right up. I really like the idea of using gui tools on my local machine with out having to install more on the postgresql server or setting it up to linsten on a port.

[ Parent | Reply to this comment ]