Setting up OpenVPN 2.4 with EasyRSA 3

Setting up OpenVPN 2.4 with EasyRSA 3

Mad Cat

9 minute read

Cat with suspicious eyes

Nowadays spies are everywhere, governments, ISP, marketing campaigns… they want to make a profit and take advantage of uninformed Internet users. If you want to keep this cat-mouse game of privacy, one of the more basic things you must do is setting up a VPN service for connecting to the Internet.

When done all the traffic originated in your devices will be routed through the server, with the additional advantage of having a private lan between all your devices, or for example you will be able to connect securely to open wifi networks without worries of your data being intercepted.

This tutorial uses EasyRSA 3 and OpenVPN 2.4.2 for providing the VPN service and generating the different certificates used by OpenVPN.

Anyway you must always remember that even though using free software is supposed to be more secure, you might still be eavesdropped. After all OpenVPN generally uses OpenSSL and software always has bugs…

Remember as well to setup the service in a private server. You can use any Linux distribution for setting up the service. Clients can run any other operating system dough, even Android or Windows, if you trust them…

Enough talking, let’s get our paws dirty.

Step 0. Setting up our CA

Use your package management software to install EasyRSA and OpenVPN, search the path for the EasyRSA files, in my distro it’s /usr/share/easy-rsa, once installed copy the easy-rsa with the scripts to whatever folder you want, here we use /root to simplify things. Remember to keep all the generated files in a safe place.

$ cp -Rp /usr/share/easy-rsa /root/easy-rsa-3
$ cd /root/easy-rsa-3

If you want you can edit vars.example and make some changes that are supposed to improve the security and the compatibility of our setup:

set_var EASYRSA_KEY_SIZE        4096
set_var EASYRSA_CRL_DAYS        3650
set_var EASYRSA_DIGEST          "sha512"

After editing the file, rename it:

$ mv vars.example vars

Now run the following command:

$ ./easyrsa init-pki

Here we can use a password or not, depending on the nopass optional parameter:

$ ./easyrsa build-ca [nopass]

This generates all the files we need to manage our CA. The following files are produced by the previous steps and are specially relevant:

  1. /root/easy-rsa-3/pki
  2. /root/easy-rsa-3/pki/ca.crt
  3. /root/easy-rsa-3/pki/private/ca.key

Step 1. Creating a server certificate

Now that our CA is ready, let’s create a certificate for our server. The only parameter we need here is the CN and it will be asked during the process, you can use your server hostname or whatever you want:

First we make a request:

$ ./easyrsa gen-req EntityName [nopass]

Then we sign our own request:

$ ./easyrsa sign-req server EntityName

You can run the request step in any other computer and transfer the files to the computer with our CA files as well, but this requires and extra import step.

Like in the previous step some files are generated, take note of the following files, let’s say we used “server.lan” for our EntityName:

  1. /root/easy-rsa-3/pki/private/server.lan.key
  2. /root/easy-rsa-3/pki/reqs/server.lan.req
  3. /root/easy-rsa-3/pki/issued/server.lan.crt

Step 2. Defining clients, obtaining certificates

This step it’s like step 1. but in this case the certificate is for our client, suppose that our client is called “client1”, this would be the steps for generating the certificate (Substitute client1 with your desired name):

First we make a request:

$ ./easyrsa gen-req client1 nopass

Then we sign our own request:

$ ./easyrsa sign-req client client1

What we said about using another computer is still valid here.

Some of the generated files are:

  1. /root/easy-rsa-3/pki/private/client1.key
  2. /root/easy-rsa-3/pki/reqs/client1.req
  3. /root/easy-rsa-3/pki/issued/client1.crt

Note that this step should be repeated for each client for increased security. The idea is to have a different certificate for each client.

Step 3. Creating and empty list of revoked certs

We just created our CA and for the moment maybe all our certs are safe, but in the future this can change, for example in case one of our devices gets stolen. For dealing with this situations we create an empty certificate revocation list.

$ ./easyrsa gen-crl

The list can be found in the following path:

  1. /root/easy-rsa-3/pki/crl.pem

Step 4. Generating DH params

Now it’s time to generate our Diffie-Hellman parameters. This step can take a lot of time depending on the chosen length and the available entropy on the machine, so take heed, go for a coffee.

$ mkdir /etc/openvpn/ssl -p
$ openssl dhparam -out /etc/openvpn/ssl/dh.pem 4096

Step 5. Generating ta.key

Wouldn’t it be nice if we can discard any packet sent to our service that wasn’t originated by us? Well there is a mechanism called HMAC that allows us to sign our packets, and you guessed it, any non-signed packet will be discarded.

Run the following commands:

$ cd /etc/openvpn/ssl
$ openvpn --genkey --secret ta.key

Step 6. Configuring OpenVPN server side

First of all, we are going to copy the required files to the proper function of the server:

