Duo Security 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 Duo Security. This guide will expand on setting up an OpenVPN server on Ubuntu by adding Duo Security support to that server using Viscosity's built in Challenge/Request support.
Preparation
For this guide, we assume:
- You have already installed the latest LTS version of Ubuntu (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
- A Duo Security account
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 Duo Security.
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. Please note, your PAM username will need to match your username in Duo Security.
If you wish to use Duo Security as your primary authentication method, i.e. without a local password, please refer to Duo Security's own OpenVPN plugin and guide - https://duo.com/docs/openvpn
Of course, you can modify the script linked below and replace PAM with an authentication method of your choice, like LDAP for example.
This guide should only be used as an example for setting up Duo on your server. The script used below is designed as an example only.
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.
Duo Security Setup
To get started, we need to do some quick setup in Duo Security's Dashboard. We'll assume you already have Duo security setup for 2FA via Duo Mobile or you're setup to use SMS for example.
First, login to the Dashboard, click Applications in the menu on the left, then click the Protect an Application button on the right. On the next page, click Protect in the Auth API row.
On the next page, take a copy of the Integration key, Secret key and API hostname, we'll need these later. Change the Name to something you'll recognise, then click Save down the bottom.
Modifying the Server
Once we have the keys and hostname from Duo we can setup our server to support it.
First, we need to update/upgrade our Ubuntu installation to prevent any conflicts.
sudo apt update
sudo apt upgrade
Next install Python3 and PIP3, this will allow us to install extra packages, install it by running the following from your Ubuntu server's command line:
sudo apt install python3 python3-pip
Next, install PAM and duo_client using PIP:
sudo python3 -m pip install python-pam duo_client
Next you will need to download our script for OpenVPN to use. Do this with:
cd /etc/openvpn
sudo wget https://raw.githubusercontent.com/thesparklabs/openvpn-two-factor-extensions/master/Duo-Security/openvpn_pam_duo.py
After the file is in place, we need to make it executable by running:
sudo chmod +x /etc/openvpn/openvpn_pam_duo.py
Next, we need to edit the script and enter our keys and hostname we copied earlier from the Duo Dashboard. Edit the script:
sudo nano /etc/openvpn/openvpn_pam_duo.py
Scroll down to the following section and replace each one with the appropriate value:
#------------------------------------------------------------------------------ # VARIABLES #------------------------------------------------------------------------------ duo_ikey = 'YOUR_INTEGRATION_KEY' duo_skey = 'YOUR_SECRET_KEY' duo_host = 'api-XXXXXXXX.duosecurity.com' #------------------------------------------------------------------------------
And then save the script.
Finally, we need to modify the OpenVPN server configuration. First, stop the server using:
sudo systemctl stop openvpn@server
Then edit the server configuration using:
sudo nano /etc/openvpn/server.conf
Scroll all the way to bottom then on a new line add the following:
#Use a script to authenticate username/password and Duo Security auth-user-pass-verify openvpn_pam_duo.py via-env script-security 3 #Auth-gen-token for renegotiation without needing to use token auth-gen-token
Now find the following two lines:
user nobody group nobody
And comment them out, changing them to:
#user nobody #group nobody
Save the configuration then restart the server:
sudo systemctl start openvpn@server
Setting up Viscosity
Now the server is setup, we need to make two small changes to our configuration in Viscosity.
- Open Viscosity's Preferences and edit your connection.
- Go to the Authentication tab and tick 'Use Username/Password authentication'
- Go to the Advanced tab, then on a new line add:
static-challenge "Enter Duo Security Response" 0
- Save the connection
The comment in quotes for the static-challenge command you added, i.e. "Enter Duo Security Response" is what is displayed to the user when the Duo Response needs to be entered. You can change this message to whatever you like.
Now that changes to your configuration in Viscosity have been made, connect to the server to test the changes! You will see an extra Password window appear during the connection process, here you can enter your OTP from the Duo Mobile app, or type in push to get a push notification. Alternatively, you can type in sms or phone to get an sms with a code or callback. If you choose sms or phone, you will get an auth failure and need to connect, simply enter the code you get from the sms or phone call next time you see the password window appear.