Standard OpenVPN Google Authenticator implementations typically require:
- Shell access to server
- User home directories
- Direct execution of
google-authenticator
binary
This becomes problematic when using client certificate authentication via .ovpn
files where users don't have shell accounts. Here's how to implement it properly:
First ensure your OpenVPN server has these packages:
sudo apt-get install openvpn libpam-google-authenticator
Edit /etc/pam.d/openvpn
:
# Standard UNIX authentication
auth requisite pam_unix.so
# Google Authenticator
auth required pam_google_authenticator.so nullok
The nullok
parameter allows users without 2FA to still authenticate.
Add these to your OpenVPN server config (server.conf
):
plugin /usr/lib/openvpn/openvpn-plugin-auth-pam.so openvpn
username-as-common-name
client-cert-not-required
Create a helper script (/usr/local/bin/generate_otp.sh
):
#!/bin/bash
USERNAME=$1
SECRET_FILE="/etc/openvpn/otp-secrets/$USERNAME"
google-authenticator -t -d -f -r 3 -R 30 -w 1 -s "$SECRET_FILE"
Then run for each user:
sudo bash /usr/local/bin/generate_otp.sh username
Modify the .ovpn
file to include:
auth-user-pass
script-security 2
auth-retry interact
Test the connection with:
openvpn --config client.ovpn
You should be prompted for both password and OTP code.
For a more advanced approach using TLS crypt, add to server config:
tls-crypt /etc/openvpn/tls-crypt.key
Generate the key with:
openvpn --genkey tls-crypt /etc/openvpn/tls-crypt.key
When working with OpenVPN configurations that rely solely on .ovpn
files without shell access for users, traditional Google Authenticator integration approaches won't work. The standard PAM-based method requires:
- User shell accounts
- Google Authenticator binary execution
- Configuration files in user home directories
We'll implement a solution using OpenVPN's plugin system with the openvpn-otp
project as our base. This approach:
1. Intercepts authentication requests
2. Validates OTP tokens separately
3. Doesn't require shell access
4. Works with existing .ovpn configurations
Server-Side Configuration
First, install required packages on your Debian VM:
sudo apt-get update
sudo apt-get install openvpn libpam-google-authenticator git build-essential
Clone and build the openvpn-otp plugin:
git clone https://github.com/evgeny-gridasov/openvpn-otp.git
cd openvpn-otp
make
sudo cp openvpn-otp.so /etc/openvpn/
Configuring the OpenVPN Server
Add these lines to your server configuration (/etc/openvpn/server.conf
):
plugin /etc/openvpn/openvpn-otp.so /etc/openvpn/otp-secrets
reneg-sec 0
Create the OTP secrets file:
sudo touch /etc/openvpn/otp-secrets
sudo chmod 600 /etc/openvpn/otp-secrets
Generating User Credentials
For each user, generate a Google Authenticator secret:
google-authenticator -t -d -f -r 3 -R 30 -w 3 -q
Add the secret to /etc/openvpn/otp-secrets
in this format:
username BASE32SECRETCODE
Client Configuration Modifications
Modify your .ovpn
files to include these authentication directives:
auth-user-pass
auth-nocache
reneg-sec 0
Create a test user with this script:
#!/bin/bash
USERNAME="testuser"
SECRET=$(head -10 /dev/urandom | sha256sum | head -c 32 | base32)
echo "$USERNAME $SECRET" | sudo tee -a /etc/openvpn/otp-secrets
echo "Add this secret to Google Authenticator: $SECRET"
Authentication failures: Ensure time synchronization between server and client devices
Plugin loading errors: Verify plugin path and permissions in server.conf
OTP validation problems: Check the otp-secrets file format and permissions
- Regularly rotate OTP secrets
- Monitor authentication logs
- Consider rate-limiting authentication attempts
- Keep the otp-secrets file strictly secured
For larger deployments, consider:
- LDAP integration with OTP
- RADIUS authentication with FreeRADIUS
- Commercial solutions like Duo Security