Reply
Member
Posts: 112
Registered: ‎03-25-2015
Kudos: 57
Solutions: 2

Secure OpenVPN server setup with multi-factor authentication (Google Authenticator): step-by-step

[ Edited ]

This is a guide to setting up a reasonably secure multi-user OpenVPN server on an Edgerouter.  I have spent some time following various guides on this forum and others, together with the guidance on Hardening OpenVPN, into a (hopefully) easy to follow guide.

 

Some features of the setup and why I chose them:

 

  • Multi-factor authentication:
    • Public Key Infrastructure (PKI) - "something unique" - keys and certs for server and each client
    • Usernames and Passwords - "something you know"
    • RFC6238 TOTP (Time-based One-Time Passwords), using Google Authenticator - "something you have" (your smartphone, with an app to generate throwaway passwords every 30 seconds)
  • Sufficiently-strong encryption, especially suited to ARM-based iOS clients such as iPhones:
    • AES-256-CBC main cipher
    • TLS-DHE-RSA-WITH-AES-256-CBC-SHA for the control channel
  • PKCS#12:
    • Enables storage of client certificates/keys in Apple Keychain, for hardware-backed crypto on iOS devices (assuming you have a strong device passcode)
  • tls-auth (a pre-shared key for the TLS channel):
    • Protects from some forms of DoS attack
    • Makes it harder for port-scanners to detect an OpenVPN instance

Right then... let's go! There are several main sections to this guide:

 

  1. Work out what you want/need from your OpenVPN server(s)
  2. Add user account(s)
  3. Setup the Public Key Infrastructure (PKI)
  4. Install and configure Google Authenticator for Time-based One Time Passwords (TOTP)
  5. OpenVPN server(s) configuration
  6. Port forwarding, firewall and other settings
  7. OpenVPN client(s) configuration

1. What you do want from your OpenVPN server(s)?

 

In my case, I needed an OpenVPN server using TCP and accessible via port 443, so that I could still reach it when connected to restrictive public/work networks (i.e. where the default of UDP on port 1194 would not work).

also wanted an OpenVPN server using UDP, because it's more efficent (in most cases). 

I wanted to access my NAS and my Edgerouter UI when away from home, as well as route as much as possible of my client's network traffic via the VPN, when connected - i.e. to provide improved privacy on public hotspots.

