OpenVPN: Integration with LinOTP

Introduction

This article describes how to improve the security of connecting VPN clients by implementing an additional security layer based on the two factor authentication provided by LinOTP. Clients of your VPN do not only require the normal VPN certificate or a shared secret, they also need to provide a One Time Password to improve security significantly. There are various methods to use OTP with OpenVPN - the following will be described in this guide:

  • authentification by a RADIUS server connected to LinOTP done by:
    • openVPN plugin: openvpn-auth-radius
    • PAM: libpam-radius-auth
  • authentification by PAM through the LinOTP web API done by:
    • PAM python modul: pam_linotp.py
    • PAM C modul: pam_linotp

If you don't have an openVPN server you find a how-to of a basic setup in the end of this document with all the certificate stuff (also includes client side): Install VPN Server

What this guide does not cover:

Prerequisites

You will need a basic installation of Debian Wheezy and ideally an already running openVPN setup. If you are missing the OpenVPN setup, go to Install VPN Server first and then come back here.

Package versions

This how-to was tested with the following versions of packages (retrieved from Debian Wheezy and LinOTP repositories plus pip) :

  • openvpn: 2.2.1-8+deb7u2
  • openssl: 1.0.1e-2+deb7u7
  • openvpn-auth-radius: 2.1-4
  • libpam-radius-auth: 1.3.16-4.4
  • libpam-python: 1.0.2-1
  • pam_linotp.py: 2.7

Don't worry - you can use these packages in other version (older as well as newer, but of course newer is recommended) and have a successfully running setup. But if you encounter obscure problems, please check the changelogs, whether they contain any related modifications.

Authentification via RADIUS

RADIUS is widely used authentification protocol. If you have a RADIUS server running you can connect it to LinOTP and use it's One Time Passwords as (additional) authentification layer for your VPN clients (see our LinOTP+RADIUS documentation how such a setup is done: http://linotp.org/howtos/howto-radius.html).

Here we describe how to establish an authorisation request from the VPN server to the RADIUS server.

We assume you have the following:

Connect to RADIUS via VPN plugin

It is really easy to add an additional OneTimePassword (OTP) to your certificate+key based authentification, because there is already an openVPN plugin available for RADIUS.

Overview openVPN plugin + RADIUS

Install the necessary packages on your VPN server:

apt-get install openvpn-auth-radius openssl

Copy the configuration file of the pluging to your VPN directory:

cp /usr/share/doc/openvpn-auth-radius/examples/radiusplugin.cnf /etc/openvpn/

TIP: We work with a copy of the 'radiusplugin.cnf'. Hereby we avoid the risk of loosing our precious configuration due to a system update.

Adopt '/etc/openvpn/radiusplugin.cnf' to your needs:

#Our name, can be anything...
NAS-Identifier=VPN
#some default RADIUS-parameters
Service-Type=5
Framed-Protocol=1
NAS-Port-Type=5

#Our IP, if RADIUS is configured with IP based
#access restriction you better put the correct one in...
NAS-IP-Address=192.168.122.120 

#The plugins needs to interpret the used configuration file
OpenVPNConfig=/etc/openvpn/server.conf

#The plugin may interfere with the client configuration directories 
#if necessary
overwriteccfiles=true

server
{
#The authentification Port of the RADIUS server
        authport=1812

#The IP of the RADIUS server
        name=192.168.122.162

#How often should an authentifications be retried before marked as "failed"?
        retry=1
        wait=1

#Shared secret of the RADIUS server
        sharedsecret=SECRET
}

IMPORTANT: Secure '/etc/openvpn/radiusplugin.cnf' to be readable by root only, because the RADIUS server secret is therein (it is in fact clear text...)

Go to your VPN server configuration file (i.e. '/etc/openvpn/server.conf') and add the following line:

plugin /usr/lib/openvpn/radiusplugin.so /etc/openvpn/radiusplugin.cnf

Activate new server configuration:

WARNING: If you do so only clients providing a correct OTP in addition to a valid client certificate will be able to connect successfully to your VPN server.

  • Open a terminal and connect to the main logfile:
  • tail -f /var/log/syslog
  • Restart the server:
  • service openvpn restart
Go to chapter VPN client OTP integration next.

Connect to RADIUS via PAM (libpam-radius-auth)

While using the VPN plugin mechanism is a quite minimal intrusive way to contact the RADIUS server it is (at the moment) limited i.e. regarding the use of a two-way-challenge OneTimePassword. Furthermore if you use the more generic implementation of PAM you can at will add the OneTimePassword authentification to any login procedure of your system (ssh, terminal-logins etc.), which is great. So if you plan to use your LinOTP structure for more than one service you should probably go for this solution.

