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 http://sshmenu.sourceforge.net/articles/transparent-mulithop.html. 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
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:
#!/bin/sh # Invoked as /home/pi/piconnect -c <target> target=$2 case $target in <target>) addr=`cat /home/pi/addr/$target.addr`;; *) exit;; esac 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
On the target machine B
Add a script /root/ssh-register
#!/bin/sh IP=`hostname -I` ssh -l pi -i /root/.ssh/id_rsa <bridge> "echo $IP >addr/<target>.addr"
Then add the line
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.