Using Linux and OpenVPN to create a virtual private network (VPN) server with two-factor authentication (2FA) enabled using Google Authenticator

In this procedure we install the open source program OpenVPN on a server running on Linux to create a virtual private network (VPN) authenticated against Active Directory with two-factor authentication (2FA) enabled Google Authenticator.

Business case

A Linux server running OpenVPN server software can replace a Windows server or other commercial solution for the VPN server role in the enterprise, reducing software licensing costs and improving security and stability.

Authenticating connections to the VPN server using client certificates and Google Authenticator one-time passwords (OTPs)

Verifying client-side VPN certificates to authenticate a VPN connection

The VPN server will verify client digital certificates as one of the authentication methods.

Using Google Authenticator to obtain a one-time password (OTP) to authenticate a VPN connection

The VPN server will verify the one-time password (OTP) generated by Google Authenticator as one of the authentication methods.

Entering the OTP from Google Authenticator as the password for the VPN connection

To access the network, help desk clients will:

  • Enter their local network file share or Active Directory username as the username for the VPN connection.
  • Enter the OTP from Google Authenticator as the password for the VPN connection.

Not verifying a local password authentication module (PAM) or Active Directory password to authenticate a VPN connection

This procedure does not verify a PAM or Active Directory password to authenticate the VPN connection.

There are ways of prompting for a username, and a password, and an OTP from Google Authenticator. However, some of these are difficult to integrate with with client VPN connector software, which do not support a second password field. Some approaches ask the help desk client to enter a system password and the OTP as a combined password, but this can be confusing for help desk clients.

This procedure was tested on Ubuntu Linux 22.04 LTS

This procedure was tested on Ubuntu Linux 22.04 LTS.

Deploying the VPN server as a physical or virtual machine

Deploy OpenVPN on a physical Linux server or on a virtual Linux server hosted as a virtual machine (VM), using KVM on Linux, Hyper-V, VMware, or VirtualBox on Windows, or Parallels using MacOS.

Adding a macvtap or bridge mode network adapter to a virtual machine

For KVM, add a macvtap network adapter to the automation server. For Hyper-V, VMware, VirtualBox or Parallels, add a bridge mode network adapter. This will allow the VPN server to access the same network as the server’s hypervisor host.

Assigning a static IP address to the server that will host the VPN

Assign a static IP to the VPN server.

Assigning a permanent host name to a dynamic host configuration protocol (DHCP) public-facing IP address

Most residential Internet connections have a dynamic host configuration protocol (DHCP) public-facing IP address, which can change over time. You can use a service like no-ip.com to associate a permanent host name such as permhostname.ddns.net to a host with a dynamic IP address:

https://no-ip.com

Forwarding ports from the public-facing IP address to the internal IP address of the VPN host

Use the control panel of your router to forward a port from the public-facing IP address to the internal IP address of the VPN host.

As an example, for the server described in this procedure, we are using the TCP port 443 to host the connection:

Entering commands as root

This procedure assumes that you are logged in as the root user of the Linux server.

Escalate to the root user by entering the following commands:

sudo su

Installing tools on the server

apt install libpam-google-authenticator curl oath libqrencode4

Modifying the /etc/sysctl.conf file to enable network forwarding

From a root shell, enter the following commands:

cd /etc
nano sysctl.conf

Add the following text to the bottom of the file:

net.ipv4.ip_forward=1

Press Ctrl-X to save and exit the file.

Enter the following command to reload the sysctl settings:

sysctl -a

Creating the /etc/rc.local file

Enter the following commands:

cd /etc
nano rc.local

Add the following text:

!/usr/bin/bash
iptables -t nat -A POSTROUTING -s 10.8.0.0/24 -o enp3s0 -j MASQUERADE

If you are using the no-ip.com dynamic update client (DUC), add the following text:

/usr/local/bin/noip2

Add the following text:

exit 0

Press Ctrl-X to save and exit the file.

Enter the following command

chmod 755 rc.local

Starting the rc-local service

Enter the following command:

systemctl restart rc-local

Using a script to automate the installation of OpenVPN

The openvpn-install.sh from Angristan automates the installation of the OpenVPN server application:

https://github.com/Angristan/OpenVPN-install

Downloading the OpenVPN installation script

To download the openvpn-install.sh script, enter the following commands:

cd /root
curl -O https://raw.githubusercontent.com/angristan/openvpn-install/master/openvpn-install.sh
chmod +x openvpn-install.sh

Running the OpenVPN installation script

./openvpn-install.sh

Modifying the OpenVPN server configuration file

From a root shell, enter the following commands:

cd /etc/openvpn/server
nano server.conf

Locate the following line:

push "redirect-gateway def1 bypass-dhcp"

Change the line to:

push "redirect-gateway def bypass-dhcp"

Add the following text to the end of the file:

auth-user-pass-verify "/etc/openvpn/server/google-authenticator.sh" via-env
script-security 3
username-as-common-name

Press Ctrl-X to save and exit the file.

Creating the google-authenticator.sh script

Enter the following commands:

cd /etc/openvpn/server
nano google-authenticator.sh
#!/usr/bin/bash
# this script written by OpenAI ChatGPT
# see References section for prompt
# check if the user has provided a username and password
if [ -z "$username" -o -z "$password" ]; then
  exit 1
