OpenVpn with 2fa Setup
How to setup OpenVPN with two factor authentication, tls-auth for packet filtering, and high grade ciphers to keep your data well encrypted.
This solution is totaly free and open source and as secure as vpn's get.
Install via Ansible Galaxy
If you don't want to setup the vpn yourself, or you want it in a hurry, you can use my ansible code.
- openvpn-2fa-ansible-playbook.tar.gz
- openvpn-2fa-ansible-playbook.tar.gz.sig
- gpg --keyserver pgp.mj2.uk --recv-keys 0x1edeabf83d5702e2
- gpg --verify openvpn-2fa-ansible-playbook.tar.gz.sig openvpn-2fa-ansible-playbook.tar.gz
Software Used
Overview of solution
Once setup, when authenticating to your VPN service the following authentication process will occur;
- A TLS handshake will be established.
- You will be asked for your username and 2fa token (OATH-TOTP)
- Your Certificates / Keys will be used to verify and encrypt your data.
Install and configure OpenVPN
First checkout easyrsa3, it's the easiest way to manage a number of certs for different users.
git clone https://github.com/OpenVPN/easy-rsa
Once checked out you'll first want to edit the default vars this will save you time whilst creating certs as well as strengthen the security by upping the certs from sha1rsa 1024 bit to sha256rsa 4096 bit.
cd easy-rsa/easyrsa3
cp vars.example vars
vi vars
Full example setup:
set_var EASYRSA_REQ_COUNTRY "GB"
set_var EASYRSA_REQ_PROVINCE "London"
set_var EASYRSA_REQ_CITY "London"
set_var EASYRSA_REQ_ORG "Organisation"
set_var EASYRSA_REQ_EMAIL "user@domain.uk"
set_var EASYRSA_REQ_OU "Org Unit"
set_var EASYRSA_KEY_SIZE 4096
set_var EASYRSA_ALGO rsa
set_var EASYRSA_CA_EXPIRE 3650
set_var EASYRSA_CERT_EXPIRE 3650
set_var EASYRSA_CRL_DAYS 180
set_var EASYRSA_DIGEST "sha256"
Then setup your certs:
./easyrsa init-pki
./easyrsa build-ca
nohup ./easyrsa gen-dh &
./easyrsa build-server-full
finally create a new cert for each user using;
./easyrsa build-client-full
Use your package manager to install OpenVPN and generate a tls authenticatio key
yum install openvpn
apt-get install openvpn
openvpn --genkey --secret ta.key
edit the config file; /etc/openvpn/server.conf. A template copy of this config file can be found by using mlocate.
yum/apt-get install mlocate; updatedb; locate openvpn | grep sample-config-files
A complete config file example:
plugin /usr/lib64/openvpn/plugin/lib/openvpn-auth-pam.so openvpn
local [PUBLIC IP]
port 1194
proto udp
dev tun
ca /etc/openvpn/easyrsa3/pki/ca.crt
cert /etc/openvpn/easyrsa3/pki/issued/main.crt
key /etc/openvpn/easyrsa3/pki/private/main.key
dh /etc/openvpn/easyrsa3/pki/dh.pem
server 192.168.0.0 255.255.255.0
ifconfig-pool-persist ipp.txt
client-config-dir ccd
push "redirect-gateway def1 bypass-dhcp"
push "dhcp-option DNS 8.8.8.8"
push "dhcp-option DNS 8.8.4.4"
push "dhcp-option DNS 208.67.222.222"
push "dhcp-option DNS 208.67.220.220"
client-to-client
keepalive 10 900
tls-auth /etc/openvpn/easyrsa3/pki/ta.key 0
tls-cipher TLS-DHE-RSA-WITH-AES-256-CBC-SHA
cipher AES-256-CFB8
auth SHA512
comp-lzo
max-clients 100
user vpndata
group vpndata
persist-key
persist-tun
status openvpn-status.log
log openvpn.log
verb 1
reneg-sec 10800
The key config settings are;
1. plugin /usr/lib64/openvpn/plugin/lib/openvpn-auth-pam.so openvpn
This is the pam plugin that we will be using to setup 2fa.
2. tls-auth /etc/openvpn/easyrsa3/pki/ta.key 0
The tls auth key generated with "openvpn --genkey --secret ta.key", acts as a packet filter and can protect from DoS attacks. This is in addition to the tls-cipher (double TLS).
3. tls-cipher TLS-DHE-RSA-WITH-AES-256-CBC-SHA
The tls cipher list provided by openvpn actually just prints all tls ciphers supported by openssl, as any not supported by openvpn will be supported by openssl. Should you choose to you can specify a list of acceptable tls ciphers.
4. cipher AES-256-CFB8
To get a list of ciphers supported by your version of openvpn you can use "openvpn --show-ciphers", if you are using NetworkManager in linux you can roll back to "AES-256-CBC". This is one of the most important values as this is the cipher used to encrypt your data.
5. auth SHA512
This setting will authenticate packets signed with a HMAC-SHA512, you could leave it at HMAC-SHA1 (the default), yubico have an article on why HMAC-SHA1 is not vulnerable as SHA1 is. However I chose to up this regardless.
6. reneg-sec 10800
The vpn will by default request users to re-authenticate every hour, dependant on your client tool this can cause issues, so consider increasing this value to 3 hours.
Google Authenticator Pam Module
checkout the google authenticator pam module using git, build it and add a line to the pam configuration for openvpn.
git clone https://github.com/google/google-authenticator/
cd google-authenticator/libpam/
autoreconf --install
./configure
make
make install
updatedb
locate pam_google_authenticator.so
vi /etc/pam.d/openvpn
# google auth
auth required /usr/local/lib/security/pam_google_authenticator.so
account required pam_nologin.so
account include system-auth
password include system-auth
session include system-auth
Once the pam module is inplace all you'll need to do is execute google-authenticator as a vpn user, and save the stored OATH-HOTP or OATH-TOTP into either google-authenticator or a 2fa security device like the Yubico Yubikey.
Example output from the google-authentication setup tool:
[bob@test1001 ~]$ /usr/local/bin/google-authenticator
Do you want authentication tokens to be time-based (y/n) y
https://www.google.com/chart?chs=200x200&chld=M|0&cht=qr&chl=otpauth://totp/bob@test1001%3Fsecret%3DVPVDLLGGJHYLWR6A%26issuer%3Dtest1001
Your new secret key is: VPVDLLGGJHYLWR6A
Your verification code is 640702
Your emergency scratch codes are:
39775931
81409345
46487840
82009665
10238364
Do you want me to update your "/home/bob/.google_authenticator" file (y/n) y
Do you want to disallow multiple uses of the same authentication
token? This restricts you to one login about every 30s, but it increases
your chances to notice or even prevent man-in-the-middle attacks (y/n) Do you want to disallow multiple uses of the same authentication
token? This restricts you to one login about every 30s, but it increases
your chances to notice or even prevent man-in-the-middle attacks (y/n) y
By default, tokens are good for 30 seconds and in order to compensate for
possible time-skew between the client and the server, we allow an extra
token before and after the current time. If you experience problems with poor
time synchronization, you can increase the window from its default
size of 1:30min to about 4min. Do you want to do so (y/n) y
If the computer that you are logging into isn't hardened against brute-force
login attempts, you can enable rate-limiting for the authentication module.
By default, this limits attackers to no more than 3 login attempts every 30s.
Do you want to enable rate-limiting (y/n) y
Setting Up The Client to Connect
Download the following files from your vpn server;
- ta.key
- ca.crt
- "client".crt
- "client".key
Then edit a file for the OpenVPN config; vi my-vpn.ovpn
client
dev tun
proto udp
remote [PUBLIC IP]
persist-key
persist-tun
ca ca.crt
cert "client".crt
key "client".key
auth-user-pass
comp-lzo yes
nobind
auth-nocache
script-security 2
reneg-sec 10800
tls-auth ta.key 1
cipher AES-256-CFB8
tls-cipher TLS-DHE-RSA-WITH-AES-256-CBC-SHA
remote-cert-tls server
auth SHA512
and finnaly you can connect with:
openvpn --config my-vpn.ovpn