April 7, 2016

Setting up OpenVPN

On this blog post I describe how I set up an OpenVPN server on my Raspberry Pi, which is running Arch Linux, and the Open VPN client on my laptop, which is running Kubuntu. If you use different systems, you can find more information on the OpenVPN how to section.


Public Key Infrastructure

OpenVPN uses public key infrastructure (PKI) to encrypt the data traveling inside the VPN tunnel and to verify the parties concerned with the data transmission. Understanding how PKI works will help one to understand the steps in the OpenVPN set up process. Therefore, I will briefly explain the idea behind PKI.

When you want to establish a secure connection, the first thing you need to do is verify that you are "talking" to the right "person". To do this, PKI uses digital certificates. They are used to confirm that the server you are connecting to is the real server and not an impostor. Similarly, they are used to confirm to the server that you are the person you claim to be (or in this case that my laptop really is my laptop). However, these certificates are not valid unless you have a reliable authority standing behind them. That is why one needs to create a certificate authority as a part of the OpenVPN configuration process. Only the certificates verified by your designated CA will be accepted.

So, when attempting an OpenVPN connection, the client and the server will both present their CA verified certificates. If noted valid, the source material for the secret keys is generated and exchanged over SSL/TLS connection (in TLS mode). Both parties use this material to create the keys, which they will use for encrypting and decrypting data.


Installation and initial set up

Okay, let's start working... OpenVPN installing commands:

For Arch Linux:    pacman -S openvpn

For Kubuntu:        apt-get install openvpn 

If you installed OpenVPN 2.3, or newer version, you will need to install easy-rsa separately. This is done by typing

git clone https://github.com/OpenVPN/easy-rsa.git

on both machines (on Arch I had to install git first). Then you have to cd to the right directory, which in my case is /etc/openvpn/easy-rsa/easyrsa3/. Next we will initialize the PKI for the server. Lets run the command

./easyrsa init-pki

on the server machine. Then we need to create the CA using the following command:

./easyrsa build-ca

Now, as I am running these commands on my Pi, it has become the certificate authority that will have to sign all the other certificates. Next, I typed

./easyrsa gen-req OpenVPNServer

to create a request for the CA to create a certificate for the server (I named it OpenVPNServer). In my case Raspberry Pi is the CA, and it will also run the OpenVPN server. Next I typed:

./easyrsa import-req /etc/openvpn/easyrsa3/openvpnServer.req OpenVPNServer

to import the request for signing. The signing will be done with the command:

./easyrsa sign-req server OpenVPNServer

Now we have the server certificate ready. Then we need to create the Diffie-Hellman parameters for the server. Let's run:

./easyrsa gen-dh

This process took about 30 minutes to run on my Pi. Diffie-Hellman is an algorithm that can be used to share a "password" between two parties over public communication line so that even if a third party sees every message in plain text, he cannot deduce the password. OpenVPN will need DH parameters when the encryption and decryption key source material is exchanged.

Now we have the CA and the server certificates ready, plus DH parameters set up. All of this was done on my Raspberry Pi, and the initial setup is now completed. Next we need to set up the PKI on the client, and create a request for the client certificate. Let's run command

./easyrsa init-pki

on the client machine. The PKI has to be initialized for all new machines that will be connected to the VPN. Next we will create the request for the certificate:

./easyrsa gen-req ComputerName

Now we need to transfer this request-file to the CA, which in my case means the Raspberry Pi. I did this using the netcat method described below. Then, on the CA, I imported the request using command (check that the file path is correct for you):

./easyrsa import-req ~/ComputerName.req

Next, let's sign the client certificate:

./easyrsa sign-req client ComputerName

Then, we will use the netcat method in reverse to send the certificate back to the client. Plus, we need to send the ca.crt file to the client too. I also used rm to remove the redundant .req files from both of the devices.


Configuration

You can find example configuration-files from /usr/share/openvpn/examples/. Copy the one you need (ie. server.conf or client.conf) to your preferred location. I used /etc/openvpn/. Btw, you can also find the same sample configuration files on the OpenVPN webpage.

