An tunnel is a way of providing a connection for which other connections can be made without revealing what they are. An SSH tunnel is using the SSH protocol to create such connection. One of the main benefit to an SSH tunnel is creating a secure tunnel between 2 points. For a tunnel to exist a connection needs to be established but also maintained. A SSH session usually has a timeout if no activity is detected from the server side.
One use I have found is to secure MySQL data. Whilst MySQL does support SSL connections not all applications have the ability to use it. For example WordPress 3.7.x does not support MySQL over SSL out of the box.
For a tunnel to exist there must be 2 servers running SSH. In this case server A will be initiating server with a IP of 10.0.0.1 to server B which has an IP address of 10.0.0.2. Examples of it’s use could be server B is a source control server, backup server or even a database. These are central services where external applications or servers require access to. It makes it easier to maintain the certificates on server B and revoke them later in one.
Both servers will be running Ubuntu but this should work on all Linux distributions.
This section applies to both servers and can be done in parallel.
Install SSH server:
sudo apt-get install openssh-client openssh-server
Create a new user called tunnel who will initate the connection. Once the connection is created the tunnel will be available to all users.
sudo useradd -m -s /bin/bash tunnel
Set a strong password for the new tunnel user:
sudo passwd tunnel
Switch to the tunnel user:
su - tunnel
Generate a SSH key with no password:
ssh-keygen
Note down the public key which is needed on Server B:
cat /.ssh/id_rsa.pub
Create a script which will check and keep the tunnel alive. Create a file called check_ssh_tunnel.sh:
touch check_ssh_tunnel.sh
Edit the file and add the following:
createTunnel() {
/usr/bin/ssh -f -N -L13306:hostb:3306 -L19922:hostb:22 tunnel@hostb
if [[ $? -eq 0 ]]; then
echo Tunnel to hostb created successfully
else
echo An error occurred creating a tunnel to hostb RC was $?
fi
}
## Run the ‘ls’ command remotely. If it returns non-zero, then create a new connection
/usr/bin/ssh -p 19922 tunnel@localhost ls
if [[ $? -ne 0 ]]; then
echo Creating new tunnel connection
createTunnel
fi
The above script was taken from Brandon Checketts site. I have created an maintained my own on github.
Replace hostb with server B’s address. The script forwards port 13306 on server A to 3306 on server B.
Switch to the tunnel user:
su - tunnel
If it does not exist create an authorised key file in .ssh:
mkdir .ssh
touch .ssh/authorized_keys
Add / append the public key from Server A into the authorised key file.
SSH from server A to server B to check the connection. It may prompt you to accept a server finger print which identifies server B is the correct server.
ssh tunnel@10.0.0.2
If successful close the connection by typing exit.
A second port is used to keep the tunnel alive. In the example above this is 19922 and doing a ls command. Run the script to check it works. If no existing tunnel exist then it will create one otherwise no output means the tunnel was checked and still OK.
After checking the script, create a cron entry as the runnel user on server A. It should run the script every so often to check and keep the connection alive.
crontab -e
Add the following to run the check_ssh_tunnel.sh every minute and on boot:
* * * * * /home/tunnel/check_ssh_tunnel.sh
@reboot /home/tunnel/check_ssh_tunnel.sh
This is a crude but good way to encrypt data between two points. I’ve tested the setup for the past month and it seems to hold up well. I’ve improved on the script from Brandon’s example to parameterise some of the commands to make it easier to configure.
Danny’s bashTunnel
Creating a Permanent SSH Tunnel Between Linux Servers
Running A Python Script At Boot Using Cron