Raja's Exocortex

OpenVPN Advanced Security

Features

  1. Every client must use a unique certificates
  2. Clients must use username/password authentication
  3. Clients must use Google 2FA tokens
  4. Client certificate and username must match - certificate sharing is not permitted
  5. OpenVPN server sends email notification during client connect/disconnect
  6. 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 1

Add 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-env

2. FA Using Google Authenticator

Install Required Packages

# Optional for Google Authenticator 2FA
apt install libpam-google-authenticator

Setup 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_pass

Generate 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 openvpn

When 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"`
EOM

client-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"`
EOM

Creating Users

#TODO fix this, incomplete

  1. Create EASYRSA certificate for user pki-tool client
  2. Embed certificate components in client.conf
  3. Create unix user account for user adduser user1 --shell=/usr/sbin/nologin
  4. Create Google 2FA token for user openvpn-gauth-2fa.sh user1 - scan the QR code using Authenticator app
  5. To connect to VPN, user has to enter password + 2FA code in the password prompt