Overview libpam-radius-auth + RADIUS
  • Install the necessary package (at your VPN server):
  • apt-get install libpam-radius-auth
  • Adopt plugin configuration to your needs:
  • You will find the documentation and examples of the PAM module in '/usr/share/doc/libpam-radius-auth'. Have a look... And adopt the configuration of the PAM plugin in '/etc/pam_radius_auth.conf' according to your needs:

    # RADIUSserver[:port] shared_secret_of_RADIUS_server      timeout (s)
    # you can provide more than one server line
    192.168.8.203   	SECRET			3
      
  • Activate Modul:
  • We have to change the VPN Server configuration in order to use the PAM infrastructure. This is done by activating the openvpn-auth-pam plugin.

    Add this line to your configuration file '/etc/openvpn/server.conf':

    plugin /usr/lib/openvpn/openvpn-auth-pam.so openvpn

    WARNING: The name of the PAM file must be the same as the parameter of the plugin!

    The argument 'openvpn' of the plugin is the (future) PAM configuration which is to call the 'openvpn_auth-pam' plugin.

  • Create a new file '/etc/pam.d/openvpn':
  • auth 	[success=1 default=ignore] 	pam_radius_auth.so
    auth 	requisite           		pam_deny.so
    auth 	required 			pam_permit.so
    account required 			pam_permit.so
    

    You can set the parameter 'debug' for the plugin to make it verbose in case of trouble.

Serverside is finished, we will need to adjust the client configuration as well. See the chapter VPN client OTP integration how this is done.

Direct authentification via LinOTP web interface (no RADIUS server needed)

As it comes in the world of Open source, there are two implementations of the necessary PAM module:

  • libpam-python together with pam_py_linotp (so a script-based variant, developed and updated the LinOTP)
  • pam_linotp (written in C)

Both PAM modules connect directly to the https-interface of your LinOTP instance. So no trouble in setting up a RADIUS server :)

Which one you like more is up to you, we will show both setups here.

pam_py_linotp

