How to enable 2-factor auth using Google Authenticator for .ovpn file based openVPN access?

No. Of course you can't do that. This would defeat the very purpose of 2FA. Your server must have a way to verify the user credentials, and this info shouldn't be sent over the network (ie. you can't use solely the client.ovpn file).

While you don't necessarily have to create unix users, but you must let your users install their verification codes to the server. You can use sftp with virtual users using their already issued certificate, https with client side (mutual) authorization, CIFS (samba), or good old ftp with TLS extension or any other way which let the server know the verification codes created by the users. The communication channel should be secure (encrypted || local).

Naturally if your users upload their own files, you cannot use the aggregated file based credentials used by openvpn-otp. Fortunately we have another (and much better) option by using linux excellent security module pam.

First of all, you have to collect the user files created by google-authenticator in a directory by one of the methods mentioned above. In our case it will be /etc/google-auth.

You must enforce single user-id for all files here, because you don't have real users. Let it be openvpn. The permissions must be 0400 (-r--------). Pam don't like world/group readable credentials (certainly). You can easily enforce this with either samba, apache, ftp or at the worst case using a cron tab (not recommended).

For test purpose, just do this:

mkdir /etc/google-auth
apt-get install libpam-google-authenticator
google-authenticator
# set up as you wish, save image and/or codes
mv ~/.google_authenticator /etc/google-auth/some_username
chown -R openvpn /etc/google-auth

After that you ask openvpn to authenticate against libpam, which has its own google auth module. Append this to your openvpn server file:

plugin /usr/lib/openvpn/openvpn-plugin-auth-pam.so openvpn

This says we will use the pam authentication method with the pam auth id openvpn.

Now, create the pam setup for openvpn. Edit /etc/pam.d/openvpn :

auth    requisite       /lib/security/pam_google_authenticator.so secret=/etc/google-auth/${USER}  user=openvpn
account    required     pam_permit.so

Here we say that without successful google authentication we fail immediately (requisite), we are using a special secret file instead of the default $HOME/.google_authenticator (secret=) and we access the files as user openvpn since there is no real userid associated with our users. In the next line we just say we allow everyone to connect after successful authentication. Of course you should implement your own permission policy here. You can control permitted users by file, mysql db or ldap with the respective pam modules.

Append this to your openvpn client file

   auth-user-pass
   auth-nocache
   reneg-sec 0

We use auth-user-pass to let the openvpn client to ask for username and password. We don't like caching ("password" is changing) and periodical re-negotion is bad for us for the same reason.

After that you should be able to connect without openvpn-otp. Please consider this is much more flexible method, since you can implement very complex rules in pam control files if you wish. You can enable/disable users based on your mysql or ldap directory without touching those certificates for example.


Setup: OpenVPN Server with 2FA (Google Authenticator) on Ubuntu Server 18.04.4 LTS for Raspberry Pi Hardware: Raspberry Pi 3 Model B+ Rev 1.3

  • you have to login with a linux user with no active 2FA login setup (my case someuser)
  • enter the following commands
sudo apt install libqrencode3 libpam-google-authenticator
google-authenticator
sudo mv /home/someuser/.google_authenticator /etc/google-auth/someuser
sudo chown -R root /etc/google-auth
  • add the following file the your openvpn config file (in my case /etc/openvpn/server/server.conf)
plugin /usr/lib/aarch64-linux-gnu/openvpn/plugins/openvpn-plugin-auth-pam.so  openvpn
  • create the file /etc/pam.d/openvpn and fill it with the following content
# Google Authenticator
auth    requisite       /lib/aarch64-linux-gnu/security/pam_google_authenticator.so secret=/etc/google-auth/someuser user=root
account    required     pam_permit.so
  • add the following 3 lines to your openvpn client file
auth-user-pass
auth-nocache
reneg-sec 0
  • restart openvpn service and run a test
systemctl restart openvpn@server
  • when connection with the OpenVPN client (in windows 10) you get an additional login ( User: someuser / Password: 'OTP from Google Authenticator')