We will first configure the server, and then adjust the client accordingly. Generally, the sample configuration files provide good explanations for the settings. However, they don't tell you all. Here are my notes.

  •  In case you wondered, ";" and "#" both mark the beginning of a comment on the configuration file.
  • TCP or UDP?
    • TCP is more reliable, but it can be a little slower. TCP will always make sure the data packet (or multiple packets, depending on the configuration) has arrived to the receiver. Only after confirmation, it will send the next packet. Whereas UDP will just send one packet after another, without confirming if they have arrived. So UDP can be faster, if the connection is reliable. However, if packets are lost, they are lost forever. There will be no retransmission. Whereas with TCP the connection problem will be noticed very quickly, and the lost packets are resent.
  • Change the file paths of ca.crt, server.crt, dh.pem and server.key files to match the actual paths.
  • I also modified the "push dhcp-options DNS X.X.X.X" settings to match those provided by my ISP (you can check the IP of your DNS by logging into your routers management webpage and checking the status tab). 
  • Modify the push redirect-gateway option to "redirect-gateway def1"
    • This will direct your traffic through the VPN

Then the following commands need to be executed in order to add the correct rules to your iptables on your server:

iptables -I INPUT 1 -p udp --dport 1194 -j ACCEPT

iptables -I FORWARD 1 --source 10.8.0.0/24 -j ACCEPT


iptables -I FORWARD -i br0 -o tun2 -j ACCEPT


iptables -I FORWARD -i tun2 -o br0 -j ACCEPT


iptables -t nat -A POSTROUTING -s 10.8.0.0/24 -j MASQUERADE

Note that these iptables rules are not permanent, but will be reset on reboot. The best way I found to overcome this problem is to first store the configuration in a file

iptables-save > /etc/iptables.conf

Next time when you log in, you can load them from the file using

iptables-restore < /etc/iptables.conf

I had some trouble making this automatic, but was finally able to do it with some help from a friend. First create a script file, eg. iptablesconf.sh, that does the above for you. You will need to insert just this into the script:

"!/bin/bash

iptables-restore < /etc/iptables.conf

Then change the owner and the group of the script

chown root:wheeler iptablesconf.sh

Next you have to edit the /etc/sudoers file. Uncomment the "%wheel ALL=(ALL) NOPASSWD: ALL" line. Now the script has the root privileges it needs to execute iptables commands and it can be run successfully at startup. You just need to add the line

bash /home/cornucopia/iptablesconf.sh

to /etc/bash.bashrc file and the script will be run. Other operating systems have different names for these files so you need to find the right one for your OS.

One more thing, you need to modify net.ipv4.ip_forward using

sysctl -w net.ipv4.ip_forward=1

On Arch Linux you can make this change permanent by adding the line

net.ipv4.ip_forward = 1

into /etc/sysctl.d/99-sysctl.conf. These options allow the data to flow through the VPN. It took a while for me to get this right. First my problem was that I was able connect to the VPN, but my traffic was not routed through it. Once I fixed this, the problem was that I was able to connect to my home network, but not to the Internet. Finally I was able to fix this, too, with the these instructions.

On the client side, you will have to change the settings to match those on the server. The client.conf contains fewer lines, and is much faster to configure. Furthermore, none of the iptables or forwarding settings need to be done there. Just remember to change the file paths to match the real locations of the files (ca.crt, client.crt and client.key).

If there are any problems, they will be stated on the command line when you try to run the program. You can create an OpenVPN session by first typing

openvpn server.conf

on the server. This will open the server and make it wait for a connection. Then type

openvpn client.conf

on the client side to establish a connection from your computer to the server.

Notice that in case you want to connect to the VPN from outside of your LAN, you need to implement some port forwarding on your router.


Netcat commands

You can use Netcat to easily transfer text-files over your LAN using two simple commands. On the receiving end type:

nc -l -p <port> -q 1 -v > text.file

This command makes netcat listen for an input, and then stores it in a text.file (the file is created during the process). The -q 1 flag tells the program to wait one second after receiving input and then terminate the connection. The -v flag tells netcat to be verbose, so you will be able to see some information about the connection.

On the sending side the command to use is:

cat text.file | nc <receivers IP-address> <port>

This command reads the text.file and then sends the output to the other device.


References

Some of the sources I used provide additional information, so I will list them here.

https://forums.openvpn.net/topic12708.html
http://www.ducea.com/2006/08/01/how-to-enable-ip-forwarding-in-linux/
https://wiki.archlinux.org/index.php/sysctl

No comments :

Post a Comment