OpenVPN Advanced Security
Features
- Every client must use a unique certificates
- Clients must use username/password authentication
- Clients must use Google 2FA tokens
- Client certificate and username must match - certificate sharing is not permitted
- OpenVPN server sends email notification during client connect/disconnect
- To authenticate successfully, in the password field the user has to enter password + 2FA token (no spaces)
Systemd Setup
Ubuntu systemd runs openvpn with restricted capabilities and openvpn cannot run client Google 2FA, connect/disconnect scripts to send email notifications. User authentication will randomly fail and users will be unable to login.
To fix this in /lib/systemd/system/openvpn@.service ensure LimitNPROC is set to 100. After editing, run systemctl daemon-reload; systemctl restart openvpn.service.
1. Pinning Users to Certificates
OpenVPN can pin user names to the client certificate CN.
Eg. Create certificates with CN format $user-$device, eg. rsubr-laptop and assign it to the user rsubr. Below script will ensure that OpenVPN auth succeeds only if the CN user matches the authenticated user.
#!/bin/bash
# Filename: /etc/openvpn/auth-cn-user.sh (chmod 755)
# OpenVPN script to ensure certificate common_name and client username
# match. This is to ensure certificates are not shared by users.
if [ -z "$common_name" ]; then
echo "common_name environment variable absent"
echo "This script must be invoked only by OpenVPN and not directly"
exit 1
fi
# Extract the user from cert CN (eg. rsubr-laptop, extract only rsubr)
user=$(echo "$common_name" | cut -d'-' -f1)
# Ensure CN user and authenticated username are the same
if [ "$user" == "$username" ]; then
echo "Permitting $common_name / $username"
exit 0
fi
echo "ERROR: Denying $common_name / $username"
exit 1Add the below to openvpn server.conf:
# Ensure username and certificate name are same, users cannot share certs
auth-user-pass-verify /etc/openvpn/auth-cn-user.sh via-env2. FA Using Google Authenticator
Install Required Packages
# Optional for Google Authenticator 2FA
apt install libpam-google-authenticatorSetup PAM to include Google Authenticator 2FA tokens.
OpenVPN PAM Config
# OpenVPN PAM config
# Filename: /etc/pam.d/openvpn (chmod 644)
# PAM auth for openvpn using google authentictor 2FA
# User enters password + 2FA token in a single prompt
# User must have a valid account and password:
# adduser user1 --shell=/usr/sbin/nologin
@include common-account
auth requisite pam_google_authenticator.so secret=/etc/openvpn/google-authenticator/${USER} user=root forward_pass
auth required pam_unix.so use_first_passGenerate Google Auth 2FA tokens for every OpenVPN user using the below script. The 2FA QR code will be displayed on the SSH console and the OpenVPN user needs to add this to their Goole Authenticator app by be scanning the QR code.
#!/bin/bash
# Filename: /usr/local/sbin/openvpn-gauth-2fa.sh (chmod 755)
#
# Script to create Google Authenticator tokens for OpenVPN
# Ensure these 2 packages are installed
# apt install libqrencode3 libpam-google-authenticator
# Run "openvpn-gauth-2fa.sh user1" to create 2FA QR code for importing into Google Authenticator
MFA_LABEL="OpenVPN"
MFA_DIR="/etc/openvpn/google-authenticator"
user_id="$1"
if [ "Z$user_id" == "Z" ]; then
echo "ERROR: No user id provided"
exit 1
fi
# Create MFA_DIR if it does not exist
if [ ! -d "$MFA_DIR" ]; then
mkdir -p "$MFA_DIR"
chown -Rh root. "$MFA_DIR"
chmod 700 "$MFA_DIR"
fi
google-authenticator -t -l "${MFA_LABEL}" -f -d -w 3 -r 3 -R 30 -s "${MFA_DIR}/${user_id}"Add the below to OpenVPN server.conf:
# Authentiate users with both password and google-authenticator 2FA
# Clients have to enter password and 2fa token in the password prompt
plugin /usr/lib/x86_64-linux-gnu/openvpn/plugins/openvpn-plugin-auth-pam.so openvpnWhen users login using Windows/MacOS/other client, in the login prompt in addition to their password they have to enter the 6 digit 2FA code. Eg. if the password is secret and the 2FA token is 123456 the user has to secret123456 in the OpenVPN client password prompt. OpenVPN PAM will strip the last 6 digits off the submitted password and use it as the 2FA token.
Use pamtester for troubleshooting PAM settings.
3. Email Alerts on User Login/Logout
client-connect.sh
#!/bin/bash
# Filename: /etc/openvpn/client-connect.sh
# Script must be called by OpenVPN server, do not run directly
# OpenVPN config
# script-security 2
# client-connect /etc/openvpn/client-connect.sh
# client-disconnect /etc/openvpn/client-disconnect.sh
MAILTO="root"
mail -s "OpenVPN Client connect" $MAILTO <<EOM
OpenVPN Client $common_name connected
User: $common_name
Remote IP: $trusted_ip
Local IP: $ifconfig_pool_remote_ip
Time: `date +"%H:%M:%S - %Y-%m-%d"`
EOMclient-disconnect.sh
#!/bin/bash
# Filename: /etc/openvpn/client-disconnect.sh
# Script must be called by OpenVPN server, do not run directly
# OpenVPN config
# script-security 2
# client-connect /etc/openvpn/client-connect.sh
# client-disconnect /etc/openvpn/client-disconnect.sh
MAILTO="root"
mail -s "OpenVPN Client disconnect" $MAILTO <<EOM
OpenVPN Client $common_name disconnected
User: $common_name
Remote IP: $trusted_ip
Local IP: $ifconfig_pool_remote_ip
Bytes Received: $bytes_received
Bytes Sent: $bytes_sent
Connection Duration: $time_duration (seconds)
Time: `date +"%H:%M:%S - %Y-%m-%d"`
EOMCreating Users
#TODO fix this, incomplete
- Create EASYRSA certificate for user
pki-tool client - Embed certificate components in client.conf
- Create unix user account for user
adduser user1 --shell=/usr/sbin/nologin - Create Google 2FA token for user
openvpn-gauth-2fa.sh user1- scan the QR code using Authenticator app - To connect to VPN, user has to enter password + 2FA code in the password prompt