WARNING: pam_py_linotp in version 2.7 needs an existing local user for successful authentification (which is not as it should be - use pam_linotp instead if usermanagement differs between the VPN server and the used LinOTP UserIdResolver.

Overview pam_py_linotp
  • The python-based PAM plugin requires the package 'libpam-python':
  • apt-get install libpam-python python
  • Then we need the PAM plugins itself. Here you have two options:
    • Download by hand from 'https://pypi.python.org/pypi/pam_py_linotp/':
      • download:
      • wget --no-check-certificate -P /tmp https://pypi.python.org/packages/source/p/pam_py_linotp/pam_py_linotp-2.7.tar.gz
      • extract:
      • tar -C /tmp -xzf /tmp/pam_py_linotp-2.7.tar.gz
      • install:
      • cp /tmp/pam_py_linotp-2.7/src/pam_linotp.py /lib/security/
    • or: install via 'pip'
      • provide requirements:
      • apt-get install python-pip
      • install:
      • pip install pam_py_linotp
  • Activate plugin:
  • We have to change the VPN Server configuration in order to use the PAM python plugin. This is done by activating the openvpn-auth-pam plugin of the VPN server.

    Add this line to your configuration file '/etc/openvpn/server.conf':

    plugin /usr/lib/openvpn/openvpn-auth-pam.so openvpn

    WARNING: The name of the PAM file must be the same as the parameter of the plugin! The argument 'openvpn' of the plugin is the (future) PAM configuration which is to call the openvpn_auth-pam plugin.

  • Create a new file '/etc/pam.d/openvpn'
  • auth [success=1 default=ignore]  pam_python.so /lib/security/pam_linotp.py \
    nosslhostnameverify nosslcertverify url=https://192.168.8.203/validate/simplecheck
    auth    requisite                       pam_deny.so
    auth    required                        pam_permit.so
    account required                        pam_permit.so
    

    Substitute the IP with the one of your RADIUS server.

    WARNING: If you have self-signed https-certificates you must set the 'nosslhostnameverify' and 'nosslcertverify' plugin options.

The pam_linotp.py plugin knows a number of parameters:

  • url= - the IP of your LinOTP machine
  • realm= - sets the realm which should be used to get the authentification (i.e. 'realm=management'), if not set it defaults to the standardrealm of LinOTP
  • debug - if you have trouble, try to set this - you will get a lot more messages in the logfiles (i.e. in '/var/log/auth') - be careful: the PIN+OTP will be shown
  • nosslhostnameverify - ignore the mismatch of real hostname and the hostname in the certificate
  • nosslcertverify - necessary for self-signed certificates

Serverside is finished, we will need to adjust the client configuration as well. See the chapter VPN client OTP integration how this is done.

pam_linotp

Overview pam_linotp
  • If not yet done, add the linotp-Repository to your openVPN server.
  • echo 'deb http://www.linotp.org/apt/debian wheezy linotp' > /etc/apt/sources.list.d/linotp.list
  • Add the gpg-key of linotp to your apt-keyring:
  • apt-key adv --keyserver eu.pool.sks-keyservers.net --recv-keys 913DFF12F86258E5
  • And install the in C written pam_linotp:
  • apt-get update
    apt-get install libpam-linotp
    	
  • Activate plugin:
  • We have to change the VPN Server configuration in order to use the PAM plugin. This is done by activating the openvpn-auth-pam plugin of the VPN server.

    Add this line to your configuration file '/etc/openvpn/server.conf':

    plugin /usr/lib/openvpn/openvpn-auth-pam.so openvpn

    WARNING: The name of the PAM file must be the same as the parameter of the plugin! The argument 'openvpn' of the plugin is the (future) PAM configuration which is to call the openvpn_auth-pam plugin.

  • Create a new file '/etc/pam.d/openvpn'
  • auth [success=1 default=ignore]  pam_linotp.so nosslhostnameverify \
    nosslcertverify url=https://192.168.8.203/validate/simplecheck
    auth    requisite                       pam_deny.so
    auth    required                        pam_permit.so
    account required                        pam_permit.so
    

    WARNING: If you have self-signed https-certificates you must set the 'nosslhostnameverify' and 'nosslcertverify' plugin options.

The pam_linotp plugin knows a number of parameters:

  • url= - the IP of your LinOTP machine
  • realm= - sets the realm which should be used to get the authentification (i.e. 'realm=management'), if not set it defaults to the standardrealm of LinOTP
  • debug - if you have trouble, try to set this - you will get a lot more messages in the logfiles (i.e. in '/var/log/auth') - be careful: the PIN+OTP will be shown
  • nosslhostnameverify - ignore the mismatch of real hostname and the hostname in the certificate
  • nosslcertverify - necessary for self-signed certificates

Serverside is finished, we will need to adjust the client configuration as well. See the next chapter VPN client OTP integration how this is done.

VPN client OTP integration

  • Add the following line to your client configuration file (i.e. '/etc/openvpn/my-company.conf').
  • auth-user-pass
  • And restart openVPN:
  • service openvpn restart

    Now you will be asked for a username - provide (a valid) one and answer the following question for the password with the PIN and the OTP written consecutivly.
    So, i.e., if your PIN is '4886' and your OTP is '798392' write '4886798392'

    Here you see how such a dialog looks alike:

    service openvpn start
    [....] Starting virtual private network daemon: my-companyEnter Auth Username:fritz                                                                           
    Enter Auth Password:
    Enter Private Key Password:
    . ok
    

    Auth Username - username of the authentification request

    Auth Password - PIN+OTP (without the "+")

    Private Key Password - the Passphrase of the private key

    TIP: If you use the linOTP appliance the RADIUS-Authport (1813) is closed and even if we don't use accounting the openvpn-plugin tries to connect. So if you find something like

    Thu Oct 23 15:06:24 2014 RADIUS-PLUGIN: BACKGROUND ACCT: Error: Start packet couldn't send.
    Thu Oct 23 15:06:24 2014 Error: RADIUS-PLUGIN: FOREGROUND: Accounting failed for user:tux!
    Thu Oct 23 15:06:24 2014 PLUGIN_CALL: plugin function PLUGIN_CLIENT_CONNECT failed with status 1: /usr/lib/openvpn/radiusplugin.so
    Thu Oct 23 15:06:24 2014 WARNING: client-connect plugin call failed
    
    in the log of your openVPN server, you will have to open the port on your linOTP machine:
    iptables -A INPUT -p udp -m udp --dport 1813 -j ACCEPT
    

    Troubleshooting tips:

    • keep an eye on the logfile of your VPN server to determine the source of any authentification problems (i.e. '/var/log/syslog' and '/var/log/auth').
    • if for any reasons you can not connect successfully to your RADIUS server, look in the log files there
    • check the firewall-rules of RADIUS and VPN server
    • listen with i.e. 'tcpdump' at the RADIUS server to see, if there is any communication trial seen from the VPN server

    Congratulation - you just improved the security of your VPN a lot!

    Install VPN Server

    If you are not familiar with OpenVPN or you need a working testsetup to try out LinOTP as described above you should follow this tutorial.

    We go straight forward with the Debian package:

    apt-get install openvpn

    Basic VPN Setup secured by certificates

    Generate certificates

    If you already have have a certificate-infrastracture you can skip this and go on with Setup VPN Server

    The following steps should be performed at an offline maschine due to security reasons. We will need (and so create) the following ressources:

    • one CA - Certificate Authority, consisting of a public certificate and a private key
    • one VPN-Server certificate and private key
    • A(multiple) certificates and privates key for the VPN clients

    What are all this keys good for? Server and Client certificates and keys are used to authenticate each other (so not everybody can connect to your precious openVPN) and to establish an encrypted connection. The Certificate Authority signs the certificates of both sides and only correctly signed certificates are accepted during initialization of the VPN-connection.

    WARNING: If ever anybody gets access to your CA he will be able to sign arbitrary certificates and connect to your VPN by them (that is why the CA should be on a secured machine). And you should make sure to backup the files of your CA. If they are lost you will not be able to revoke issued certificates.

    There is a bundle of scripts included in Debian's openVPN-package which eases the generation of the CA and the necessary certificates and keys a lot: 'easy-rsa'. So just install 'openvpn' on your soon-to-be CA-computer (and disable openvpn, because this is not becoming your server):

    apt-get install openvpn openssl
    service openvpn stop
    update-rc.d openvpn disable
    

    Copy the scripts somewhere more convenient:

    cp -a /usr/share/doc/openvpn/examples/easy-rsa/2.0 /etc/easy-rsa
    Generate CA

    Personalize Certificate Authority

    '/etc/openvpn/easy-rsa/vars' contains information of the Certificate Authority - change this file according to your needs. What you provide here will be included in the certificate of the CA and makes it identifiable.

    cd /etc/easy-rsa
    vim vars
    

    /etc/openvpn/easy-rsa/vars:

    export EASY_RSA="`pwd`"
    export OPENSSL="openssl"
    export PKCS11TOOL="pkcs11-tool"
    export GREP="grep"
    
    export KEY_CONFIG=`$EASY_RSA/whichopensslcnf $EASY_RSA`
    
    #This is the to-be key-directory. It will contain all keys and certificates and is delete 
    #if you execute the script ./clean-all
    export KEY_DIR="$EASY_RSA/keys"
    
    # Issue rm -rf warning
    echo NOTE: If you run ./clean-all, I will be doing a rm -rf on $KEY_DIR
    
    # PKCS11 fixes
    export PKCS11_MODULE_PATH="dummy"
    export PKCS11_PIN="dummy"
    
    # Increase this to 2048 if you
    # are paranoid.  This will slow
    # down TLS negotiation performance
    # as well as the one-time DH parms
    # generation process.
    export KEY_SIZE=2048
    
    # In how many days should the root CA key expire? 
    # For security reasons set it to a low value but if you 
    # do so you will have to roll out new keys and certificates
    # every time your CA expires...
    export CA_EXPIRE=3650
    
    # In how many days should certificates expire? You should limit
    # issued certificates to protect your VPN from stolen client-certificates.
    export KEY_EXPIRE=3650
    
    # These are the default values for fields
    # which will be placed in the certificate.
    # Don't leave any of these fields blank.
    export KEY_COUNTRY="US"
    export KEY_PROVINCE="CA"
    export KEY_CITY="San Francisco"
    export KEY_ORG="My Company"
    export KEY_EMAIL="ca@my-company.net"
    export KEY_CN="My Company Certificate Authority"
    
    #additional information you can provide to 
    #make your certificate more uniqe
    #export KEY_NAME=changeme
    #export KEY_OU=changeme
    

    Now it is time to start the CA-generation.

    source vars
    ./clean-all
    ./build-ca
    

    IMPORTANT: './clean-all' will remove any old 'keys' directory. This is alright if it is the first time you initialize your CA. If it is not the first time in this directory you use the scripts you will loose any previous certificates and keys.

    This will trigger a dialog, where the values of the 'vars' file are provide as default and can be accepted by just pressing .

    TIP: Leave out fields by using a '.' as content.

    root@server:/etc/easy-rsa# ./build-ca 
    Generating a 2048 bit RSA private key                                                             
    ..............................................+++ 
    ..........+++ 
    writing new private key to 'ca.key' 
     ----- 
    You are about to be asked to enter information that will be incorporated 
    into your certificate request.
    What you are about to enter is what is called a Distinguished Name or a DN. 
    There are quite a few fields but you can leave some blank
    For some fields there will be a default value,
    If you enter '.', the field will be left blank.
     -----
    Country Name (2 letter code) [US]:
    State or Province Name (full name) [CA]:
    Locality Name (eg, city) [San Francisco]:
    Organization Name (eg, company) [My Company]:
    Organizational Unit Name (eg, section) []:.
    Common Name (eg, your name or your server's hostname) [My Company Certificate Authority]:
    Name []:
    Email Address [ca@my-company.net]:
    

    Congratulation! You just created your first CA - the files are placed in a (newly created) '/etc/openvpn/easy-rsa/keys' directory:

    -rw-r--r-- 1 root root 1253 Jun 20 11:23 ca.crt
    -rw------- 1 root root  916 Jun 20 11:23 ca.key
    -rw-r--r-- 1 root root    0 Jun 20 11:22 index.txt
    -rw-r--r-- 1 root root    3 Jun 20 11:22 serial
    
    • ca.crt - The public certificate of your CA. It will be distributed to all VPN clients later.
    • ca.key - The private key of the CA, must be kept secret by all means (notice the permissions of the files...)

    You don't have to care of the 'index.txt' and 'serial' files, they are for internal purposes.

    TIP: You can control the content of your CA certificate with 'openssl x509 -in keys/ca.crt -text'. If you don' like what you see here start again with editing 'vars' then 'source vars', './clean_all' and './build_ca'.

    Now, we are ready for the next step - the generation of the server certificate.

    Generate server certificate

    Having the CA, we can issue the certificate and the key of our openVPN server. 'easy-rsa' has a script for this too, you just have to provide a filename as parameter:

    ./build-key-server vpn1.my-company.net

    Next steps should look familiar, proceed as above in section 'Generate CA'.

    IMPORTANT: The "Common Name" field must be unique to your certificate structure.

    Leave blank:

    ....
    A challenge password []:
    An optional company name []:
    ....
    

    Answer the yes-no questions with 'yes':

    ....
    Sign the certificate? [y/n]:y
    ....
    1 out of 1 certificate requests certified, commit? [y/n]y
    ....
    

    Here the complete (example) procedure:

    root@vpnserver:/etc/easy-rsa# ./build-key-server vpn1.my-company.net
    Generating a 1024 bit RSA private key
    .......++++++
    ........++++++
    writing new private key to 'vpn1.my-company.net.key'
    You are about to be asked to enter information that will be incorporated
    into your certificate request.
    What you are about to enter is what is called a Distinguished Name or a DN.
    There are quite a few fields but you can leave some blank
    For some fields there will be a default value,
    If you enter '.', the field will be left blank.
    Country Name (2 letter code) [US]:
    State or Province Name (full name) [CA]:
    Locality Name (eg, city) [San Francisco]:
    Organization Name (eg, company) [My company]:
    Organizational Unit Name (eg, section) []:.
    Common Name (eg, your name or your server's hostname) [vpn1.my-company.net]:
    Name []:.
    Email Address [ca@my-company.net]:
    
    Please enter the following 'extra' attributes
    to be sent with your certificate request
    A challenge password []:
    An optional company name []:
    Using configuration from /root/2.0/openssl-1.0.0.cnf
    Check that the request matches the signature
    Signature ok
    The Subject's Distinguished Name is as follows
    countryName           :PRINTABLE:'US'
    stateOrProvinceName   :PRINTABLE:'CA'
    localityName          :PRINTABLE:'San Francisco'
    organizationName      :PRINTABLE:'My company'
    commonName            :PRINTABLE:'vpn1.my-company.net'
    emailAddress          :IA5STRING:'ca@my-company.net'
    Certificate is to be certified until Jun 17 09:55:26 2024 GMT (3650 days)
    Sign the certificate? [y/n]:y
    
    
    1 out of 1 certificate requests certified, commit? [y/n]y
    Write out database with 1 new entries
    Data Base Updated
    

    Well - what has happened here? The script:

    • generated one certificate and one private key for the VPN server
    • generated a Certificate Sign Request (CSR) for the VPN server certificate
    • approved the CSR with the private key of the CA

    Now we have a VPN server certificate signed by the CA. Any VPN client can verify the server's certificate as valid by checking the signature against the public certificate of the CA.

    Next we need a Diffie-Hellman key for encrypted communication between VPN client and server:

    ./build-dh
    

    As before, the key and certificate is placed in the 'keys' directory, which should look like this by now:

    root@server:/etc/easy-rsa# ls -l keys/
    total 40
    -rw-r--r-- 1 root root 3943 Jun 20 11:55 01.pem
    -rw-r--r-- 1 root root 1253 Jun 20 11:23 ca.crt
    -rw------- 1 root root  916 Jun 20 11:23 ca.key
    -rw-r--r-- 1 root root  424 Jun 20 17:33 dh2048.pem
    -rw-r--r-- 1 root root  123 Jun 20 11:55 index.txt
    -rw-r--r-- 1 root root   21 Jun 20 11:55 index.txt.attr
    -rw-r--r-- 1 root root    0 Jun 20 11:22 index.txt.old
    -rw-r--r-- 1 root root    3 Jun 20 11:55 serial
    -rw-r--r-- 1 root root    3 Jun 20 11:22 serial.old
    -rw-r--r-- 1 root root 3943 Jun 20 11:55 vpn1.my-company.net.crt
    -rw-r--r-- 1 root root  696 Jun 20 11:55 vpn1.my-company.net.csr
    -rw------- 1 root root  916 Jun 20 11:55 vpn1.my-company.net.key
    
    • vpn1.my-company.net.crt - your signed VPN server certificate
    • vpn1.my-company.net.key - your secret VPN server key
    • vpn1.my-company.net.csr - the Certificate Sign Request - not needed anymore
    • dh2048.pem - Diffie Hellman key

    Transfer 'vpn1.my-company.net.key', 'vpn1.my-company.net.crt', 'ca.crt' and 'dh2048.pem' via a secure channel to the openVPN server.

    TIP: You can store the files in a new to create '/etc/openvpn/keys' directory, so you have everything handy in one place.

    IMPORTANT: Make sure your private keys are only readable for root. In addition you should make the 'keys' directory only accessible to the administrator.

    If you want to harden your VPN server setup a bit, add an additional security layer in form of a shared secret between VPN server and clients (you have to provide the 'ta.key' to all of your clients in order to connect them):

    openvpn --genkey --secret /etc/openvpn/keys/ta.key
    

    The key directory of your VPN server should now read like this:

    root@server:/etc/openvpn/keys# ls -l
    total 24
    -rw-r--r-- 1 root root 1679 Jun 27 12:01 ca.crt
    -rw-r--r-- 1 root root  424 Jun 27 12:01 dh2048.pem
    -rw------- 1 root root  636 Jun 27 12:10 ta.key
    -rw-r--r-- 1 root root 5408 Jun 27 12:01 vpn1.my-company.net.crt
    -rw------- 1 root root 1704 Jun 27 12:01 vpn1.my-company.net.key
    
    Generate client certificates

    Having the CA, we can issue the certificate and the key for a new openVPN Client. 'easy-rsa' has a script for this too, you just have to provide the filename as parameter. The generated key will be protected by password, which must be entered every time the client connects to the server:

    cd /etc/easy-rsa
    ./build-key-pass vpn_client1
    

    IMPORTANT: Again: make sure, the 'Common Name' is unique.

    TIP: If you want a client-key without password-protection, use instead 'build-key'

    The whole procedure

    root@server:/etc/easy-rsa# ./build-key-pass vpn_client1
    Generating a 2048 bit RSA private key
    ..............................................+++
    ....+++
    writing new private key to 'vpn_client1.key'
    Enter PEM pass phrase:
    Verifying - Enter PEM pass phrase:
     -----
     You are about to be asked to enter information that will be incorporated
     into your certificate request.
     What you are about to enter is what is called a Distinguished Name or a DN.
     There are quite a few fields but you can leave some blank
     For some fields there will be a default value,
     If you enter '.', the field will be left blank.
      -----
    Country Name (2 letter code) [US]:
    State or Province Name (full name) [CA]:
    Locality Name (eg, city) [San Francisco]:New York
    Organization Name (eg, company) [My Company]:    
    Organizational Unit Name (eg, section) []:roadwarriors
    Common Name (eg, your name or your server's hostname) [vpn_client1]:
    Name []:Joe Average
    Email Address [ca@my-company.net]:
    
    Please enter the following 'extra' attributes
    to be sent with your certificate request
    A challenge password []:
    An optional company name []:
    Using configuration from /etc/easy-rsa/openssl-1.0.0.cnf
    Check that the request matches the signature
    Signature ok
    The Subject's Distinguished Name is as follows
    countryName           :PRINTABLE:'US'
    stateOrProvinceName   :PRINTABLE:'CA'
    localityName          :PRINTABLE:'New York'
    organizationName      :PRINTABLE:'My Company'
    organizationalUnitName:PRINTABLE:'roadwarriors'
    commonName            :T61STRING:'vpn_client1'
    name                  :PRINTABLE:'Joe Average'
    emailAddress          :IA5STRING:'ca@my-company.net'
    Certificate is to be certified until Jun 24 10:13:19 2024 GMT (3650 days)
    Sign the certificate? [y/n]:y
    
    
    1 out of 1 certificate requests certified, commit? [y/n]y
    Write out database with 1 new entries
    Data Base Updated
    

    Well - what has happened here? The script:

    • generated one certificate and one private key for the new VPN client
    • generated a Certificate Sign Request (CSR) for the VPN client certificate
    • approved the CSR with the private key of the CA

    Now the client has a by the CA signed certificate and can be verified as valid by the VPN server.

    As before, the key and certificate are placed in the 'keys' directory, which should look like this by now:

    root@server:/etc/easy-rsa# ls -l keys/
    total 84
    -rw-r--r-- 1 root root 5408 Jun 27 11:57 01.pem
    -rw-r--r-- 1 root root 5352 Jun 27 12:13 02.pem
    -rw-r--r-- 1 root root 1679 Jun 27 11:48 ca.crt
    -rw------- 1 root root 1708 Jun 27 11:48 ca.key
    -rw-r--r-- 1 root root  424 Jun 27 11:59 dh2048.pem
    -rw-r--r-- 1 root root  266 Jun 27 12:13 index.txt
    -rw-r--r-- 1 root root   21 Jun 27 12:13 index.txt.attr
    -rw-r--r-- 1 root root   21 Jun 27 11:57 index.txt.attr.old
    -rw-r--r-- 1 root root  123 Jun 27 11:57 index.txt.old
    -rw-r--r-- 1 root root    3 Jun 27 12:13 serial
    -rw-r--r-- 1 root root    3 Jun 27 11:57 serial.old
    -rw-r--r-- 1 root root 5408 Jun 27 11:57 vpn1.my-company.net.crt
    -rw-r--r-- 1 root root 1050 Jun 27 11:56 vpn1.my-company.net.csr
    -rw------- 1 root root 1704 Jun 27 11:56 vpn1.my-company.net.key
    -rw-r--r-- 1 root root 5352 Jun 27 12:27 vpn_client1.crt
    -rw-r--r-- 1 root root 1090 Jun 27 12:27 vpn_client1.csr
    -rw------- 1 root root 1834 Jun 27 12:27 vpn_client1.key
    
    • vpn_client1.crt - your signed VPN server certificate
    • vpn_client1.key - your secret VPN server key
    • vpn_client1.csr - the Certificate Sign Request - not needed anymore

    TIP: You can check the content of your client certificate with 'head -20 vpn_client1.crt'. If you are not satisfied, delete 'vpn_client1.*' and start the creation again.

    Transfer 'ca.crt', 'vpn_client1.key' and 'vpn_client1.crt' to the client via a secure channel. For convenience save them in '/etc/openvpn/keys' directory. It should look like this (including the option 'ta.key' shared secret):

    root@client:/etc/openvpn/keys# ls -l
    total 20
    -rw-r--r-- 1 root root 1679 Jun 27 12:29 ca.crt
    -rw------- 1 root root  636 Jun 27 12:29 ta.key
    -rw-r--r-- 1 root root 5352 Jun 27 12:29 vpn_client1.crt
    -rw------- 1 root root 1834 Jun 27 12:29 vpn_client1.key
    

    IMPORTANT: Make sure your private keys are only readable by root. In addition you can make the 'keys' directory only accessible by the administrator.

    Setup VPN Server

    Ok, go back to your VPN Server and enter the configuration directory '/etc/openvpn'. It should now contain a secured 'keys' folder with the following content (mind the permissions...):

    root@server:/etc/openvpn/keys# ls -l
    total 24
    -rw-r--r-- 1 root root 1679 Jun 27 12:01 ca.crt
    -rw------- 1 root root  424 Jun 27 12:01 dh2048.pem
    -rw------- 1 root root  636 Jun 27 12:10 ta.key
    -rw-r--r-- 1 root root 5408 Jun 27 12:01 vpn1.my-company.net.crt
    -rw------- 1 root root 1704 Jun 27 12:01 vpn1.my-company.net.key
    

    TIP: We already have copied the necessary files here, if not - you find all of them in the key-directory of the CA.

    Next we create the configuration file for the VPN server. Let's call it '/etc/openvpn/server.conf' and put the following content in:

    #Switch to server mode - permit multiple clients
    mode server
    
    #The properties of the VPN network - make sure, it is 
    #an unused network on both sides, server and client!
    #Change according to your needs
    server 10.46.78.0 255.255.255.0
    
    #Again network properties
    #default is net30 because of compatibility issues
    #in older versions of windows - each client would get
    #an own subnet (/30). For *x OS and newer windows-clients
    #it is much more convenient to have a common subnet
    topology subnet
    #Try to avoid unnecessary disconnects for
    #idle clients.
    keepalive 10 60
    
    #which kind of device is used for the VPN
    #tun works at OSI Layer 3 ("routing-mode" and should be sufficient for most setups)
    #tap works at OSI Layer 2 ("bridging-mode") and is sometimes useful, if you need certain
    #features (e.g. broadcasting) of the Layer in your VPN
    dev tun
    
    #the certificate of the CA for authenticating clients
    ca keys/ca.crt
    
    #certificate (and private key) of the VPN server
    #needed to be authenticated by clients
    cert keys/vpn1.my-company.net.crt
    key keys/vpn1.my-company.net.key
    
    #Diffie-Hellman secret, necessary for encryption
    dh keys/dh2048.pem
    
    #optional security layer via a shared secret (only necessary if you created one)
    tls-auth keys/ta.key 0
    
    #if a 'soft-restart' (SIGUSR1) is performed, the tun-interface
    #is preserved while 'reload' (SIGHUP) shuts the tun-interface down
    #and opens a new one
    persist-tun
    
    #switch compression on 
    comp-lzo
    
    #own logfile for debug-reasons, comment out if everything is ok
    log  /var/log/openvpn.log
    #if you have problems, you can increase the verbosity
    #0 - no messages
    #1 - 4 normal usage range
    #verb 4
    
    • Start the server:
    • service openvpn start
    • Open a terminal and connect to the logfile:
    • tail -f /var/log/openvpn.log
    • Control:
    • There should be by now a new network-interface:

      Show network-configuration:

      ip a

      This is how it should look like:

      
      3: tun0:  mtu 1500 qdisc pfifo_fast state UNKNOWN qlen 100 link/none 
      inet 10.46.78.1/24 brd 10.46.78.255 scope global tun0
      
      

    Congratulations: Your server is up and running. Now have a cup of tea or if you are eager to connect your first client continue with the next chapter.

    Setup VPN Client

    Enter the configuration directory '/etc/openvpn' of your VPN client. It should now contain a secured 'keys' folder with the following content (mind the permissions...):

    root@client:/etc/openvpn/keys# ls -l
    total 20
    -rw-r--r-- 1 root root 1679 Jun 27 12:29 ca.crt
    -rw------- 1 root root  636 Jun 27 12:29 ta.key
    -rw-r--r-- 1 root root 5352 Jun 27 12:29 vpn_client1.crt
    -rw------- 1 root root 1834 Jun 27 12:29 vpn_client1.key
    <

    Create a configuration file '/etc/openvpn/my-company.conf' with the following content:

    #Sets two options: 
    #pull - try to get configuration (routes etc.) from server
    #tls-client
    client
    
    #must be the same (tun or tap) as
    #in the configuration of the server
    dev tun
    
    #IP of the server, you can provide more
    #than on 'remote' line in case of failover
    #configuration. Consider using an FQDN instead
    #of IPs 
    remote 192.168.122.120
    
    #Client's certificate and private key
    #needed do be authenticated by the server
    cert keys/vpn_client1.crt
    key keys/vpn_client1.key
    #Certificate of the CA, needed to authenticate the server
    ca keys/ca.crt
    
    #optional security layer via a shared secret (only necessary if you created one)
    tls-auth keys/ta.key 1
    
    #security(optional): requires a special server certificate (the one we created for our server
    #has this feature
    ns-cert-type server
    
    #security(optional): don't allow to cache passwords. Improves security but every time the connection
    #has to be reetablished (which can be a number of times during a vpn-session) the user 
    #must to provide the password for the certificate. We leave it disabled...
    #auth-nocache
    
    #choose an arbitrary free local port for connecting to the server
    #you can use 'port n' if you want to assign a fixed one.
    nobind
    
    #if a 'soft-restart' (SIGUSR1) is performed, the tun-interface
    #is preserved while 'reload' (SIGHUP) shuts the tun-interface down
    #and opens a new one
    persist-tun
    
    #switch compression on
    comp-lzo
    
    #own logfile for debug-reasons
    log  /var/log/openvpn.log
    
    #if you have problems, you can increase the verbosity
    #0 - no messages
    #1 - 4 normal usage range
    #verb 4
    
    • Start openVPN:
    • service openvpn start
      	

      You should be asked for the password of your private client key:

      [....] Starting virtual private network daemon: my-companyEnter Private Key Password:
      . ok 
      	
    • Open a terminal and connect to the logfile:
    • tail -f /var/log/openvpn.log
    • Control:
    • There should now show up a new network-interface:

      Show network-configuration:

      ip a

      This is how it should look like:

      
      4: tun0:  mtu 1500 qdisc pfifo_fast state UNKNOWN qlen 100 link/none 
      inet 10.46.78.2/24 brd 10.46.78.255 scope global tun0
      
      	

    Now Server (10.46.78.1) and Client (10.46.78.2) can communicate with each other in a secure manner. You can add more clients by issuing certificates+keys.

    Bibliography

    Some useful ressources: