5. OpenSSH

OpenSSH is a FREE version of the SSH connectivity tools developed by the OpenBSD project. It certainly needs no introduction as it has now grown into the de facto standard for secure console access over the Internet, widely supplanting the infamous "r" commands.

Beginning with version 4.3, OpenSSH also provides secure VPN tunneling capabilities at both layer 2 and layer 3 of the OSI model, by using the tun(4) pseudo-device to encapsulate network traffic within SSH packets.

Of the VPN solutions we've seen so far, OpenSSH-based VPNs are by far the simplest to use and the fastest to implement; however, they also imply a considerable overhead. As a consequence, the documentation warns that OpenSSH VPNs may be more suited to temporary setups, such as for wireless VPNs, and recommends the use of IPsec for more permanent VPNs.

5.1 Configuration

We will configure the same VPN topology as in the previous chapters; the VPN1 machine will act as the OpenSSH server, waiting for connections from VPN2.

First off, we need to enable tunneling support on the OpenSSH server, since this feature is disabled by default. This is achieved by setting the PermitTunnel parameter in /etc/ssh/sshd_config(5) to "ethernet", "point-to-point" or "yes", depending on whether you want the VPN to operate, respectively, at layer 2 of the OSI model, layer 3 or both.

/etc/ssh/sshd_config
[ ... ]

# Enable layer-3 tunneling. Change the value to 'ethernet' for layer-2 tunneling
PermitTunnel point-to-point

On the client side, the Tunnel parameter, in /etc/ssh/ssh_config(5), must be set to the same value as PermitTunnel on the OpenSSH server:

/etc/ssh/ssh_config
[ ... ]

# Enable layer-3 tunneling. Change the value to 'ethernet' for layer-2 tunneling
Tunnel point-to-point

Next, we need to enable IP forwarding on both VPN gateways, since they will have to perform routing of network traffic:

# sysctl net.inet.ip.forwarding=1

Uncomment the following line in /etc/sysctl.conf(5) to re-enable it after reboot:

/etc/sysctl.conf
net.inet.ip.forwarding=1

And the configuration phase is over: how could it be easier? Now we only have to force sshd(8) to reread its configuration file by sending it a SIGHUP signal:

VPN1# pkill -HUP sshd

5.2 Starting the VPN

Before actually firing up the VPN, we will carry out a couple of preliminary steps on both the OpenSSH server and the client, i.e. creating and configuring the tun(4) network device and setting up the appropriate routes to the remote network(s) and hosts.

VPN1# ifconfig tun0 create
VPN1# ifconfig tun0 10.0.0.1 10.0.0.2 netmask 0xfffffffc
VPN1# route add 192.168.0.0/24 10.0.0.2
VPN1# route add 192.168.1.0/24 10.0.0.2
VPN2# ifconfig tun0 create
VPN2# ifconfig tun0 10.0.0.2 10.0.0.1 netmask 0xfffffffc
VPN2# route add 172.16.0.0/24 10.0.0.1

Well, we're finally ready to initiate the ssh(1) connection and establish the VPN tunnel. The -f option requests ssh(1) to go to background after prompting for the password, and the -w option specifies the numerical ID of the tun(4) device in charge of forwarding VPN traffic; in our setup, we're using tun0 on both client and server, so we will set this option to 0:0.

VPN2# ssh -f -w 0:0 1.2.3.4 true
root@VPN1's password: pAssWOrd

5.3 Finishing touches

To finish, we will configure the client machine to automatically start the VPN on boot. To prevent the system from hanging during startup until the user enters the password, we need to create an RSA authentication key for the user with the ssh-keygen(1) utility:

VPN2# ssh-keygen -b 2048 -t rsa
Generating public/private rsa key pair.
Enter file in which to save the key (/root/.ssh/id_rsa): <enter>
Enter passphrase (empty for no passphrase): <enter>
Enter same passphrase again: <enter>
Your identification has been saved in /root/.ssh/id_rsa.
Your public key has been saved in /root/.ssh/id_rsa.pub.
The key fingerprint is:
cd:9c:3b:3a:c0:92:7f:c2:9b:6e:3a:48:dc:50:a4:2a root@vpn2.kernel-panic.it
VPN2#

and add the newly-generated key, contained in /root/.ssh/id_rsa.pub, to the authorized keys in /root/.ssh/authorized_keys on the server; please make sure that this file has restrictive permissions (600):

VPN1# cat authorized_keys
ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAoWqL6wpgL5j3dlFtdYWT+cc72F/FtMhmTBLUEcCMQQy8
/V9CptSn7yCC+1R5xhZD8WO3d11c7R8pUHPP77A3omFruEpk4pREuisHnMtA6XyVFoxshhV1osyoQ/HJ
w6BhTmmGDCCyNsPmQyAPi9V7rL4NNSlll6mFXqLDNth6wf0qjo33BURsyKR6xxmt5QBhDpCBDel3EwLh
gE2Jy06XJZKa62/WU6ofbnXZWwGX8ZsbCPxqqu3EOBhMwlUgA1IgksGfOcB4rgV+qpcPUfl3fQM67Mc7
Nwhh7jqkaCTpu/vs4OpBFt6j9eVxMgRGylg4a9tBcZY2588wPZZThpx/sw== root@vpn2.kernel-pa
nic.it
VPN1# chmod 600 /root/.ssh/authorized_keys

Next, on the server side, we need to create the configuration file for the tun(4) pseudo-device, /etc/hostname.tun0, which will also include the necessary static routes:

/etc/hostname.tun0
10.0.0.1 10.0.0.2 netmask 0xfffffffc
!route add 192.168.0.0/24 10.0.0.2 >/dev/null 2>&1
!route add 192.168.1.0/24 10.0.0.2 >/dev/null 2>&1

Similarly, on the client side, we will create the /etc/hostname.tun0 configuration file:

/etc/hostname.tun0
10.0.0.2 10.0.0.1 netmask 0xfffffffc
!route add 172.16.0.0/24 10.0.0.1 >/dev/null 2>&1

but also add the VPN start command in /etc/rc.local(8).

/etc/rc.local
[ ... ]
echo -n ' OpenSSH-VPN'
/usr/bin/ssh -f -w 0:0 1.2.3.4 true