Environment
For this example we use the following parameters:
- VPN server in local subnet
192.168.0.0/255.255.255.0
behind NAT firewall-router. - VPN subnet
10.168.8.0/255.255.255.0
with max. 10 VPN clients. - The VPN server is accessible via the domain name
mydomainname.com
and will listen at the standard port1194
(but it’s a good idea not to use this standard VPN port but any other unused one, e.g.1199
). - Encryption is done with 2’048 bit long keys and cipher
AES-256-CBC
. - A PKI (public key infrastructure) with key lenghts of 2’048 bits is used for client authentication.
Maybe you have to change these values used below to fit your environment.
Installation
# install packages
sudo su
apt-get update
apt-get install openvpn openssl easy-rsa
# Easy-RSA ist located in a Linux distribution specific sub-folder
# somewhere in /usr/share/
. just search for it:
find /usr/share/ -type d -name easy-rsa
# copy Easy-RSA PKI with sample files and adapt them.
# for Debian or Ubuntu:
cp -r /usr/share/easy-rsa /etc/openvpn/easy-rsa
# for older Debian/Raspbian versions:
cp -r /usr/share/doc/openvpn/examples/easy-rsa/2.0 /etc/openvpn/easy-rsa
Setup Public Key Infrastructure (PKI) & Generate Keys
# edit the RSA variables file
nano /etc/openvpn/easy-rsa/vars
# and change the following variables to:
# set the top level directory of Easy-RSA tree export EASY_RSA="/etc/openvpn/easy-rsa" # set the key size to 2048 bits export KEY_SIZE=2048
# at the bottom of the file, set the default values for creating certificates:
export KEY_COUNTRY="CH" export KEY_PROVINCE="Region" export KEY_CITY="City" export KEY_ORG="Organization" export KEY_OU="Home" export KEY_EMAIL="admin@example.com (changeme)" export KEY_CN="Common Name (changeme)" export KEY_ALTNAMES="Alternative CNs (changeme)" export KEY_NAME="Odroid OpenVPN"
# clean/reset your PKI installation
cd /etc/openvpn/easy-rsa
source vars
./clean-all
# generate a new RSA private key “ca.key”
./pkitool --initca
# create a symlink to the config file of the appropriate openssl version
# (forcing overwrite if it already exists)
ln -fs openssl-1.0.0.cnf openssl.cnf
# build your own root certificate authority (CA)
./build-ca OpenVPN
# build your OpenVPN server certificate/key
./build-key-server server
# build the DIFFIE-HELLMAN parameters.
# this might take a long while for a 2048 bits long prime number,
# but it’s wise to be paranoid enough. 😉
# on an Odroid-C2 it took about 4 minutes and on a RaspPi B+ about 15 minutes
./build-dh
# generate the TLS HMAC (hash message authentication code) key
openvpn --genkey --secret keys/ta.key
OpenVPN Configuration
# server configuration
nano /etc/openvpn/openvpn.conf
# …and add the following content
# (change the name of the DH parameter file dh2048.pem
accordingly
# if you have chosen a different size than 2048)
#------------------------------------------------ # OpenVPN server configuration # for <Odroid/RasPi> #------------------------------------------------ # Which local IP address should OpenVPN # listen on? (optional) ;local 192.168.0.x # Which TCP/UDP port should OpenVPN listen on? # If you want to run multiple OpenVPN instances # on the same machine, use a different port # number for each one. You will need to # open up this port on your firewall. port 1194 # TCP or UDP server? ;proto tcp proto udp # "dev tun" will create a routed IP tunnel, # "dev tap" will create an ethernet tunnel. # Use "dev tap0" if you are ethernet bridging # and have precreated a tap0 virtual interface # and bridged it with your ethernet interface. # If you want to control access policies # over the VPN, you must create firewall # rules for the the TUN/TAP interface. # On non-Windows systems, you can give # an explicit unit number, such as tun0. # On Windows, use "dev-node" for this. # On most systems, the VPN will not function # unless you partially or fully disable # the firewall for the TUN/TAP interface. ;dev tap dev tun # SSL/TLS root certificate (ca), certificate # (cert), and private key (key). Each client # and the server must have their own cert and # key file. The server and all clients will # use the same ca file. # # See the "easy-rsa" directory for a series # of scripts for generating RSA certificates # and private keys. Remember to use # a unique Common Name for the server # and each of the client certificates. # # Any X509 key management system can be used. # OpenVPN can also use a PKCS #12 formatted key file # (see "pkcs12" directive in man page). ca /etc/openvpn/easy-rsa/keys/ca.crt cert /etc/openvpn/easy-rsa/keys/server.crt key /etc/openvpn/easy-rsa/keys/server.key # Certificate revocation list crl-verify /etc/openvpn/easy-rsa/keys/crl.pem # Diffie Hellman parameters. dh /etc/openvpn/easy-rsa/keys/dh2048.pem # Configure server mode and supply a VPN subnet # for OpenVPN to draw client addresses from. # The server will take 10.8.0.1 for itself, # the rest will be made available to clients. # Each client will be able to reach the server # on 10.8.0.1. Comment this line out if you are # ethernet bridging. See the man page for more info. server 10.168.8.0 255.255.255.0 # Push routes to the client to allow it # to reach other private subnets behind # the server. Remember that these # private subnets will also need # to know to route the OpenVPN client # address pool (10.8.0.0/255.255.255.0) # back to the OpenVPN server. # add route to the OpenVPN subnet: push "route 10.168.8.0 255.255.255.0" # add route to the local subnet: push "route 192.168.0.0 255.255.255.0" # If enabled, this directive will configure # all clients to redirect their default # network gateway through the VPN, causing # all IP traffic such as web browsing and # and DNS lookups to go through the VPN # (The OpenVPN server machine may need to NAT # the TUN/TAP interface to the internet in # order for this to work properly). # CAVEAT: May break client's network config if # client's local DHCP server packets get routed # through the tunnel. Solution: make sure # client's local DHCP server is reachable via # a more specific route than the default route # of 0.0.0.0/0.0.0.0. ;push "redirect-gateway" push "redirect-gateway def1" # Certain Windows-specific network settings # can be pushed to clients, such as DNS # or WINS server addresses. CAVEAT: # http://openvpn.net/faq.html#dhcpcaveats push "dhcp-option DNS 62.2.17.60" push "dhcp-option DNS 62.2.24.158" # Uncomment this directive to allow different # clients to be able to "see" each other. # By default, clients will only see the server. # To force clients to only see the server, you # will also need to appropriately firewall the # server's TUN/TAP interface. client-to-client # The keepalive directive causes ping-like # messages to be sent back and forth over # the link so that each side knows when # the other side has gone down. # Ping every 30 seconds, assume that remote # peer is down if no ping received during # a 120 second time period. ;keepalive 30 120 # For extra security beyond that provided # by SSL/TLS, create an "HMAC firewall" # to help block DoS attacks and UDP port flooding. # # Generate with: # openvpn --genkey --secret ta.key # # The server and each client must have # a copy of this key. # The second parameter should be '0' # on the server and '1' on the clients. ;tls-auth ta.key 0 # This file is secret tls-auth /etc/openvpn/easy-rsa/keys/ta.key 0 # Select a cryptographic cipher. # This config item must be copied to # the client config file as well. ;cipher BF-CBC # Blowfish (default) cipher AES-256-CBC # AES ;cipher DES-EDE3-CBC # Triple-DES # Enable compression on the VPN link. # If you enable it here, you must also # enable it in the client config file. comp-lzo # The maximum number of concurrently connected # clients we want to allow. max-clients 10 # It's a good idea to reduce the OpenVPN # daemon's privileges after initialization. # # You can uncomment this out on # non-Windows systems. user nobody group nogroup # The persist options will try to avoid # accessing certain resources on restart # that may no longer be accessible because # of the privilege downgrade. persist-key persist-tun # Output a short status file showing # current connections, truncated # and rewritten every minute. status /var/log/openvpn-status.log # By default, log messages will go to the syslog (or # on Windows, if running as a service, they will go to # the "\Program Files\OpenVPN\log" directory). # Use log or log-append to override this default. # "log" will truncate the log file on OpenVPN startup, # while "log-append" will append to it. Use one # or the other (but not both). ;log openvpn.log ;log-append openvpn.log log-append /var/log/openvpn.log # Set the appropriate level of log # file verbosity. # # 0 is silent, except for fatal errors # 4 is reasonable for general usage # 5 and 6 can help to debug connection problems # 9 is extremely verbose verb 3 # Tell the clients to send a notification on exit push "explicit-exit-notify 3"
# create the client configuration template file …
nano /etc/openvpn/client-template.ovpn
# … with the content below
client dev tun proto udp remote mydomainname.com 1194 resolv-retry infinite nobind persist-key persist-tun comp-lzo verb 3 mute-replay-warnings mute 20 ns-cert-type server key-direction 1 cipher AES-256-CBC
Make sure this file has at least one new line at the end! Otherwise the script will create false configuration files.
# create client configuration directory
md /etc/openvpn/clients
Network Routing
# define routing for the clients i.e. NAT the VPN client traffic to the internet.
# this command assumes that the VPN subnet is 10.168.8.0/24
# (taken from the server directive in the OpenVPN server configuration)
# and that the local ethernet interface is eth0
.
sh -c 'echo 1 > /proc/sys/net/ipv4/ip_forward'
iptables -t nat -A POSTROUTING -s 10.168.8.0/24 -o eth0 -j MASQUERADE
nano /etc/sysctl.conf
# enable ipv4 forwarding by uncommenting the following line: net.ipv4.ip_forward=1
# edit Crontab : make a Crontab entry to make this routing persistent,
# i.e. apply this setting at every boot
crontab -e
@reboot sudo iptables -t nat -A POSTROUTING -s 10.168.8.0/24 -o eth0 -j MASQUERADE
Don’t forget to forward your OpenVPN port (in this example 1194
) to your OpenVPN server on your NAT firewall-router!
Self-signed Certificate Revocation List (CRL)
(based on “SOHO Remote Access VPN – Easy as Pie.pdf”)
# go to the Easy-RSA sub-folder and at the very first time
# just revoke an invalid/inexistent dummy certificate to create the CRL files.
cd /etc/openvpn/easy-rsa
./revoke-full dummy
This will result in some erros regarding the not existing certificate „dummy“ that can be ignored.
# and make sure the CRL file is world readable
chmod 644 /etc/openvpn/easy-rsa/keys/crl.pem
# open the server configuration file
nano /etc/openvpn/openvpn.conf
# … and make sure it contains the following line
# (this is already the case if you have created the file as told above)
# Certificate revocation list crl-verify /etc/openvpn/easy-rsa/keys/crl.pem
OpenVPN will consult the new CRL for any new connections (after restarting with the new server configuration). However, a user currently logged in and whose certificate is revoked will not be kicked off unless the OpenVPN service is restarted.
Start/Stop/Restart OpenVPN Service
# start OpenVPN with the new settings
/etc/init.d/openvpn start
# alternatively you can start the OpenVPN service on newer systems with
service openvpn start
For stopping or restarting just replace start
with stop
or restart
.
Client Configuration Generation Script
# create script for automated client configuration file generation
nano /etc/openvpn/OvpnMakeClientConf.sh
# add the following content with the appropriate destination folder
# and owner of the client configuration package in the three DEST
-variables:
#!/bin/bash # Variable Declarations OVPNTEMPLATE="client-template.ovpn" OVPNCLIENTS="/etc/openvpn/clients/" EXTOVPN=".ovpn" EXTCRT=".crt" EXTKEY=".key" EXTCSR=".csr" CAKEY="ca.crt" TAKEY="ta.key" KEYSRC="/etc/openvpn/easy-rsa/keys/" PREFIX="openvpn-" DEST="/home/odroid/" DESTOWNER="odroid" DESTGROUP="odroid" # use client name if passed as argument NAME=$1 # otherwise read it from the console if [ "($NAME)" == "()" ]; then # ask for a client name echo "Enter Client Name (the certificate has been generated with): " read NAME fi # verify that client's public key exists if [ ! -f $KEYSRC$NAME$EXTCRT ]; then echo "[ERROR]: Client Public Key Certificate not found: $KEYSRC$NAME$EXTCRT" exit fi echo "Client's cert found: $KEYSRC$NAME$EXTCRT" # verify that there is a private key for that client if [ ! -f $KEYSRC$NAME$EXTKEY ]; then echo "[ERROR]: Client Private Key not found: $KEYSRC$NAME$EXTKEY" exit fi echo "Client's Private Key found: $KEYSRC$NAME$EXTKEY" # confirm the CA public key exists if [ ! -f $KEYSRC$CAKEY ]; then echo "[ERROR]: CA Public Key not found: $KEYSRC$CAKEY" exit fi echo "CA public Key found: $KEYSRC$CAKEY" # confirm the tls-auth ta key file exists if [ ! -f $KEYSRC$TAKEY ]; then echo "[ERROR]: tls-auth Key not found: $KEYSRC$TAKEY" exit fi echo "tls-auth Private Key found: $KEYSRC$TAKEY" # ready to make a new client .opvn file - start by populating with the template file cat $OVPNTEMPLATE > $OVPNCLIENTS$NAME$EXTOVPN # append the CA Public Cert echo "<ca>" >> $OVPNCLIENTS$NAME$EXTOVPN cat $KEYSRC$CAKEY >> $OVPNCLIENTS$NAME$EXTOVPN echo "</ca>" >> $OVPNCLIENTS$NAME$EXTOVPN # append the client Public Cert echo "<cert>" >> $OVPNCLIENTS$NAME$EXTOVPN cat $KEYSRC$NAME$EXTCRT | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' >> $OVPNCLIENTS$NAME$EXTOVPN echo "</cert>" >> $OVPNCLIENTS$NAME$EXTOVPN # append the client Private Key echo "<key>" >> $OVPNCLIENTS$NAME$EXTOVPN cat $KEYSRC$NAME$EXTKEY >> $OVPNCLIENTS$NAME$EXTOVPN echo "</key>" >> $OVPNCLIENTS$NAME$EXTOVPN # append the TA Private Key echo "<tls-auth>" >> $OVPNCLIENTS$NAME$EXTOVPN cat $KEYSRC$TAKEY >> $OVPNCLIENTS$NAME$EXTOVPN echo "</tls-auth>" >> $OVPNCLIENTS$NAME$EXTOVPN echo "$NAME$EXTOVPN successfully created." tar czf $OVPNCLIENTS$PREFIX$NAME.tgz -C $KEYSRC $CAKEY $TAKEY $NAME$EXTCRT $NAME$EXTCSR $NAME$EXTKEY -C $OVPNCLIENTS $NAME$EXTOVPN mv $OVPNCLIENTS$PREFIX$NAME.tgz $DEST chown $DESTOWNER:$DESTGROUP $DEST$PREFIX$NAME.tgz echo "Done! $DEST$PREFIX$NAME.tgz successfully created."
# for a RaspberryPi the three DEST
-variables could be:
DEST="/home/pi/" DESTOWNER="pi" DESTGROUP="pi"
# make the script executable
chmod 700 /etc/openvpn/OvpnMakeClientConf.sh
Create Client Keys
# replace “clientX” with your client name.
# the clients don’t have to have a user account on this machine
# (i.e. this solution is totally independent of any user accounts).
# the common name of the client key must match the client name.
cd /etc/openvpn/easy-rsa/
source vars
./build-key clientX
Create Client Configuration
# replace “clientX” with your client name
# (as used for the previously generated client key).
cd /etc/openvpn
./OvpnMakeClientConf.sh clientX
Make sure you have generated the client keys before running this script! You’ll find the generated OpenVPN client configuration files in the destination directory as defined in the script.
Create Client Keys and Configuration
With the following script you can combine the two steps above.
# create script for automated client key and configuration file generation
nano /etc/openvpn/OvpnMakeClientKeysConf.sh
# and add the following content:
#!/bin/bash # Easy-RSA directory (without trailing "/") EASYRSA="/etc/openvpn/easy-rsa" # use client name if passed as argument NAME=$1 # otherwise read it from the console if [ "($NAME)" == "()" ]; then # ask for a client name echo "Enter Client Name: " read NAME fi # create client keys source $EASYRSA/vars $EASYRSA/build-key $NAME # create client configuration ./OvpnMakeClientConf.sh $NAME
# make the script executable
chmod 700 /etc/openvpn/OvpnMakeClientKeysConf.sh
# call the script
# replace “clientX” with your client name
cd /etc/openvpn
./OvpnMakeClientKeysConf.sh clientX
Revoke a Client Certificate
# create script for client certificate revocation
nano /etc/openvpn/OvpnRevokeClient.sh
# and add the following content:
#!/bin/bash # Easy-RSA directory (without trailing "/") EASYRSA="/etc/openvpn/easy-rsa" # Variable Declarations KEYSRC="/etc/openvpn/easy-rsa/keys/" EXTCRT=".crt" CRL=crl.pem # use client name if passed as argument NAME=$1 # otherwise read it from the console if [ "($NAME)" == "()" ]; then # ask for a client name echo "Enter Client Name (the certificate has been generated with): " read NAME fi # verify that client's public key exists if [ ! -f $KEYSRC$NAME$EXTCRT ]; then echo "[ERROR]: Client Public Key Certificate not found: $KEYSRC$NAME$EXTCRT" exit fi echo "Client's cert found: $KEYSRC$NAME$EXTCRT" # revoke client's certificate # this will add it to the CRL source $EASYRSA/vars $EASYRSA/revoke-full $NAME # make the CRL world readable chmod 644 $KEYSRC$CRL echo "Done!"
# make the script executable
chmod 700 /etc/openvpn/OvpnRevokeClient.sh
# call the script
# replace “clientX” with your client name
cd /etc/openvpn
./OvpnRevokeClient.sh clientX
# the script will display status information as it progresses. look specifically for
# “error 23
”. this indicates that the certificate was successfully revoked.
# optional: verify the certificate has been added to the revocation list
openssl crl -text -noout -in /etc/openvpn/easy-rsa/keys/crl.pem
List Revoked Certificates
# list revoked certificates
cd /etc/openvpn/easy-rsa
source vars
./list-crl
Hints and Recommendations
You can make the client configuration files accessible by Samba sharing the client file destination folder.
What To Find Where
Path & Filename | Purpose |
/etc/openvpn/openvpn.conf |
OpenVPN server configuration |
/etc/openvpn/client-template.ovpn |
OpenVPN client configuration template |
/etc/openvpn/OvpnMakeClientConf.sh |
OpenVPN client configuration gereration script (with existing keys) |
/etc/openvpn/OvpnMakeClientKeysConf.sh |
Client keys and OpenVPN client configuration gereration script (calls OvpnMakeClientConf.sh ) |
/etc/openvpn/easy-rsa/* |
Easy-RSA scripts and config files |
/etc/openvpn/easy-rsa/keys/* |
PKI keys and certificates (see details below) |
/etc/openvpn/clients/*.ovpn |
OpenVPN configuration files for client devices |
Easy-RSA creates the following PKI files in the directory /etc/openvpn/easy-rsa/keys
:
Filename | Purpose |
ca.key |
root CA private key |
ca.crt |
root CA public key/certifiacte |
server.key |
OpenVPN server private key |
server.csr |
OpenVPN server certificate signing request |
server.crt |
OpenVPN server certificate |
dh{DH-size}.pem |
Diffie Hellman parameter file |
ta.key |
TLS HMAC key (hash message authentication code) |
crl.pem |
certificate revocation list |
<UserName>.key |
UserName private key |
<UserName>.csr |
UserName certificate signing request |
<UserName>.crt |
UserName certificate |
Remove the following client files from the OpenVPN server and store them securely offline:
Filename | Purpose |
/etc/openvpn/easy-rsa/keys/<UserName>.key |
UserName private key |
/etc/openvpn/easy-rsa/keys/<UserName>.csr |
UserName certificate signing request |
/etc/openvpn/clients/<UserName>.ovpn |
OpenVPN configuration file for client devices |
Troubleshooting
The OpenVPN server logs are located in /var/log/openvpn.log
and /var/log/openvpn-status.log