How to set up an OpenVPN tunnel with Google Authenticator

Dylan Perdigão
3 min readApr 15, 2022

After creating an OpenVPN tunnel, we want to make the connection more secure using a One-Time-Password (OTP). To do this, we use, for instance, Google Authenticator.

Setup the OpenVPN tunnel

You can follow this tutorial to set up the OpenVPN tunnel between the client and the server.

Download the Google Authenticator App

You can download Google Authenticator on Play Store or App Store.

Install the libraries

On the server, you need to install the following libraries.

sudo apt-get install -y libqrencode4 libpam-google-authenticator

Configure the server

You need to create a new user we called gauth.

cd /etc/openvpn/
addgroup
gauth
useradd -g gauth gauth
sudo google-authenticator
mkdir google-authenticator
chown gauth:gauth google-authenticator
chmod 0700 google-authenticator

Then you need to edit the server.conf.

nano server.conf

Adding the following line

plugin /usr/lib/openvpn/openvpn-plugin-auth-pam.so \“login login USERNAME password PASSWORD pin OTP\”

Your server.conf file should look like this.

plugin      /usr/lib/openvpn/openvpn-plugin-auth-pam.so \"login login USERNAME password PASSWORD pin OTP\"
local 192.168.172.70
port 1195 # DIFFERENT FROM TUN1
proto udp
dev tun
ca /etc/pki/CA/certs/ca.crt
cert /etc/pki/CA/certs/tun0-server.crt
key /etc/pki/CA/private/tun0-server.key
dh /etc/pki/CA/openvpn/dh2048.pem
server 10.7.0.0 255.255.255.0
ifconfig-pool-persist /var/log/openvpn/ipp.txt
push \"route 10.8.0.0 255.255.255.0\"
keepalive 10 120
tls-auth /etc/pki/CA/private/ta.key 0
cipher AES-256-CBC
persist-key
persist-tun
status /var/log/openvpn/openvpn-status.log
script-security 2
tls-verify /etc/pki/OCSP_check.sh
verb 3
explicit-exit-notify 1

Now edit the nano login file.

nano /etc/pam.d/login

Add the following line at the beginning (replacing {USER} with the username of the session account).

auth required pam_google_authenticator.so secret=/etc/openvpn/google-authenticator/<USER> forward_pass

Your login file should look like this.

auth required pam_google_authenticator.so secret=/etc/openvpn/google-authenticator/<USER> forward_pass
...

Then for generating the QRCode, you need to run the following command (replacing {USER} with the username of the session account).

su -c "google-authenticator -t -d -r3 -R30 -f -l 'OpenVPN Server' -s /etc/openvpn/google-authenticator/{USER}" - gauth

Now the console should output a QRCode with the following message.

Your new secret key is: 6DGZQVG5E6SSWCLXKYCKXHJHPA
Enter code from app (-1 to skip): 962663
Code confirmed
Your emergency scratch codes are:
38250790
17829309
86725593
79778279
47995335

By default, a new token is generated every 30 seconds by the mobile app.
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. This allows for a
time skew of up to 30 seconds between authentication server and client. If you
experience problems with poor time synchronization, you can increase the window
from its default size of 3 permitted codes (one previous code, the current
code, the next code) to 17 permitted codes (the 8 previous codes, the current
code, and the 8 next codes). This will permit for a time skew of up to 4 minutes
between client and server.
Do you want to do so? (y/n) y

Scan the QRCode or insert the code manually with the Google Authenticator App.

Configure the client

Edit the client.conf.

cd /etc/openvpn/
nano
client.conf

Adding the following line

auth-user-pass

Your client.conf file should look like this.

auth-user-pass
client
dev tun
proto udp
remote 192.168.172.70 1195
resolv-retry infinite
nobind
persist-key
persist-tun
ca /etc/pki/CA/certs/ca.crt
cert /etc/pki/CA/certs/tun0-client.crt
key /etc/pki/CA/private/tun0-client.key
tls-auth /etc/pki/CA/private/ta.key 1
cipher AES-256-CBC
verb 3

Restart all the services on each side and when the client.

Then the client will prompt a message asking for a username, a password, and the private key password.

When the client asks for the password, you need to concatenate the user password with the OTP.

If the password is example-pass and the OTP is the 344938, you should enter:

example-pass344938

OTP code from Google Authenticator
Client Asking for user password

You can now ping your server!

--

--