Securing OpenVPN With A One Time Password (OTP) On Ubuntu

Version 1.0
Follow me on Twitter

So, you got yourself a nice OpenVPN box. People need to login with their certificates but... if their laptop is stolen anyone could login. Sure, you could add password login but thats a bit outdated. The solution for this is using a OTP (one time password).

This technique is being used by a lot of large corporations including banks. This tutorial shows you how to configure OpenVPN to add additional security.

This assumes you already have OpenVPN configured and working properly.


Getting the Google Authenticator

First we need to download the Google Authenticator code. This can be done using "hg". You might need to install mercurial, if so its just as easy as doing:

apt-get install mercurial

We also need some compile tools, so let's install a package of compilers (you can remove this when we're done):

apt-get install build-essential

Let's check out the sourcecode for the Google Authenticator system:

cd /tmp && hg clone google-authenticator && cd libpam

Ok, nice, so we now got it checked out. In order to make it work properly with OpenVPN we need to change the Makefile.

vim Makefile

Add the following line after the license part and before the .SUFFIXES:


Save the file and lets proceed, shall we? We need to compile this, so thats easy:


No errors? Good. It might be that you get an error about "displayQRCode". If so, you will need to make some changes to the makefile. If everything went as it should, you can just proceed.

find /usr/lib -name

In the makefile, replace all 3 references to "/usr/lib/" with the path you got (e.g. "/usr/lib/i386-linux-gnu/"). Save it up, and re-run make. You should now be able to proceed just fine.

If it was compiled succesfully, proceed with installing it:
make install

We're done, let's proceed shall we?


Configuring OpenVPN to use PAM

Open up /etc/openvpn/server.conf and add the following line:

plugin /usr/lib/openvpn/ openvpn

This will use PAM to provide additional means of authentication. The last part (openvpn) is the file in /etc/pam.d we'd like to use. Since we do not want it to interfere with other services (e.g. SSH or sudo) we just use a new file.

Restart OpenVPN to have it re-read the config file.


Configure PAM to authenticate using Google Authenticator

Create the file /etc/pam.d/openvpn:

cp /etc/pam.d/common-account /etc/pam.d/openvpn
vim /etc/pam.d/openvpn

Add the following line:

auth    required              

If you are using encrypted homedirectories, you will need to change that to:

auth    required               secret=/var/unencrypted-home/${USER}/.google_authenticator

We're finished with the PAM config. Obviously you can make it a lot more complex, for example by adding IP restrictions (no OTP on trusted IPS) or adding more security.


Configure Google Authenticator

Ok, so we have almost everything in place but the proper config. This should be done per-user. Either login as user (su - username or directly) and issue the command:


This will present you with a few questions:|0&cht=qr&chl=otpauth://totp/me@myserver%3Fsecret%XXXXXXXXXXXXX
Your new secret key is: XXXXXXXXXXXXXXXXX
Your verification code is 1234567
Your emergency scratch codes are:
Do you want me to update your "~/.google_authenticator" file (y/n)

Save the URL & info as we will need that later. Answer "y" and you will get the next question:

Do you want to disallow multiple uses of the same authentication
token? This restricts you to one login about every 30s, but it increases
your chances to notice or even prevent man-in-the-middle attacks (y/n)

You should also answer Y(es) here, as its far more secure to disallow reusable keys. Answer accordingly and the next question pops up:

By default, tokens are good for 30 seconds and in order to compensate for
possible time-skew between the client and the server, we allow an extra
token before and after the current time. If you experience problems with poor
time synchronization, you can increase the window from its default
size of 1:30min to about 4min. Do you want to do so (y/n)

30 seconds might not be too long, so we could increase the time limit. For me, 30 seconds is enough so i just answer N(o) here.

The final question:

If the computer that you are logging into isn't hardened against brute-force
login attempts, you can enable rate-limiting for the authentication module.
By default, this limits attackers to no more than 3 login attempts every 30s.
Do you want to enable rate-limiting (y/n)

For additional security you should answer (Y)es here.

Ok done! In case you do have encrypted homedirs you will need to do one additional step. Until they've implemented support for encrypted homedirs, you will have to put it outside of the encrypted homefolders.


mkdir -p /var/unencrypted-home/${USER}/
cp .google_authenticator /var/unencrypted-home/${USER}/
chmod og-rwx /var/unencrypted-home/${USER}/ -R


Configuring the client

The client should have password logins as additional means of security. If you are using the NetworkManager addin for OpenVPN you can just switch it to certificate + password, else you will have to enable "auth-user-pass" in your VPN client config.


Wrapping up

Ok, so now we have:

  1. Installed Google Authenticator PAM module
  2. Enabled PAM support for OpenVPN

Install the Google Authenticator app, instructions for each mobile platform (Android, iOS, BlackBerry) can be found on the Google Knowledgebase.

Once you have installed the app, have it scan the barcode. The URL we received earlier (the one) provides a QR code we can scan. Once we scan it, it will automatically configure the client.

So, the next time you login to your OpenVPN server you will be promped for an additional password. Provide the 6 digit passcode and you will gain access.

Share this page:

11 Comment(s)