fi

# get the user's secret key from the Google Authenticator app
secret_key=$(grep "^$username:" /etc/openvpn/server/google-authenticator.keys | cut -d: -f2)

# check if the user has a secret key
if [ -z "$secret_key" ]; then
  exit 1
fi

# generate a six-digit code using the secret key and the current time
code=$(oathtool --totp -b "$secret_key")

# compare the generated code with the password provided by the user
if [ "$code" = "$password" ]; then
  exit 0
else
  exit 1
fi

Press Ctrl-X to save and exit the file.

Enter the following command:

chmod 755 google-authenticator.sh

Restarting the OpenVPN server

From a root shell, enter the following command:

systemctl restart openvpn-server@server

Downloading the OpenVPN client profile

Use the FileZilla file transfer client to download the OpenVPN client profile:

https://blog.gordonbuchan.com/blog/index.php/2021/03/07/web-presence-step-by-step-chapter-7-configuring-the-ssh-server-on-an-ubuntu-linux-cloud-server-to-limit-sftp-directory-visibility-within-chroot-jail-directories/#:~:text=Obtaining%20the%20FileZilla%20file%20transfer%20program

Modifying the OpenVPN client profile

Use a text editor to load the OpenVPN client profile. Add the following text to the bottom of the file:

auth-user-pass

Save and exit the file.

Downloading and Installing the Google Authenticator app on a help desk client’s smartphone

Visit the Apple App Store or the Google Play Store. Search for “google authenticator” and download the app:

Click on “Get started”:

Running the google-authenticator command on the server to enrol the help desk client’s Google Authenticator app

Open a terminal window as root, and make the terminal window full-screen. Enter the following command:

google-authenticator

Scanning the QR code into the Google Authenticator smartphone app

Click on “Scan a QR code” then click on “OK” to allow the app to access the camera:

Look at the one-time code shown on the Google Authenticator app:

Enter the code in the Terminal window in the field: “Enter code from the app (-1 to skip):”

Enter “n” to the question: “Do you want me to update your “/root/.google_authenticator file? (y/n):”

Creating the /etc/openvpn/server/google-authenticator.keys file and entering the secret key created during enrolment of the help desk client’s Google Authenticator app.

Enter the following commands:

cd /etc/openvpn/server
nano google-authenticator.keys

Add an entry to the file in with the format “username: yournewsecretkey”:

client06a:NRX7VMDMIC6XSDFJNU3WVB3K2I

Press Ctrl-X to save and exit the file.

A note re automation

Should this process be automated further? Yes. The google-authenticator program on the server could be scripted so that the client’s username and secret code could be added to the /etc/openvpn/server/google-authenticator.keys file.

Downloading the OpenVPN client application

https://openvpn.net/community-downloads/

Importing the OpenVPN client profile

Import the OpenVPN client profile into the OpenVPN client application.

Connecting to the OpenVPN server

An example of a Windows client connecting to the OpenVPN server:

For “Username” enter the username of the VPN connection. For “Password” enter the one-time password (OTP) displayed by the Google Authenticator app:

A successful connection:

References

https://egonbraun.medium.com/using-google-authenticator-mfa-with-openvpn-on-ubuntu-16-04-774e4acc2852
https://amilstead.com/blog/openvpn-with-google-authenticator-totp/
https://github.com/evgeny-gridasov/openvpn-otp
https://www.softether.org/
https://charlesreid1.com/wiki/Ubuntu/OpenVPN_Server#Adding_MFA_to_VPN_Access
https://www.howtoforge.com/how-to-set-up-openvpn-to-authenticate-with-linotp
https://www.howtoforge.com/securing-openvpn-with-a-one-time-password-otp-on-ubuntu
https://www.digitalocean.com/community/tutorials/how-to-configure-multi-factor-authentication-on-ubuntu-18-04
https://warlord0blog.wordpress.com/2022/09/01/openvpn-mfa-and-pam/
https://binsec.wiki/en/security/howto/protect-hardening/authorization-and-authentication/openvpn-configure-2fa-google-authenticator/
https://forums.openvpn.net/viewtopic.php?t=12886
https://www.freeipa.org/page/Windows_authentication_against_FreeIPA
http://pgina.org/
https://www.ezeelogin.com/kb/article/how-to-install-google-authenticator-on-centos-ubuntu-323.html
https://askubuntu.com/questions/182498/google-authenticator-for-desktop
https://unix.stackexchange.com/questions/341226/samba-not-starting-on-ubuntu-server-16-10
https://www.linuxquestions.org/questions/linux-server-73/samba-4-5-issues-4175597252/
https://serverfault.com/questions/1026344/how-can-i-setup-nat-on-my-openvpn-server-for-the-client
https://arashmilani.com/post?id=53
https://unix.stackexchange.com/questions/283801/iptables-forward-traffic-to-vpn-tunnel-if-open
https://aranel.net/tech/raspberrypi-openvpn
https://forums.openvpn.net/viewtopic.php?t=29880
https://superuser.com/questions/168128/openvpn-can-connect-but-cant-ping-or-access-the-server
https://chat.openai.com AI prompt: “create detailed instructions for the integration of google authenticator with openvpn”