Because I'm a home user, I have a small number of clients... I'm happy to spend time configuring them carefully to provide a relative secure overall solution.  Thus, I will setup unique certificates/keys and user/passwords for each client and I will store 'identities' (from PKCS#12 files) in Apple Keychain where available.  Then even if my iPhone is rooted, my keys will remain protected by hardware-backed crypto unless the attacker also has my device passcode; this way, I'm better-protected if one of my devices gets lost or stolen.

 

If your requirements are different to mine, you'll want to skip or amend some of the steps.  I've tried to give a few alternatives where it's sensible. Man Happy

 

I'm using EdgeOS v1.6 for this guide.

 

2. Add a user account for each client device

 

Each client should have its own account.  It's then a trivial matter to disable accounts for any compromised devices. As an example, let's setup accounts called "bob-iphone" and "bob-macbook":

 

  1. Log in to the EdgeOS web UI as an Administrator
  2. Go to the 'Users' tab and click the 'Add User' button
  3. Username = "bob-iphone"
  4. Full name = "Bob iPhone 6 OpenVPN"
  5. Enter a unique, strong, memorable password.
  6. Role = 'Operator'
  7. Repeat steps 1-6 for the "bob-macbook" user, and any other client devices

3. Setup Public Key Infrastructure (CA, DH, certs, keys, etc)

 

Login to your Edgerouter via SSH, using your admin username and password.

 

Change to root shell:

sudo -i

 

Create some folders in /config folder (which is included in every config backup file and survives upgrades):

mkdir /config/openvpn
mkdir /config/auth/openvpn
mkdir /config/auth/openvpn/keys

 

Change to the directory /config/auth/openvpn/keys and create text files index.txt (empty) and serial (contains 00):

cd /config/auth/openvpn/keys
touch index.txt
echo 00 > serial

 

Make a copy of the example easy-rsa vars file, to customise for our needs (note the space between vars and ./):

cd /config/openvpn
cp -p /usr/share/doc/openvpn/examples/easy-rsa/2.0/vars ./

 

Edit our new copy of the vars file:

vi ./vars

 

To edit with vi, move using cursor keys, press ‘i’ to edit, make changes as required, then press ‘esc’ when finished editing and type ‘:wq’ to save and quit. These are the changes to make:

# Modify the following lines of the vars file as needed/desired
# these are listed in the order you will find them in the file
# they are not all next to each other.
export EASY_RSA="/usr/share/doc/openvpn/examples/easy-rsa/2.0"
export KEY_DIR="/config/auth/openvpn/keys"
# comment these two out.
# export PKCS11_MODULE_PATH="dummy" # commented out
# export PKCS11_PIN="dummy" # commented out
# By default the KEY_SIZE is 1024. 
# It’s worth changing it to 2048 for extra security if you want... # BUT the (one-off) step for "./build-dh" takes around an hour if using 2048. # It’s your choice, of course. ;) export KEY_SIZE=2048 # Change the following values to whatever you want export KEY_COUNTRY="MyCountryCode" # e.g. "US" export KEY_PROVINCE="MyProvince" export KEY_CITY="MyCity" export KEY_ORG="MyOrganisationName" export KEY_EMAIL="admin@MyDomain.com" export KEY_EMAIL=admin@MyDomain.com export KEY_CN=server export KEY_NAME=MyOrganisation_Edgerouter # can be some other name export KEY_OU=Operations # comment these two out. # export PKCS11_MODULE_PATH=changeme # commented out # export PKCS11_PIN=1234 # commented out

 

Change to the Easy-RSA folder and use the scripts to create a Certificate Authority (CA) and generate keys and certificates for each client:

cd /usr/share/doc/openvpn/examples/easy-rsa/2.0

# note there needs to be a space after the dot on this next line:
. /config/openvpn/vars

# cleans all in /config/auth/openvpn/keys previously generated keys and certificates
# if you are following this guide, the /keys directory is already empty.
./clean-all

# takes some time, only about 5-10 minutes I think when i made a 1024 key.
# takes about an hour for a 2048 key.
./build-dh

# most steps in the following will use your pre-populated values (from your
# edited 'vars' file). For Common Name, I used 'OpenVPN-CA' ./build-ca # Assuming you edited the information in the vars files simply hit enter all
# the way through this. Otherwise enter your desired values.
# As in the previous step, most parameters can be defaulted by pressing enter. # When the Common Name is queried, enter "server". # Two other queries require positive responses, "Sign the certificate? [y/n]"
# and "1 out of 1 certificate requests certified, commit? [y/n]" - answer
# 'y' for both. ./build-key-server server # Generating client certificates and keys follows a similar process: ./build-key bob-iphone ./build-key bob-macbook # Generate a pre-shared key for TLS authentication: openvpn --genkey --secret /config/auth/openvpn/keys/ta.key # Finally, create a PKCS#12 (.p12) file containing our iPhone cert and key.
# (Note that the CA file is also included, but that will be ignored by the
# iPhone when importing into its keychain, so we'll still need to include the
# CA file separately in our OpenVPN config later on.) # When prompted, specify a strong unique password to protect the file in
# transit (you'll only need to enter this once, when importing the p12 file
# into your iPhone's keychain). openssl pkcs12 -export -in bob-iphone.crt -inkey bob-iphone.key -certfile ca.crt -name OVPNclient -out bob-iphone.p12

 

Creating a .p12 file (last step above) is not strictly required, but it provides extra security because it enables the private key to be stored in the Apple Keychain (which has hardware-backed crypto). To make sure your keychain is safe, need to have a strong device passcode set - not just a simple 4 digit PIN - of course.

 

4. Install and configure Google Authenticator

 

Firstly, if you've never installed any Debian packages on your Edgerouter, you'll need to follow the first couple of steps in the guide on How to add other Debian packages to EdgeOS, to setup an appropriate repository (assuming you're using EdgeOS v1.6, you'll want the 'wheezy' repo).

 

Once that's done, go to root shell, if you're not already:

sudo -i

 

Install the libqrencode3 package (not strictly essential, but it makes things much easier later):

apt-get install libqrencode3

 

Unfortunately, Google Authenticator hasn't been packaged for Debian wheezy, but the jessie package works just fine for our purposes. (Alternatively, you can compile it from source, but I didn't bother as the jessie package just works and doesn't have any non-wheezy dependencies...)
Grab and install the jessie package like this:

cd ~
mkdir ./downloaded-packages
cd downloaded-packages
curl -O http://ftp.us.debian.org/debian/pool/main/g/google-authenticator/libpam-google-authenticator_20130529-2_mips.deb
dpkg -i libpam-google-authenticator_20130529-2_mips.deb

 

Create a new PAM config for our OpenVPN server(s) to use:

cd /etc/pam.d
cp common-account openvpn

 

Now edit the new config using vi (again, use cursors to reach the last line of the file, press 'i' to make changes, and when done, press esc, then type ':wq' to write and quit):

vi openvpn

 

You now need to ask yourself if you want 2-factor or 3-factor authentication... i.e. do you want to have to enter username and a six-digit TOTP code when prompted, or do you want to have to enter username, password AND the six-digit TOTP code?
Personally, I tried both and found that entering username and a strong password as well as the TOTP quickly became very tiresome. Also, for me, the combination of PKI and TOTP is very much "secure enough". But you might feel differently, so I'm giving both options below...

 

(a) To require only username and TOTP to authenticate, add the following to the end of the openvpn file:

auth required pam_google_authenticator.so

 

(b) Alternatively, to require username and password+TOTP (both in the password field, e.g. password123456) to authenticate, add the following to the end of the openvpn file:

auth requisite pam_google_authenticator.so forward_pass
auth required pam_unix.so use_first_pass

 

Now the fun bit... Man Happy

 

Be sure to adjust the command below so that the username (at the end of the line) matches the real user you've set up earlier, and the label text between '\"' and '\"' is whatever you want to appear next to the passcode in your authenticator app (remember you might eventually have lots of other Google Authenticator entries with their own secret codes - there are loads of services offering 2-factor authentication now - so give it a sensible unique name):

sudo su -c "google-authenticator --label=\"OpenVPN bob-iphone\"" bob-iphone

 

Answer 'y' to the first question, and if you installed the libqrencode3 package earlier, you'll be presented with a nice QR code as ASCII art in your terminal window - neat, eh? (I had to resize the terminal window on my Macbook so that the QR code was displayed properly).


If you did not install the extra package, then you can copy'n'paste the URL provided by the google-authenticator executable into any browser and Google's web service will provide an image of the relevant QR code for you.

 

Now's the time to install a suitable TOTP-capable app on your smartphone, if you don't already use one for other sites which offer two factor authentication. The Google Authenticator app is the obvious choice, but there are others to choose from if you like (e.g. Authy).


Now open Google Authenticator app and press the '+' button. Choose the option 'Scan a barcode' and then scan the QR code. The app will then start displaying a unique six digit one-time password every 30 seconds (hence the importance of your server and clients all having accurate time set on them!).

 

Back in our SSH session, answer the rest of the questions as follows (if you don't have faith in your time synchronisation working properly, you might want to answer 'y' to the third question):

Do you want me to update your "/home/bob-iphone/.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) 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) n

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

 

Now change rights on the newly-created Google Authenticator config for your user, so that only the user is allowed only read permissions, like this:

sudo chmod 400 /home/bob-iphone/.google_authenticator

 

Repeat the above steps to run the google-authenticator executable for each user that you created earlier.

 

(Continued below, as my tutorial won't fit in one post... 20k character limit apparently.)

Member
Posts: 112
Registered: ‎03-25-2015
Kudos: 57
Solutions: 2

Re: Secure OpenVPN server setup with multi-factor authentication (Google Authenticator): step-by-ste

[ Edited ]

5. OpenVPN server(s) configuration

 

As I mentioned in section one, I'll be setting up two OpenVPN instances here: one accessible from external port 443 using TCP (to pass through most restrictive firewalls etc) and another one accessible from external port 1194 using UDP. Your requirements might be different to mine, so please adjust the below steps to meet your needs!

 

First, let's set up the 443-TCP instance as interface vtun0...

 

Login to your Edgerouter via SSH and enter configuration mode:

configure

 

Then enter the following commands. I've commented (using #) to explain what's going on:

# The EdgeOS UI listens on port 443 TCP by default, which would clash with our 
# OpenVPN server if it also tried to listen on port 443 using TCP, so we'll
# listen on port 1194 and use port-forwarding later so that we can reach our
# server from the outside set interfaces openvpn vtun0 local-port 1194
# By default, OpenVPN is peer-to-peer, but we want to put our instance in
# 'multi-user server' mode set interfaces openvpn vtun0 mode server
# Enable TLS and assume server role during TLS handshake set interfaces openvpn vtun0 openvpn-option --tls-server
# This line enables adaptive fast LZO compression. You must enable it on both
# server and client(s). set interfaces openvpn vtun0 openvpn-option --comp-lzo
# The following line instructs OpenVPN to drop root privileges following
# initialisation - this is an important option for security set interfaces openvpn vtun0 openvpn-option '--user nobody --group nogroup'
# We need to tell OpenVPN to remember the key after first reading it. Normally
# if you drop root privileges in OpenVPN, the daemon cannot be restarted (e.g.
# on SIGUSR1 signal), since it will now be unable to re-read protected key
# files. # This option solves the problem by persisting keys across SIGUSR1 resets, so
# they don't need to be re-read. set interfaces openvpn vtun0 openvpn-option --persist-key
# Keep the tunnel up across SIGUSR1 restarts. Also keep the same IP addresses. set interfaces openvpn vtun0 openvpn-option --persist-tun set interfaces openvpn vtun0 openvpn-option --persist-local-ip set interfaces openvpn vtun0 openvpn-option --persist-remote-ip
# Check that the client is still reachable, every 8 seconds (unless a packet
# has been received from the client in the meantime). If no pings received from
# the client for 30 seconds, assume that the connection needs restarting. set interfaces openvpn vtun0 openvpn-option '--keepalive 8 30'
# Set the verbosity level for the logs to a medium-low level. If you're having
# trouble getting things working, you will want to set this to a value between
# 6-11, where higher numbers give more debugging information set interfaces openvpn vtun0 openvpn-option '--verb 3'
# We trust all of our clients, so will allow them to communicate with each
# other while connected via the VPN set interfaces openvpn vtun0 openvpn-option --client-to-client
# Write a file with details of clients and the virtual IP address assigned to
# them, so that they hopefully always get the same address (this helps clients
# using persist-tun option) set interfaces openvpn vtun0 openvpn-option '--ifconfig-pool-persist /config/auth/openvpn/vtun0-ipp.txt'
# The following lines instruct clients to direct all of their traffic (as much
# as possible) via the VPN. You should replace 192.168.2.1 with the address of
# your Edgerouter on your LAN (assuming that your Edgerouter is providing DNS
# for your LAN, that is). set interfaces openvpn vtun0 openvpn-option '--push redirect-gateway def1' set interfaces openvpn vtun0 openvpn-option '--push dhcp-option DNS 192.168.2.1'
# If you just want to make your LAN devices accessible from wherever you are
# but don't want to route internet traffic via your VPN tunnel, then leave out
# the following two lines and instead use something like (but replace the
# subnet and mask with your actual subnet and mask): set interfaces openvpn vtun0 openvpn-option "--push route 192.168.2.0 255.255.255.0"
# Enable HMAC authentication of the TLS control channel, using the key we
# generated earlier. The zero at the end is important, because it specifies the
# direction of the negotiation. # With the following option enabled (and the corresponding option enabled on
# the clients), unauthorised clients are dropped before they can even attempt a
# TLS handshake. set interfaces openvpn vtun0 openvpn-option '--tls-auth /config/auth/openvpn/keys/ta.key 0'
# Enable our 'openvpn' PAM config for authentication of users using either TOTP
# or both password+TOTP (according to how you set up the PAM config earlier),
# on top of the standard PKI-based authentication: set interfaces openvpn vtun0 openvpn-option '--plugin /usr/lib/openvpn/openvpn-auth-pam.so openvpn'
# Use 256bit AES-CBC cipher for main encryption. AES ciphers are considered
# strong and they are also well suited to ARM-powered clients such as iPhones.
# You can amend this to AES-128-CBC to trade off some security for slightly
# increased performance set interfaces openvpn vtun0 openvpn-option '--cipher AES-256-CBC'
# All the advice online seems to recommend using the snappily-named cipher
# suite called TLS-DHE-RSA-WITH-AES-256-CBC-SHA for the control channel.
# However, if you use that name in the following line, you'll receive an error.
# That's because our OpenVPN server uses OpenSSL, which uses a different name
# for the same cipher suite: set interfaces openvpn vtun0 openvpn-option '--tls-cipher DHE-RSA-AES256-SHA'
# The float option means that our clients can remain connected even if they
# move IP addresses after they first authenticate (so long as the packets still
# pass verification etc, of course). We want this because our clients might
# switch from wifi to cellular networks and back again, and we want to maximise
# the chances of our tunnel remaining usable during such events. set interfaces openvpn vtun0 openvpn-option --float
# Use TCP protocol for the tunnel (for compatibility with restrictive firewalls
# remember), and passively accept connections from clients set interfaces openvpn vtun0 protocol tcp-passive
# This is a virtual subnet used just for OpenVPN clients. I've chosen a
# relatively obscure subnet here, to minimise the chance of it clashing with
# whatever local subnet the client is connected to at the time. set interfaces openvpn vtun0 server subnet 10.7.91.0/24
# Use the certificates (public keys) and private key that we generated earlier.
# If you chose to use 1024 bit strength when editing the 'vars' file, you'll
# need to specify "dh1024.pem" for the Diffie Hellman parameter file in the
# third line below: set interfaces openvpn vtun0 tls ca-cert-file /config/auth/openvpn/keys/ca.crt set interfaces openvpn vtun0 tls cert-file /config/auth/openvpn/keys/server.crt set interfaces openvpn vtun0 tls dh-file /config/auth/openvpn/keys/dh2048.pem set interfaces openvpn vtun0 tls key-file /config/auth/openvpn/keys/server.key

 

That's all that's needed for our corporate-firewall-friendly TCP OpenVPN server. Man Wink

 

Now we'll set up our alternative server, using UDP protocol for efficiency and also running on port 1194 (it's fine to have a server on 1194-TCP as well as one on 1194-UDP, btw, as the protocols are different).


I won't explain each command in detail - only those which differ from the above steps:

# When using UDP, we need to tell OpenVPN which interface to listen on, as it 
# won't work properly when listening on all interfaces set interfaces openvpn vtun1 local-host 192.168.2.1
set interfaces openvpn vtun1 local-port 1194 set interfaces openvpn vtun1 mode server set interfaces openvpn vtun1 openvpn-option --tls-server set interfaces openvpn vtun1 openvpn-option --comp-lzo set interfaces openvpn vtun1 openvpn-option '--user nobody --group nogroup' set interfaces openvpn vtun1 openvpn-option --persist-key set interfaces openvpn vtun1 openvpn-option --persist-tun set interfaces openvpn vtun1 openvpn-option --persist-local-ip set interfaces openvpn vtun1 openvpn-option --persist-remote-ip set interfaces openvpn vtun1 openvpn-option '--keepalive 8 30' set interfaces openvpn vtun1 openvpn-option '--verb 3' set interfaces openvpn vtun1 openvpn-option --client-to-client set interfaces openvpn vtun1 openvpn-option '--ifconfig-pool-persist /config/auth/openvpn/vtun1_ipp.txt' set interfaces openvpn vtun1 openvpn-option '--push redirect-gateway def1' set interfaces openvpn vtun1 openvpn-option '--push dhcp-option DNS 192.168.2.1' set interfaces openvpn vtun1 openvpn-option '--cipher AES-256-CBC' set interfaces openvpn vtun1 openvpn-option --float set interfaces openvpn vtun1 openvpn-option '--tls-auth /config/auth/openvpn/keys/ta.key 0' set interfaces openvpn vtun1 openvpn-option '--tls-cipher DHE-RSA-AES256-SHA'
# This time, we want to use UDP protocol set interfaces openvpn vtun1 protocol udp
# We need to choose a different subnet to our other OpenVPN instance set interfaces openvpn vtun1 server subnet 10.8.91.0/24
set interfaces openvpn vtun1 tls ca-cert-file /config/auth/openvpn/keys/ca.crt set interfaces openvpn vtun1 tls cert-file /config/auth/openvpn/keys/server.crt set interfaces openvpn vtun1 tls dh-file /config/auth/openvpn/keys/dh2048.pem set interfaces openvpn vtun1 tls key-file /config/auth/openvpn/keys/server.key

 

Note that we use the exact same certificates and keys for both OpenVPN servers.

 

Finally, it's time to commit and save our configuration changes:

commit
save

 

6. Port forwarding, firewall etc

 

There are a few other settings that we need before our OpenVPN servers will be working properly...

 

Port forwarding, so that our clients connected via external networks can access our OpenVPN servers . You should replace the rule numbers below so they don't clash with any of your existing port forwarding rules, and replace 192.168.2.1 with your Edgerouter's LAN IP. You can use the GUI if it's easier for you, of course:

set port-forward rule 6 description 'OpenVPN TCP'
set port-forward rule 6 forward-to address 192.168.2.1
set port-forward rule 6 forward-to port 1194
set port-forward rule 6 original-port 443
set port-forward rule 6 protocol tcp
set port-forward rule 7 description 'OpenVPN UDP'
set port-forward rule 7 forward-to address 192.168.2.1
set port-forward rule 7 forward-to port 1194
set port-forward rule 7 original-port 1194
set port-forward rule 7 protocol udp

 

(Side note: if you already have a web server accessible via public port 443 TCP, you either need to choose a different firewall-friendly public port for your OpenVPN TCP server, or consider installing SSLH to 'multiplex' port 443 between both services.)

 

DNS forwarding (dnsmasq), otherwise VPN-connected clients won't be able to access the internet via your VPN:

set service dns forwarding listen-on vtun0
set service dns forwarding listen-on vtun1

 

Add a firewall rule. Again, change the rule number as appropriate, or use the GUI to make things simple:

set firewall name WAN_LOCAL rule 5 action accept
set firewall name WAN_LOCAL rule 5 description 'Allow OpenVPN'
set firewall name WAN_LOCAL rule 5 destination port 1194
set firewall name WAN_LOCAL rule 5 log disable
set firewall name WAN_LOCAL rule 5 protocol tcp_udp

 

Remember to commit and save your changes, as usual:

commit
save

 

If you don't have a static IP address from your ISP, you should set up a dynamic DNS service so that your Edgerouter can always be reached via a consistent domain name. Otherwise, if your WAN IP changes, you won't be able to reach your home network from outside. (I won't explain how to do that here - I'm sure you can find another post on how to do that.)

 

(Continued below...)

Member
Posts: 112
Registered: ‎03-25-2015
Kudos: 57
Solutions: 2

Re: Secure OpenVPN server setup with multi-factor authentication (Google Authenticator): step-by-ste

[ Edited ]

7. OpenVPN client(s) configuration

 

We need to create OpenVPN config (.ovpn) file(s) for each client, to tell the client how to connect to the server(s).

 

There is a useful-sounding OpenVPN feature for 'server failover', where the client will try alternative servers/ports/protocols, one by one, in order (or a random order, if you want that) until it manages to connect to one, but I've not managed to get it to work on any client (there are plenty of complaints online about it not working, too)... very annoying! Man Sad


If the failover worked properly, we could use a single config file to define connections to both of our servers: defaulting to the 1194-UDP server and using the 443-TCP server if the first wasn't reachable.

However, in the absence of a solution to the broken failover functionality, we need to define two connection profiles and choose on the client which one we want to use for a given session.

 

First, we need to make sure we've got all of the certificates and keys that we need to refer to:

ca.crt
ta.key
bob-iphone.p12
bob-macbook.crt
bob-macbook.key

 

(If you didn't create a PKCS#12 file earlier, you'll need both bob-iphone.crt and bob-iphone.key files instead.)

The key .crt files are certificates (aka public keys), and are not particularly sensitive. The .p12 file is encrypted with a strong password for transit, so that's safe too. But the .key files are your private keys - they are like the keys to your virtual house and must be carefully protected!

So you need to transfer them via a secure channel to your computer (this means NOT email!).

 

One way to do it (if your computer is running Linux or OS X) is via SCP, like this (replace username with a valid user on your computer, replace x.x.x.x with your computer's IP address, and specify a valid path where to place the files):

[log in to your Edgerouter via SSH]
sudo -i
cd /config/auth/openvpn/keys
scp ca.crt ta.key bob-*.p12 bob-*.key bob-*.crt username@x.x.x.x:/path/to/target/folder

 

Alternatively, you can get all of the files by downloading a config backup from your Edgerouter (click System at the bottom of the UI and click the Backup button).
Use 7-zip or similar utility to extract the downloaded config backup to a folder somewhere on your computer, and you'll find all your OpenVPN crypto files in the /config/auth/openvpn/keys folder.

 

Now that we have all of our key and cert files easily available on the computer, copy and paste the following config into a decent text editor on your computer (Textedit in plaintext mode is sufficient for OS X, or grab a copy of Notepad++ if you use Windows).


As per the server configuration, I've tried to add comments to explain what each line does:

# Run in client mode (and pull relevant settings from the server)
client
# Use tunnel mode (rather than bridging) - this is required for iOS
# compatibility, and is fine for most home VPN use-cases dev tun
# Use TCP protocol proto tcp
# Connect to the server at port 443 at yourdomainname.com (replace with your
# actual domain name, if you've setup dynamic (or static) DNS, or put your
# static external IP address if not) remote yourdomainname.com 443
# Keep trying to resolve the domain name for the server (useful when frequently
# switching networks, as is often the case for mobile clients) resolv-retry infinite
# Don't bind to a specific local port when it's not necessary nobind
# Try to persist the key and tunnel parameters across disconnects and restarts
# - this helps to improve the user experience if, for instance, your iPhone
# switches from wifi to cellular connection while connected to the VPN persist-key persist-tun
# This is an essential setting for preventing man-in-the-middle TLS attacks -
# it tells the client to make sure that the (authenticated and signed) remote
# certificate is a server certificate # - i.e. it was created using ./build-key-server and not just ./build-key ns-cert-type server
# We need to pass user credentials to the server (TOTP) before it will allow us
# to connect auth-user-pass
# We want to use strong, industry standard encryption which works well on iOS
# devices as well as other clients. (If you chose to use 128 bit encryption on
# the server earlier (AES-128-CBC), you need to specify the same here too.) cipher AES-256-CBC
# If your client is running a recent version of OpenVPN which supports NIST-
# style names for cipher suites, you might get an error in the log about the
# following name being deprecated. # If that's the case, you can get rid of the error by using the new name for
# the same ciphersuite: TLS-DHE-RSA-WITH-AES-256-CBC-SHA tls-cipher DHE-RSA-AES256-SHA
# Turn on adaptive fast LZO compression for the link. (If you didn't specify
# this option on the server config, then don't include it here either.) comp-lzo
# Use medium level verbosity for the logs. For debug purposes, increase this to
# a value between 6 - 11, where higher numbers give far more detail about what
# is happening verb 4
# Don't renegotiate the connection. If this isn't set, your connection will
# drop after around 10 minutes (unless you re-enter your credentials). reneg-sec 0
# Because iOS doesn't store the CA cert from the PKCS#12 file in its keychain, # we need to include the CA public key here, otherwise the client won't be able
# to verify the signature <ca> -----BEGIN CERTIFICATE----- ... paste the contents of your ca.crt file here ... -----END CERTIFICATE----- </ca>
# the following line defines the direction of TLS authentication, when using # inline format for the key, as we've done below key-direction 1
# The ta.key PSK file isn't included in the PKCS#12 either, so we need to
# include it here, otherwise our server will deny the client before it's even
# had chance to initialise the TLS handshake <tls-auth> -----BEGIN OpenVPN Static key V1----- ... paste the contents of your ta.key file here ... -----END OpenVPN Static key V1----- </tls-auth>

# The following line instructs the OpenVPN iPhone app to disable the option
# to save the user auth password. (We're using one-time passwords anyway, so
# we'll only confuse ourselves if we try to save the password!)
setenv ALLOW_PASSWORD_SAVE 0

 

Save the file above in UTF-8 format, with a filename of "Home TCP 443 bob-iphone.ovpn" or equivalent.

 

Duplicate the file (e.g. using 'save as') as "Home UDP 1194 bob-iphone.ovpn", then make the following changes to the new file:

change 'proto tcp' to 'proto udp' 
change 'remote [yourdomain/IP] 443' to 'remote [yourdomain/IP] 1194'

 

Now we need to create similar files for each of our other, non-iOS, clients (e.g. bob-macbook). I've only commented the new sections below - most of the settings are exactly the same as for our iPhone client:

client
dev tun
proto tcp
remote yourdomainname.com 443
resolv-retry infinite
nobind
persist-key
persist-tun
ns-cert-type server
auth-user-pass
cipher AES-256-CBC
tls-cipher DHE-RSA-AES256-SHA
comp-lzo
verb 4
reneg-sec 0
<ca> -----BEGIN CERTIFICATE----- ... paste the contents of your ca.crt file here ... -----END CERTIFICATE----- </ca>
# If we're not using a PKCS#12 (.p12) file to contain the client cert and key,
# we need to provide them here in in-line form <cert> -----BEGIN CERTIFICATE----- ... paste the contents of your bob-macbook.crt file here ... -----END CERTIFICATE----- </cert> <key> -----BEGIN CERTIFICATE----- ... paste the contents of your bob-macbook.key file here ... -----END CERTIFICATE----- </key> key-direction 1 <tls-auth> -----BEGIN OpenVPN Static key V1----- ... paste the contents of your ta.key file here ... -----END OpenVPN Static key V1----- </tls-auth>

# The line to disable password saving is specific to the iOS app, so I've
# excluded it here.

 

Save the file above in UTF-8 format, with a filename of "Home TCP 443 bob-macbook.ovpn" (or equivalent name for your user/client, of course).

 

Duplicate the file (e.g. using 'save as') as "Home UDP 1194 bob-macbook.ovpn", then change the protocol from 'tcp' to 'udp' and the port number from '443' to '1194', and save.

 

Repeat the above for all of your other clients, pasting in their certificates and keys in the appropriate places.

(The <ca></ca> and <tls-auth></tls-auth> sections should be the same across all of your profiles.)

 

You should now have two .ovpn files for each of your clients, e.g.:

Home TCP 443 bob-iphone.ovpn
Home UDP 1194 bob-iphone.ovpn
Home TCP 443 bob-macbook.ovpn
Home UDP 1194 bob-macbook.ovpn

 

I've used iOS 8.3, iTunes 12.1.2.27 and OpenVPN 1.0.5 build 177 for the below steps.  If you have different versions, the steps should be roughly the same, hopefully...

 

You should now email the bob-iphone.p12 file to your iPhone (I hope you set a strong password on it, when prompted earlier!).  By opening a .p12 file via Mail (or Safari), it gets added to the global keychain on your device, which is more secure than application-level storage.

Open the attachment on your iPhone and follow the prompts to install the 'identity' (i.e. PKCS#12 keys) on your iPhone.

You will be prompted for both your device passcode and the password that you set on the .p12 file. You can safely ignore the warnings about it not being signed; that's just because we created it with our own CA and not a globally-trusted CA.

 

If you haven't already done so, install the free "OpenVPN Connect" app on your iPhone (from the Apple app store).

 

To securely transfer your client profile to your device:

  1. Connect your iPhone to your computer via USB cable and fire up iTunes (if it doesn't start automatically). 
  2. Wait for any automatic syncing to finish, then click on the device icon and click on 'Apps' in the device pane, on the left hand side. 
  3. In the right hand pane, scroll down and you should see a list of apps which support 'File Sharing'. 
  4. Select the OpenVPN app from the File Sharing > Apps list, then click the 'Add...' button (at the bottom-right of the right hand pane).
  5. Select both .ovpn files for your iPhone from the file browse window which opens.
  6. Sync again for good measure, then click the 'eject' symbol at the top of the device section, to safely remove your iPhone.
  7. Unplug your iPhone from your computer.

Go to Settings on your iPhone and select OpenVPN. Enable the following options to help improve performance and reliability of your connection:

  • Seamless tunnel (iOS8+)
  • Force AES-CBC ciphersuites
  • Layer 2 reachability

Finally, fire up the OpenVPN app on your iPhone:

  • You should see a prompt that two new profiles are pending installation.
  • Click the little green + button to confirm installation.
  • You can click the profile name to switch between your 1194-UDP and 443-TCP profiles. (On the profile selection screen, you can also rename the profiles if you want.)
  • When you select a profile to use, under the name of the profile, you will see an option 'None selected' - tap this and select the Identity which you imported earlier via the .p12 file. (If you didn't bother with the .p12 file and included your client cert and key directly in the .ovpn file, you don't need to do this.) This step links the client cert and key (now held securely in your device keychain) with the .ovpn profile that you imported via iTunes.

 

To connect, when in the OpenVPN app with your chosen profile selected:

  1. Press the home button on your iPhone and open the (Google) Authenticator app.
  2. Make a note of the relevant 6-digit TOTP password, then double-click the home button to return to OpenVPN app.
  3. Enter the username (e.g. bob-iphone) and the 6 digit password, then tap the little on/off button underneath the 'Disconnected' row.
  4. After several seconds, if all has gone well, you will see confirmation that you're connected, and a little 'VPN' symbol will appear next to the wifi/cellular indicator at the top of the screen.


If you are not connected after a while, you can click the 'Disconnected' row in the app to see the log details.

 

To help debug if you have problems, adjust the 'verb 4' line in your profile(s) to something higher (e.g. 'verb 7') and then re-import the profile via iTunes as above. Then when you check the log on your device, you'll see more details of where the problem has occurred.

 

To install on non-iOS clients, download a suitable client application and follow their instructions (for OS X, Tunnelblick is apparently quite good, but I use Viscosity (I got a copy from my commericial VPN provider)).

For Viscosity, you just double-click the .ovpn file to automatically add it to your connection profiles.

 

I hope that all of the above is useful to someone, as it took me quite a while to put it all together! Man Happy

New Member
Posts: 37
Registered: ‎01-16-2016
Kudos: 10
Solutions: 1

Re: Secure OpenVPN server setup with multi-factor authentication (Google Authenticator): step-by-ste

Would it be possible to achive this (Google authenticator) with L2TP/IPsec in "local" mode?

Emerging Member
Posts: 50
Registered: ‎09-12-2015
Kudos: 16
Solutions: 1

Re: Secure OpenVPN server setup with multi-factor authentication (Google Authenticator): step-by-ste

Thank you for the excellent guide.

 

Did you - or anyone else... - try this on 1.8.0?

Member
Posts: 112
Registered: ‎03-25-2015
Kudos: 57
Solutions: 2

Re: Secure OpenVPN server setup with multi-factor authentication (Google Authenticator): step-by-ste

Yes, it works in 1.8. I think the only gotcha is that easy-rsa is no longer bundled with openvpn, so you need to install it separately (i.e. 'sudo apt-get install easy-rsa').
If you haven't already set up repositories for installing packages, there's a thread about it somewhere on here. Man Happy
Member
Posts: 112
Registered: ‎03-25-2015
Kudos: 57
Solutions: 2

Re: Secure OpenVPN server setup with multi-factor authentication (Google Authenticator): step-by-ste

And thanks! Man Happy
Emerging Member
Posts: 50
Registered: ‎09-12-2015
Kudos: 16
Solutions: 1

Re: Secure OpenVPN server setup with multi-factor authentication (Google Authenticator): step-by-ste

Icon Smile

Cool! I'll give it a try.

Emerging Member
Posts: 50
Registered: ‎09-12-2015
Kudos: 16
Solutions: 1

Re: Secure OpenVPN server setup with multi-factor authentication (Google Authenticator): step-by-ste

Just for information - today I tried the installation on ER-X SFP with 1.8.0.

It's working without problem!

 

Here are some points that changed since the guide was written:

- easy-rsa is no longer available in 1.8.0; you can install it manually  by downloading the package or add the following repo:

set system package repository wheezy-backports components 'main contrib non-free'
set system package repository wheezy-backports distribution wheezy-backports
set system package repository wheezy-backports password ''
set system package repository wheezy-backports url 'http://ftp.ch.debian.org/debian'
set system package repository wheezy-backports username ''

after adding the repo above, a

apt-get update
apt-get install easy-rsa

is working.

 

- keep in mind that for easy-rsa the path has changed. You need to run the various build-commands from within the following directory:

root@erx01:/usr/share/easy-rsa# ls -al
total 112
drwxr-xr-x    2 root     root          1624 Apr  3 10:00 .
drwxr-xr-x   68 root     root          1016 Apr  3 22:29 ..
-rwxr-xr-x    1 root     root           119 Nov  9  2013 build-ca
-rwxr-xr-x    1 root     root           352 Nov  9  2013 build-dh
-rwxr-xr-x    1 root     root           188 Nov  9  2013 build-inter
-rwxr-xr-x    1 root     root           163 Nov  9  2013 build-key
-rwxr-xr-x    1 root     root           157 Nov  9  2013 build-key-pass
-rwxr-xr-x    1 root     root           249 Nov  9  2013 build-key-pkcs12
-rwxr-xr-x    1 root     root           268 Nov  9  2013 build-key-server
-rwxr-xr-x    1 root     root           213 Nov  9  2013 build-req
-rwxr-xr-x    1 root     root           158 Nov  9  2013 build-req-pass
-rwxr-xr-x    1 root     root           449 Nov  9  2013 clean-all
-rwxr-xr-x    1 root     root          1471 Nov  9  2013 inherit-inter
-rwxr-xr-x    1 root     root           302 Nov  9  2013 list-crl
-rw-r--r--    1 root     root          7859 Dec 22  2014 openssl-0.9.6.cnf
-rw-r--r--    1 root     root          8416 Dec 22  2014 openssl-0.9.8.cnf
-rw-r--r--    1 root     root          8313 Dec 22  2014 openssl-1.0.0.cnf
-rwxr-xr-x    1 root     root         13246 Dec 22  2014 pkitool
-rwxr-xr-x    1 root     root          1035 Dec 22  2014 revoke-full
-rwxr-xr-x    1 root     root           178 Nov  9  2013 sign-req
-rw-r--r--    1 root     root          2077 Nov  9  2013 vars
-rwxr-xr-x    1 root     root           740 Nov  9  2013 whichopensslcnf

a sidenote: it would anyway be better not to use your router as a CA for the keys used on that router.

I used my Macbook on which Tunnelblick is running. With Tunnelblick installed you also have an easy-rsa installation. You can use this to generate the keys an scp them to the router.

 

I first installed the openvpn server in standard server mode (UDP port 1194) and had troubles with TLS.

--> TLS is to be used with TCP, not UDP. After I changed that in my config everything was working.

I didn't try DTLS. Maybe that would be working because it's designed for UDP.

 

This is a good setup so far. But... the PKI management is not really straight forward. And I would like to have my users authenticated on a backend like LDAP or ActiveDirectory. I'm gong to dig further... maybe I'll find a solution. 

 

Once again - thank you GainfulShrimp for the guide.

Member
Posts: 112
Registered: ‎03-25-2015
Kudos: 57
Solutions: 2

Re: Secure OpenVPN server setup with multi-factor authentication (Google Authenticator): step-by-ste

I'm really glad it worked for you startoff! Man Happy

 

The TLS stuff for authentication and key exchange should work even if the transport is UDP though.  Here's some info on how it works:

 

https://openvpn.net/index.php/open-source/documentation/security-overview.html

Regular Member
Posts: 420
Registered: ‎02-24-2015
Kudos: 75
Solutions: 8

Re: Secure OpenVPN server setup with multi-factor authentication (Google Authenticator): step-by-ste

[ Edited ]

@GainfulShrimp...

 

Thank you for your awesome write up..!!!

 

I had my setup run the UDP protocol with TLS, and as much as it does work, it did log errors. 

 

The errors referred to possible out of sequence UDP packets when trying to authenticate. The solution offered was to simply use TCP. And this worked perfectly.

 

Cheers...!!! Man Happy

EdgeRouter 8
EdgeSwitch 24 Port (x2), EdgeSwitch 8 Port (x2) and ToughSwitch 5 PoE
UniFi Video running on Intel NUC with eight UVC Gen3 and two UVC-Pro Cameras
UAP-AC, UAP-AC-LR & UAP-AC-Lite.
Member
Posts: 112
Registered: ‎03-25-2015
Kudos: 57
Solutions: 2

Re: Secure OpenVPN server setup with multi-factor authentication (Google Authenticator): step-by-ste

Glad you found it useful @WayneGee

 

According to the OpenVPN docs, usually UDP is the best choice as it doesn't incur the overhead of the inbuilt reliability of TCP (i.e. acknowledging receipt etc) - UDP is a 'fire and forget' style communication where any guarantees are supposed to be provided by the application... but if your connection isn't brilliant, TCP ends up faster. YMMV of course. Man Wink

 

I have both TCP and UDP servers setup, as I'm often behind restrictive firewalls which only allow a few port/protocol combinations through.  I reckon UDP is usually faster, when I can reach it, but there's little if any difference in my iperf tests over both types of connection, so I may just be imagining things.

 

Since I wrote this guide, I've switched my main OpenVPN servers to a Raspberry Pi 2, as it's quicker than the ERLite-3 for OpenVPN.  And I've recently bought a Pi 3 to move to, as it's faster still (and the Pi 3 has four ARMv8 Cortex-A53 cores, so should offer AES crypto acceleration, once somebody gets arm64 Debian/Raspbian working on it).

 

I figure once I get FTTH broadband, I'll need my ERL to concentrate on routing and other tasks left to other boxes, where possible.

This is all a bit pointless for now, as I'm still stuck on slow ADSL broadband.  But when I get FTTH in the next few months (hopefully), the speed difference will matter more. Man Happy

Regular Member
Posts: 420
Registered: ‎02-24-2015
Kudos: 75
Solutions: 8

Re: Secure OpenVPN server setup with multi-factor authentication (Google Authenticator): step-by-ste

@GainfulShrimp...

 

Yes, your guide is very good. 

 

Currently, I implemented only the TLS component, as I have a few questions regarding the 2F component.

 

At present, I have 4096 bit key with a REALLY long password to login via OpenVPN on my EdgeRouter 8. And this is working fine. What I am wondering is, are there any performance or security issues (or gains) swapping to a 2048 bit key?

 

I have a concern regarding having the OpenVPN client and the Google Authenticator apps on the same iOS device. Having said that, I do appreciate it would take some serious brain power on the part of a thief (ie stolen iOS device) to put 2 + 2 together......

 

Considering the above point, adding a password along with the 2F, is an idea. But (as you mentioned) using a decent password and 2F is a hassle. Having a password of only a few characters is an idea, but then this means there is a User account on the router with a really poor password......

 

Man Happy  Man Happy

 

Cheers...! And thanks for your efforts.

EdgeRouter 8
EdgeSwitch 24 Port (x2), EdgeSwitch 8 Port (x2) and ToughSwitch 5 PoE
UniFi Video running on Intel NUC with eight UVC Gen3 and two UVC-Pro Cameras
UAP-AC, UAP-AC-LR & UAP-AC-Lite.
Member
Posts: 112
Registered: ‎03-25-2015
Kudos: 57
Solutions: 2

Re: Secure OpenVPN server setup with multi-factor authentication (Google Authenticator): step-by-ste

Yup, it's all about getting the right compromise between convenience/usability and security.

 

AFAIK, both 2048 and 4096 bit keys are sufficiently strong to prevent brute force, unlike 1024 which some believe is now breakable by weasels with enough resources/supercomputers (e.g. the NSA). 4096 bit is stronger, of course, but might be overkill?
In theory, you'll see slightly quicker negotiation of the initial connection by switching to 2048 bit, but I've not tried 4096 bit so I don't know whether any difference will be noticable in practice...

 

I know what you mean about having the client and token generator on the same device, but in my case I'm connecting from other devices (e.g. my Macbook) as well as my phone, and after all it's about having sufficient multiple layers of security that an attacker will get bored and move on. (If you are under determined and targeted attack by nation state actors like the NSA, then arguably you have much bigger problems to deal with!)

 

The key thing here (sorry for the pun) is to ensure you have an extremely strong device password set on your iPhone, and you use auto-lock etc. That way, the hardware crypto protecting your client keys+certs (assuming you've followed the guide to store them in your Keychain) will protect you in case your device is stolen. Hence all the furore recently about FBI vs Apple and the terrorist's iPhone.

 

Even the phone passcode strength is a compromise, though... For instance: I usually use TouchID with a long alphanumeric passcode, but TouchID doesn't work through gloves and I find it impossible to use an alphanumeric on-screen keyboard when I'm wearing gloves either, so last time I was on holiday skiing, I downgraded to a 6-digit pin so that my fat fingers could still unlock my phone without taking my gloves off! Man Wink

Emerging Member
Posts: 50
Registered: ‎09-12-2015
Kudos: 16
Solutions: 1

Re: Secure OpenVPN server setup with multi-factor authentication (Google Authenticator): step-by-ste

@WayneGee...

 

Thanks for your information!

 

This is interessting - I couldn't authenticate while running the OpenVPN server on UDP.

I had tons of error messages regarding TLS negotiation in the log file...

 

Did you configure something additional on the server side. I only configured the server protocol to UDP and changed the port number when I switched between TCP and UDP 

Regular Member
Posts: 420
Registered: ‎02-24-2015
Kudos: 75
Solutions: 8

Re: Secure OpenVPN server setup with multi-factor authentication (Google Authenticator): step-by-ste

@GainfulShrimp...

 

Thank you for your reply. Man Happy

 

I did forget to mention, I could not create the p12 file. I kept getting errors "unable to load certificates."

 

Cheers..!!! Man Happy

EdgeRouter 8
EdgeSwitch 24 Port (x2), EdgeSwitch 8 Port (x2) and ToughSwitch 5 PoE
UniFi Video running on Intel NUC with eight UVC Gen3 and two UVC-Pro Cameras
UAP-AC, UAP-AC-LR & UAP-AC-Lite.
Regular Member
Posts: 420
Registered: ‎02-24-2015
Kudos: 75
Solutions: 8

Re: Secure OpenVPN server setup with multi-factor authentication (Google Authenticator): step-by-ste

@startoff...

 

All I did was tell the server to use TCP.

 

openvpn-option "--proto tcp"

 

Also, in the opvn file I made, set "proto tcp".

 

Nothing else needed to be done on the OpenVPN side. Just make sure you now allow tcp on your chosen port in the firewall. I just changed mine from udp to tcp.

 

Cheers...!!! Man Happy

EdgeRouter 8
EdgeSwitch 24 Port (x2), EdgeSwitch 8 Port (x2) and ToughSwitch 5 PoE
UniFi Video running on Intel NUC with eight UVC Gen3 and two UVC-Pro Cameras
UAP-AC, UAP-AC-LR & UAP-AC-Lite.
Emerging Member
Posts: 50
Registered: ‎09-12-2015
Kudos: 16
Solutions: 1

Re: Secure OpenVPN server setup with multi-factor authentication (Google Authenticator): step-by-ste


WayneGee wrote:

@GainfulShrimp...

 

Thank you for your reply. Man Happy

 

I did forget to mention, I could not create the p12 file. I kept getting errors "unable to load certificates."

 

Cheers..!!! Man Happy


Yeah, I had the same error message if I tried to create the p12 on ER.

I did it then on my Macbook; no errors at all.

Emerging Member
Posts: 50
Registered: ‎09-12-2015
Kudos: 16
Solutions: 1

Re: Secure OpenVPN server setup with multi-factor authentication (Google Authenticator): step-by-ste


WayneGee wrote:

@startoff...

 

All I did was tell the server to use TCP.

 

openvpn-option "--proto tcp"

 

Also, in the opvn file I made, set "proto tcp".

 


Thanks for your quick reply.

 

I'll give it another try  Icon Smile

Member
Posts: 112
Registered: ‎03-25-2015
Kudos: 57
Solutions: 2

Re: Secure OpenVPN server setup with multi-factor authentication (Google Authenticator): step-by-ste

@startoff and @WayneGee,

 

There was a typo in my guide for the line which generates the .p12 file, sorry!  I'd put 'ca.key' rather than 'ca.crt', hence the error about a problem with the certificates.  I've now edited the post above, but for clarity, this should work:

 

openssl pkcs12 -export -in bob-iphone.crt -inkey bob-iphone.key -certfile ca.crt -name OVPNclient -out bob-iphone.p12

I'll double-check my ovpn files to see if I can spot any other differences between my udp and tcp server configs.

Reply