$ cp /root/easy-rsa-3/pki/ca.crt /etc/openvpn/ssl/
$ cp /root/easy-rsa-3/pki/issued/server.lan.crt /etc/openvpn/ssl/
$ cp /root/easy-rsa-3/pki/private/server.lan.key /etc/openvpn/ssl/
$ cp /root/easy-rsa-3/pki/crl.pem /etc/openvpn/ssl/

In the case of my distro the configuration file is /etc/openvpn/server.conf, and it contains the following directives:

client-to-client
persist-key
persist-tun
ca /etc/openvpn/ssl/ca.crt
cert /etc/openvpn/ssl/server.lan.crt
comp-lzo adaptive
dev tun
dh /etc/openvpn/ssl/dh.pem
ifconfig-pool-persist server-ipp.txt 0
keepalive 10 120
key /etc/openvpn/ssl/server.lan.key
tls-auth /etc/openvpn/ssl/ta.key 0
cipher AES-256-CBC
auth SHA512
tls-version-min 1.2
tls-cipher TLS-DHE-RSA-WITH-AES-256-GCM-SHA384
log /var/log/openvpn/server.log
port 1194
proto udp
server 192.168.10.0 255.255.255.0
verb 3
crl-verify /etc/openvpn/ssl/crl.pem
push "route 192.168.1.0 255.255.255.0"
push "redirect-gateway def1"
push "dhcp-option DNS 192.168.1.1"

My private server is also acting as a router for the lan that’s why I’m pushing routes from the config and forcing the clients to use 192.168.1.1 as DNS. Probably you can remove those lines if you are only using a remote server that is not acting as your lan router. When you connect with your clients one IP of the net 192.168.10.0 will be assigned to your client. Here we are using UDP to transfer the VPN data, remember to open the port 1194 or whatever port you choose in your firewall. The client-to-client directive allows us to communicate with other clients connected to the VPN.

For opening the port run:

$ iptables -A INPUT -p udp --dport 1194 -i ${WAN} -j ACCEPT

We are using the VPN in TUN mode, if you need to transfer broadcast packets to the clients (or you prefer to assign IPs from the same range as your LAN) you must use TAP mode instead.

Apart from opening the 1194 port, you must also run the following commands to route the packets from our clients:

$ iptables -t nat -A POSTROUTING -s 192.168.10.0/24 -o eth0 -j MASQUERADE

If you trust all your clients you can also run:

$ iptables -A INPUT -i tun+ -j ACCEPT
$ iptables -A FORWARD -i tun+ -j ACCEPT

Remember to save your iptables rules after making these changes, and start the service. You can check the log at /var/log/openvpn/server.log in case of any problem.

Step 7. Configuring OpenVPN client side

Now it’s the turn for the client config. For example for our client1 the client config would be something like this:

client
dev tun
proto udp
port 1194
remote yourremoteserver.com 1194 udp
remote-cert-tls server
resolv-retry infinite
nobind
persist-key
persist-tun
comp-lzo
verb 3
cipher AES-256-CBC
auth SHA512
tls-version-min 1.2
tls-cipher TLS-DHE-RSA-WITH-AES-256-GCM-SHA384
<ca>
//replace this with your ca.crt file content
</ca>
<cert>
//replace this with your client1.crt file content
</cert>
<key>
-----BEGIN CERTIFICATE-----
//replace this with your client1.key file content
-----END CERTIFICATE-----
</key>
key-direction 1
<tls-auth>
//replace this with your ta.key file content
</tls-auth>

You must replace when indicated with your generated values. I understand that this can be quite painful specially if you are working from the terminal line, hence I created a couple of scripts for generating the client config with a simple command. If you have git installed you can clone the repo containing these scripts by issuing the following command (or alternatively you can copy paste them if you prefer):

$ git clone https://github.com/sys-dev-cat/openvpn-easyrsa-helpers.git

Generating a client config

The following script allows anyone to add a new client to the OpenVPN service in an easy manner and automatically generates an appropriate ovpn file. Remember to configure the variables at the beginning of the script, the generated file will be stored in /root/openvpn/clients per default:

#!/bin/bash

#
# You must configure this variables before using the script!!!
#

EASYRSA_PATH="/root/easy-rsa-3"
OPENVPNCLIENT_PATH="/root/openvpn/clients"
OPENVPN_PORT="1194"
OPENVPN_REMOTE="www.google.com"
TA_KEY_PATH="/root/openvpn/ta.key"

###########################################################################
# Don't modify anything down this block
##########################################################################

abort() {
        echo $1;
        exit 1;
}

username=$1

addtofile() {
        mkdir -p "$OPENVPNCLIENT_PATH/.tmp"
        echo $1 >> "$OPENVPNCLIENT_PATH/.tmp/${username}.ovpn"
}

## Init process
if [ -z "$username" ]
then
        abort "You must provide the name for the client"
