Proxy ssh

From Spivey's Corner
Jump to: navigation, search

Here's now to set up ssh access to a machine B (such as a Raspberry Pi) behind a firewall, given a machine A that is accessible from outside the firewall and itself has ssh access to B, without the need for users of machine B to have an account on machine A. These hints are an extended version of what's available at These commands deal with a setup where the IP address of the machine B can vary – for example, if it is assigned dynamically – by making machine B register itself with machine A when it boots. The setup below is easily adapted to multiple target machines, each registering itself under a different name.

Replace <bridge> with the name of machine A and <target> with the name of machine B in what follows.

On the bridge machine A

Create two users pi and piconnect with these lines in /etc/passwd:


Disable passwords for both accounts by setting the password field in /etc/shadow to '*'. Or (with less security) give piconnect an empty password, and follow the instructions below to enable empty passwords.

Make /home/pi and /home/pi/.ssh belong to root, and create a subdirectory /home/pi/addr belonging to the user pi.

drwxr-xr-x   5 root      root         4096 Dec  2 20:55 /home/pi
drwxr-xr-x   2 root      root         4096 Dec  2 20:51 /home/pi/.ssh
-rw-r--r--   1 piconnect piconnect     396 Dec  2 20:04 /home/pi/.ssh/connection_keys
-rw-r--r--   1 pi        pi            398 Dec  2 20:03 /home/pi/.ssh/authorized_keys
drwxr-xr-x   2 pi        pi           4096 Dec  2 20:50 /home/pi/addr
-rwxr-xr-x   1 pi        pi            168 Dec  2 20:55 /home/pi/piconnect

It's important the two directories are owned by root, otherwise the two users pi and piconnect can't both keep ssh config files here, and ssh complains about bad owners and modes.

Put this script in /home/pi/piconnect:

# Invoked as /home/pi/piconnect -c <target>
case $target in
    addr=`cat /home/pi/addr/$target.addr`;;
nc -q0 $addr 22

We carefully match the name of the target to block attacks.

Add these lines to the end of /etc/ssh/sshd_config:

Match User piconnect
  # PermitEmptyPasswords yes
  AuthorizedKeysFile /home/pi/.ssh/connection_keys

If desired, uncomment the line for empty passwords, and edit /etc/pam.d/common-auth to replace nullok_secure by nullok

On the target machine B

Add a script /root/ssh-register

IP=`hostname -I`
ssh -l pi -i /root/.ssh/id_rsa <bridge> "echo $IP >addr/<target>.addr"

Then add the line

sh /root/ssh-register

to /etc/rc.local. Generate an SSH keypair and copy the public key to /home/pi/.ssh/authorized_keys on machine A.

On the client

Add these lines to ~/.ssh/config:

Host <target>
  ProxyCommand ssh -q -l piconnect <bridge> <target>
  # ControlMaster auto
  # ControlPath ~/.ssh/sockets/%r@%h-%p
  # ControlPersist 600

Generate an SSH keypair if you don't have one, and install the public key in /home/pi/.ssh/connection_keys on machine A, making sure it is owned by piconnect. Or rely on an empty password for piconnect.

Now the command ssh <target> should start an SSH session on the target, even through the firewall.

To speed up multiple connections – for example, if ssh is used many times in a shell script – uncomment the extra lines shown, and create a directory ~/.ssh/sockets. This causes the first connection to the remote to hang around for up to 10 minutes and be reused for subsequent commands.