OpenVPN

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 port 1194 (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

Links

Schreibe einen Kommentar