It took me a while but I finally found someone that had solved this. I am linking the solution. However, typing in a password and following it up with the one-time-password (OTP) is *extremely* user unfriendly. Anything that is hard to do to make better security actually makes worse security. Instead my approach protects the private keys with a password, and you then only use the OTP as the user’s password each login.
So, here is the process. Assuming you have pivpn already installed and working with an OpenVPN configuration.
- Install google authenticator on the pi:
sudo apt-get install libpam-google-authenticator
- Edit your openvpn server configuration:
sudo nano /etc/openvpn/server.confand add
plugin /usr/lib/openvpn/openvpn-plugin-auth-pam.so openvpn(to use google authenticator) and
reneg-sec 0(to not reconnect every x minutes as the password changes every few seconds).
- NOTE: This will make this server configuration only work with OTP. If you have accounts that will just be using passwords then you will need to have a separate server configuration and separate port for that. Info on how to do that is here.
- Create a pam.d openvpn profile:
sudo cp /etc/pam.d/common-account /etc/pam.d/openvpn
- Edit it
sudo nano /etc/pam.d/openvpnto add this line at the end:
auth required pam_google_authenticator.so
- Now run
sudo service openvpnrestart to reload the configuration change.
Now, create your user. For this to work you will use system accounts (accounts you use to log to your raspberry like ‘pi’). You can create as many account as you with the
sudo adduser username command. The user’s password really doesn’t matter. Once you’ve created the user:
- login as the user on the raspberry pi:
sudo su - username(replace username with the actual username)
- run the
google-authenticatorcommand and follow the instructions (save the barcode url for next step, or import it directly on the user’s device at that time)
exitto get out of that user’s shell and return to your own.
- Executing google-authenticator adds a file
.google_authenticatorin the user’s home directory. This file must have no rights except read for the user, so run
sudo chmod 400 /home/username/.google_authenticator(change to the correct username)
- create a pivpn account with the exact same name as the user :
pivpn -aNote: the username must be the same than the system account. (The original directions suggest doing this with no password; It is safer to use a password to protect the private key. The password used here will need to be communicated safely to the user)
- edit the freshly created username.ovpn file and add the lines
auth-user-pass(to tell the client to request username and password on connection) and
reneg-sec 0(to not reconnect every x minutes as the password changes every few seconds)
Now, just install your .OVPN file on your client. (You can save the private key password if your client supports it, or require prompting for it every time.) Use the barcode URL generated earlier to show the QR Code for import into your authenticator app on your mobile device, and profit!
Login with the same username and the OTP as the password. (The private key password being the one used when you created the account with the
pivpn -a command.) You’re now using multifactor authentication!. Something you know (the private key password) and something you have (your authenticator app which is a one-time-password generator).