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:
- setup of 'LinOTP'
- setup of 'RADIUS' and connecting it to 'LinOTP' please refer to: http://linotp.org/howtos/howto-radius.html
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:
- an openVPN server (if not go to section Install VPN Server)
- LinOTP
- a RADIUS server connected to your LinOTP instance: http://linotp.org/howtos/howto-radius.html
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.
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
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.
- Install the necessary package (at your VPN server):
apt-get install libpam-radius-auth
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
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.
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.
- The python-based PAM plugin requires the package 'libpam-python':
apt-get install libpam-python python
- 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
tar -C /tmp -xzf /tmp/pam_py_linotp-2.7.tar.gz
cp /tmp/pam_py_linotp-2.7/src/pam_linotp.py /lib/security/
- provide requirements:
apt-get install python-pip
pip install pam_py_linotp
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.
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
- If not yet done, add the linotp-Repository to your openVPN server.
echo 'deb http://dist.linotp.org/debian/linotp2 wheezy linotp' > /etc/apt/sources.list.d/linotp.list
apt-key adv --keyserver eu.pool.sks-keyservers.net --recv-keys 913DFF12F86258E5
apt-get update apt-get install libpam-linotp
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.
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
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 failedin 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
tail -f /var/log/openvpn.log
There should be by now a new network-interface:
Show network-configuration:
ip a
This is how it should look like:
3: tun0: <POINTOPOINT,MULTICAST,NOARP,UP,LOWER_UP> 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
tail -f /var/log/openvpn.log
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:
- easy rsa documentation: https://openvpn.net/index.php/open-source/documentation/howto.html
- official openVPN documentation: https://openvpn.net/index.php/open-source/documentation/howto.html
- OpenVPN Wiki Archlinux: https://wiki.archlinux.org/index.php/OpenVPN
- OpenVPN Wiki Debian: https://wiki.debian.org/OpenVPN
- PAM documentation: http://www.linux-pam.org/Linux-PAM-html/Linux-PAM_SAG.html
- Wikipedia RADIUS: http://en.wikipedia.org/wiki/RADIUS
- Wikipedia OneTimePassword: http://en.wikipedia.org/wiki/One-time_password