fi

cd $EASYRSA_PATH
if [ -s ./easyrsa ]
then
        echo "Generating key for user ${username}"
        ./easyrsa gen-req $1 nopass
        ./easyrsa sign-req client $1
        echo "Done"
else
        abort "easyrsa script not found in path"
fi

echo "Preparing .ovpn file..."
addtofile "client"
addtofile "dev tun"
addtofile "proto udp"
addtofile "port $OPENVPN_PORT"
addtofile "remote $OPENVPN_REMOTE $OPENVPN_PORT udp"
addtofile "remote-cert-tls server"
addtofile "resolv-retry infinite"
addtofile "nobind"
addtofile "persist-key"
addtofile "persist-tun"
addtofile "comp-lzo"
addtofile "verb 3"


# Ensure we can connect securely to the server
echo "Adding security parameters to client configuration file"
addtofile "cipher AES-256-CBC"
addtofile "auth SHA512"
addtofile "tls-version-min 1.2"
addtofile "tls-cipher TLS-DHE-RSA-WITH-AES-256-GCM-SHA384"

# Adding ca certificate to ovpn client configuration file
echo "Adding ca certificate to ovpn client configuration file"
addtofile "<ca>" >> "$OPENVPNCLIENT_PATH"/.tmp/${username}.ovpn
cat "$EASYRSA_PATH"/pki/ca.crt | grep -A 100 "BEGIN CERTIFICATE" | grep -B 100 "END CERTIFICATE" >> "$OPENVPNCLIENT_PATH"/.tmp/${username}.ovpn
addtofile "</ca>"
echo "Done"

# Adding user certificate to ovpn client configuration file
echo "Adding user certificate to ovpn client configuration file"
addtofile "<cert>"
cat "$EASYRSA_PATH"/pki/issued/${username}.crt | grep -A 100 "BEGIN CERTIFICATE" | grep -B 100 "END CERTIFICATE" >> "$OPENVPNCLIENT_PATH"/.tmp/${username}.ovpn
addtofile "</cert>"
echo "Done"

# Adding user key to ovpn client configuration file
echo "Adding user key to ovpn client configuration file"
addtofile "<key>"
cat "$EASYRSA_PATH"/pki/private/${username}.key | grep -A 100 "BEGIN PRIVATE KEY" | grep -B 100 "END PRIVATE KEY" >> "$OPENVPNCLIENT_PATH"/.tmp/${username}.ovpn
addtofile "</key>"

# Adding ta file to ovpn client configuration file
echo "Adding tls-auth to ovpn client configuration file"
addtofile "key-direction 1"
addtofile "<tls-auth>"
cat "$TA_KEY_PATH" | grep -A 100 "BEGIN OpenVPN Static key V1" | grep -B 100 "END OpenVPN Static key V1" >> "$OPENVPNCLIENT_PATH"/.tmp/${username}.ovpn
addtofile "</tls-auth>"

mkdir -p "$OPENVPNCLIENT_PATH"/${username}
mv "$OPENVPNCLIENT_PATH"/.tmp/${username}.ovpn "$OPENVPNCLIENT_PATH"/${username}/${username}.ovpn
cd "$OPENVPNCLIENT_PATH"; tar -jcf ${username}.tar.bz2 ${username}/
echo "Done"

echo "
=========================================================================================

            Configurations are located in $OPENVPNCLIENT_PATH/${username}

    ---------------------------------------------------------------------------------
                       Download friendly version with:

            'scp root@`hostname -f`:$OPENVPNCLIENT_PATH/${username}.tar.bz2 .'

=========================================================================================
"

exit 0

Denying access to a client

If you want to revoke the access to one of your clients you have to run the following commands, the updated crl will be in /root/easy-rsa-3/pki/crl.pem, remember to copy it to whatever path you configured in openvpn server config and restart the openvpn service after copying it.

$ ./easyrsa revoke client1
$ ./easyrsa gen-crl
$ cp /root/easy-rsa-3/pki/crl.pem /etc/openvpn/ssl/

Again here is a script to make this task easier:

#!/bin/bash

## Remember to adjust these variables before running the script!!!

EASYRSA_PATH="/root/easy-rsa-3"
OPENVPNSSL_PATH="/root/openvpn"

#############################################################
## Don't modify anything starting here
#############################################################

username=$1

if [ -z "$username" ]
then
        echo "You must provide the name for the client"
        exit 1
fi

if [ -s ./easyrsa ]
then
        echo "Revoking cert for user ${username}"
        ./easyrsa revoke "$username"
        ./easyrsa gen-crl
        cp "$EASYRSA_PATH"/pki/crl.pem "$OPENVPNSSL_PATH"/crl.pem
        echo "Done"
else
        abort "easyrsa script not found in path"
fi

Enjoy your new VPN service!.

comments powered by Disqus