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.
Preparation
For this guide, we assume:
- You have already installed the latest version of Ubuntu LTS (22.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
- 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.
Ubuntu
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.
Modifying OpenVPN
As this is a newer type of 2FA, OpenVPN needs some modifications to support U2F. We've done the heavy lifting for you for Ubuntu, however if you would like to view the patch, or recompile OpenVPN yourself, you can download the patches here and here, or view them in our PPA.
First, remove your current OpenVPN install and any other apt repo's you have added for OpenVPN, we're assuming you've followed our Ubuntu guide:
sudo systemctl stop openvpn@server
sudo systemctl disable openvpn@server
sudo apt remove openvpn
sudo rm /etc/apt/sources.list.d/openvpn-aptrepo.list
sudo rm /etc/apt/sources.list.d/openvpn-aptrepo.list.save
sudo apt update
Next, add our PPA so you can install the modified version of OpenVPN:
sudo apt install software-properties-common
sudo add-apt-repository ppa:sparklabs/ppa
Press Enter to confirm
And the install the modified OpenVPN, the U2F plugin for OpenVPN and other requirements.
sudo apt update
sudo apt install openvpn openvpn-u2f-plugin python3-pip
To confirm you've installed the right version of OpenVPN, enter the following:
openvpn --version
If the correct OpenVPN was installed, you should see [FIDO] in the output, for example:
OpenVPN 2.6.6 aarch64-unknown-linux-gnu [SSL (OpenSSL)] [LZO] [LZ4] [EPOLL] [PKCS11] [MH/PKTINFO] [AEAD] [DCO] [FIDO]
Installing U2F Requirements
Now OpenVPN will support U2F, we can configure the server for U2F. The plugin uses a python script which interfaces with the u2fval package. We've updated the package recently so it needs to be downloaded from our github and installed with the following:
wget https://github.com/thesparklabs/u2fval/releases/download/2.0.3/u2fval-2.0.3.tar.gz
sudo python3 -m pip install u2fval-2.0.3.tar.gz
sudo python3 -m pip install u2fval-client
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 by running the following commands:
sudo mkdir -p /etc/yubico/u2fval
echo "SQLALCHEMY_DATABASE_URI = 'sqlite:////etc/yubico/u2fval/u2fval.db'" | sudo tee /etc/yubico/u2fval/u2fval.conf
Next, we can configure the client. Run the following commands, replacing YOURSERVER with the address of your server:
sudo u2fval db init
sudo 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:
sudo nano /etc/systemd/system/u2fval.service
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:
sudo systemctl enable u2fval.service
sudo systemctl start u2fval.service
Using Non-Yubikey Tokens
u2fval is written by Yubico specifically for Yubikey devices and does some extra validation that others keys may not require. If you are intending on using non-Yubikey devices, you may need an extra step to disable this validation.
Edit the configuration:
sudo nano /etc/yubico/u2fval/u2fval.conf
Then on a new line at the bottom of the file, add the following:
ALLOW_UNTRUSTED = True
Restart the u2fval service with:
sudo service u2fval restart
Setting up OpenVPN
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. Make a copy of the existing server and edit the configuration:
sudo cp /etc/openvpn/server.conf /etc/openvpn/u2f.conf
sudo nano /etc/openvpn/u2f.conf
Scroll to the bottom of the configuration and on a new line add the following:
#U2F and PAM plugin plugin /usr/share/openvpn/pam-u2f/auth-pam-u2f.so login #Auth-gen-token for renegotiation without needing to use token auth-gen-token
Save the configuration and then start up the new server (also ensure the old server is disabled in case it was re-enabled when installing OpenVPN):
sudo systemctl stop openvpn@server
sudo systemctl disable openvpn@server
sudo systemctl enable [email protected]
sudo systemctl start [email protected]
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 Authentication tab and tick 'Use Username/Password authentication'
- Save the connection
If during this guide you registered a dynamic DNS or domain name for your OpenVPN server, also change your servers IP address to the new address.
Using Viscosity
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. If you are on Windows 10 1803 or newer, you will see a Windows Security.
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.