YubiKey U2F Two-Factor Authentication with OpenVPN and Viscosity
After setting up your own OpenVPN server, you may want to enhance it's security. One way to do that is to use 2FA (Two Factor Authentication). This adds another security measure to prevent unwanted users connecting to your server. One type of 2FA is U2F (Universal Two Factor) with a YubiKey. This guide will expand on setting up an OpenVPN server on Ubuntu by adding U2F support to that server using Viscosity's built in U2F support which was added in version 1.7.7.
For this guide, we assume:
- You have already installed the latest version of Ubuntu (16.04 at time of writing)
- You have root access to this installation
- You have already an OpenVPN server running using one of our guides
- You already have a copy of Viscosity installed on your client device and already setup for this server
- Your copy of Viscosity is at least version 1.7.7
- You have a YubiCo YubiKey that supports U2F
- Your OpenVPN server has a Fully Qualified Domain Name (FQDN), more information below.
This guide assumes you have followed one of our server setup guides and you are already able to connect to the server we will be modifying using certificate/key authentication. This guide will add two more authentication steps. A username and password using PAM, and a challenge request using a YubiKey's U2F support.
PAM authentication is the simplest form of username/password authentication we can use with OpenVPN. PAM uses the Ubuntu's user management to authenticate against so we don't need to manage an extra database of username and passwords. If you want to add a new user to be able to authenticate, you can simply add the new user with the useradd command in Ubuntu.
A final requirement to support U2F is your server must have a FQDN. U2F requires that you must connect to your OpenVPN server with a domain name, not an IP Address. A dynamic DNS service is fine if you are connecting back to your home For a server you are hosting on a VPS though for example, we recommend you register a domain address, something like myserver.mydomain.com.
The follow instructions for Ubuntu assume that you have already setup an OpenVPN server using our Setting up an OpenVPN server with Ubuntu and Viscosity guide.
As this is a newer type of 2FA, OpenVPN needs some modifications to support U2F. To do this we will need to download OpenVPN's source code and recompile it after applying a small patch.
NOTE: This patch is required for OpenVPN 2.4.4 and earlier. We are working towards getting this patch submitted to OpenVPN so this step won't be required in the future.
First, connect to your Ubuntu server, we are assuming for this guide you are connected via SSH and have root access. Change to your home directory with
Next we need to install a couple or pre-requisites to compile OpenVPN:
apt-get install pkg-config libssl-dev liblzo2-dev libpam-dev libpkcs11-helper-dev
Once these packages have finished installing, download the latest OpenVPN source, extract it then enter the directory:
tar xvf openvpn-2.4.4.tar.gz
Next, download the required patch here and copy it to the openvpn-2.4.4 directory with SCP, alternatively you can grab it with:
wget -O openvpn2.4_u2f.diff https://www.sparklabs.com/support/kb/article/yubikey-u2f-two-factor-authentication-with-openvpn-and-viscosity/openvpn2-4_u2f
Then apply the patch:
patch -p0 -N -i openvpn2.4_u2f.diff
Finally, we can compile OpenVPN and install it:
make && make install
Run a test to ensure installation was successful, you should see a build date of today:
$ openvpn --version OpenVPN 2.4.4 x86_64-unknown-linux-gnu [SSL (OpenSSL)] [LZO] [LZ4] [EPOLL] [PKCS11] [MH/PKTINFO] [AEAD] built on TODAYS DATE HERE
Installing U2F Requirements
Now OpenVPN will support U2F, we can configure the server. We will be using a python script which connects to the management interface of OpenVPN and handles some management commands to support both PAM authentication and U2F. First, we need to install some pre-requisites for python with PIP:
apt-get install python-pip
pip install --upgrade pip
pip install u2fval u2fval-client pam
Once this is all done, we can setup our U2F server, u2fval. This server handles authorising and registering U2F tokens for us. First, create the configuration for u2fval:
mkdir -p /etc/yubico/u2fval
Paste the following into the nano window and save the file:
SQLALCHEMY_DATABASE_URI = 'sqlite:////etc/yubico/u2fval/u2fval.db'
Next, we can configure the client. Run the following commands, replacing YOURSERVER with the address of your server:
u2fval db init
u2fval client create openvpn openvpn://YOURSERVER
u2fval is a REST API. If we were using it for multiple services, we could host it with Apache or NGINX, but as we're using it on the same machine as our OpenVPN server, running it locally is fine. We'll create a service so u2fval runs on it's own and at startup. Create a new service with:
Now paste the following into the nano window and save the file:
[Unit] Description=U2F Validation REST Server [Service] ExecStart=/usr/local/bin/u2fval run [Install] WantedBy=multi-user.target
Start and enable the service with the following:
systemctl enable u2fval.service
systemctl start u2fval.service
Setting up U2F
Now all the requirements we need are installed and setup, we can interface U2F with OpenVPN. First, we need to modify our OpenVPN server configuration. First, stop and disable the existing server using:
systemctl stop [email protected]
systemctl disable [email protected]
Then we can make a copy of the existing server and edit the configuration:
cp /etc/openvpn/example.conf /etc/openvpn/u2f.conf
Scroll to the bottom of the configuration and on a new line add the following:
#Management commands for U2F management management 127.0.0.1 55555 management-client-auth
Save the configuration, but do not restart the server. The version of OpenVPN we installed from apt-get with it's service does not point to OpenVPN that we built. It's a bad idea to modify what installed as it will be overwritten next time OpenVPN is updated. So for now, we will create our own service to use.
Create a new service file with the following:
Then paste in the following and save the file:
[Unit] Description=OpenVPN U2F Supported server After=network.target [Service] PrivateTmp=true KillMode=mixed Type=forking ExecStart=/usr/local/sbin/openvpn --daemon ovpn-u2f --status /run/openvpn/u2f.status 10 --cd /etc/openvpn --script-security 2 --config /etc/openvpn/u2f.conf --writepid /run/openvpn/u2f.pid PIDFile=/run/openvpn/u2f.pid ExecReload=/bin/kill -HUP $MAINPID WorkingDirectory=/etc/openvpn ProtectSystem=yes CapabilityBoundingSet=CAP_IPC_LOCK CAP_NET_ADMIN CAP_NET_BIND_SERVICE CAP_NET_RAW CAP_SETGID CAP_SETUID CAP_SYS_CHROOT CAP_DAC_READ_SEARCH CAP_AUDIT_WRITE LimitNPROC=10 DeviceAllow=/dev/null rw DeviceAllow=/dev/net/tun rw [Install] WantedBy=multi-user.target
Next you will need to grab our example script. Save it to /etc/openvpn/openvpn_u2f_auth.py by the following:
Now we can create a service for this script to run on it's own. Create a new service file with the following:
Then paste in the following and save the file:
[Unit] Description=OpenVPN U2F Supported server After=openvpnu2f.service [Service] ExecStart=/usr/bin/python /etc/openvpn/openvpn_u2f_auth.py --port 55555 [Install] WantedBy=multi-user.target
Now we can enable and start up our services:
systemctl enable openvpnu2f.service
systemctl start openvpnu2f.service
systemctl enable openvpnu2fauthenticator.service
systemctl start openvpnu2fauthenticator.service
That's it, our server is ready to go with U2F support! We just need to make a quick change to our configuration, read on.
Setting up Viscosity
Now the server is setup, we only need to make a single change to Viscosity:
- Open Viscosity's Preferences and edit your connection.
- Go to the Networking tab and tick 'Use Username/Password authentication'
- Save the connection
If during this guide you registered a dyamic DNS or domain name for your OpenVPN server, also change your servers IP address to the new address.
Now that the changes to your configuration in Viscosity are finished, you can connect to the VPN server to test the connection. The first time you connect you'll be prompted to register your U2F security key. Simply follow the on-screen instructions by connecting your key to your computer, and if required tapping the gold disk or button on the device to activate and register it.
Once you have registered your device, or if it is already registered, you'll be prompted to authenticate using your security key. Again, simply make sure your key is connected to your computer, and if required tap the gold disk or button on the device to activate it and authenticate. Your VPN connection will then proceed to connect if authentication was successful.