Virtual Private Network (opens new window) (VPN) is a required solution in our current interconnected world to protect our own privacy and to interconnect different network through internet. Lot of commercial solutions exists around the world to deploy any kind of VPN, but, can we trust big corportation? In this series, I will show you how to deploy rapidly multiple VPN software on my two favorites operating systems: OpenBSD (opens new window) and FreeBSD (opens new window).

Before starting, for newbies and new comers in marvelous VPN world, what is a VPN? A VPN is a link between one or many nodes on an pre-existing network. This link (you can call it a tunnel) between each nodes is authenticated and encrypted. This tunnel create a new network where all your communications are “secure” (the flow can’t be read by anyone except the two end-point).

In this article, I will present to you OpenVPN (opens new window), probably one of the most known and used VPN around the world. This tool comes from Open-Source, is easy to use, easy to configure, easy to deploy and easy to hide too. I will show you how to configure it and create your own personal VPN network in different level of complexity. The first level, in this article, is straight forward, a simple VPN authenticated only with certificate. Here a map to show you an example of the final distributed OpenVPN project.

External client connected with OpenVPN, servers interconnectedwith tinc External client connected with OpenVPN, servers interconnected with tinc

# Server Configuration on OpenBSD

Before starting and doing anything, our server need some custom configuration. Firstly, this server will now act as router, need to route network packets from different interfaces and different networks, in ipv4 but also in ipv6 (in a future article). net.inet.ip.forwarding kernel state is really important. If this one is not set to 1 (enabled), all packets from others interfaces or others networks will be not forwarded, and simply discarded. During all this tutorial, if you have some problem to ping or reach a specific ports, ensure this state is well configured.

\# enable ipv4 forwarding  
sysctl net.inet.ip.forwarding=1

\# enable it at boot  
echo "net.inet.ip.forwarding=1" >> /etc/sysctl.conf

\# ensure this flag is enable (should print 1)  
sysctl net.inet.ip.forwarding

Secondly, we can play with some TCP and UDP states in the OpenBSD network stack, increasing buffer space for our UDP/TCP packets.

cat >> /etc/sysctl.conf << EOF  
net.inet.udp.recvspace=262144  
net.inet.udp.sendspace=262144  
net.inet.tcp.recvspace=262144  
net.inet.tcp.sendspace=262144  
EOF

After this little introduction, we can now install what we need: OpenVPN and Easy-RSA on our 2 OpenBSD servers. In this case, you can install them in multiple way:

  • Using official packages from OpenBSD repository with [pkg_add](https://man.openbsd.org/pkg_add) ;

  • Building [openvpn](http://openports.se/net/openvpn) and [easy-rsa](http://openports.se/security/easy-rsa) ports ;

  • Using dpb (opens new window) (and create your own repository at the same time).

During this tutorial, I will try to use only official packages, freely available, and doing all we need.

\# ensure openvpn and easy-rsa are present in the repository  
pkg\_info -Q openvpn  
pkg\_info -Q easy-rsa

\# exist? we can install it!  
pkg\_add openvpn easy-rsa

openvpn package let you initialize your own openvpn directory, by default, I will create it under /etc/openvpn on OpenBSD. This directory will contain all our OpenVPN configuration, but, also all managed certificates and keys for our servers/clients.

\# create a directory dedicated to openvpn  
mkdir /etc/openvpn  
chmod 0700 /etc/openvpn  
cd /etc/openvpn

Public Key Infrastructure (opens new window) (PKI) is a technic to store and manage (create, sign, remove or revoke) private, public keys and certificates. easyrsa can generate this easily with the help of init-pkisubcommand. If you want to create your own manually, you can find lot of tutorial on the web.

\# initialize a public key infrastructure, in our case, it will  
\# just create a directory named 'pki' with some files in it  
\# to manage ssl/tls keys  
cd /etc/openvpn  
/usr/local/share/easy-rsa/easyrsa init-pki

OpenVPN, using PKI, require a Certificate Authority (opens new window) (CA) to works as expected. A CA is used to trust other managed certificate. This certificate will sign all our generated server or client certificates, ensuring there are correctly managed by our PKI. This file can be generated with easyrsa and build-ca subcommand.

\# create a new certificate authority  
/usr/local/share/easy-rsa/easyrsa build-ca

OpenVPN gives you the ability to use many different algorithms and methods to add security to your connection. Diffie-Hellman (opens new window) (DH) seed, is used to exchange keys between two entities (in our case, server and client). This file can also be generated by easyrsawith gen-dh subcommand.

/usr/local/share/easy-rsa/easyrsa gen-dh

We have a PKI, a CA, a DH, but we still don’t have our own certificate for our OpenVPN server. This certificate will be used only for our server. Again, easyrsa can create this file with build-server-full subcommand.

/usr/local/share/easy-rsa/easyrsa build-server-full server

At this step, you have all information required to start your own server, if you try it now, you will be prompted for a password. This password protect your server key. Sometime, its pretty useful to have a protection on this kind of file, but, in other side, each time your service will be restarted (even at boot), a password will be required. This security can be removed by using openssl and [rsa](https://man.openbsd.org/openssl#RSA) subcommand.

openssl rsa -in pki/private/server.key \\  
            -out pki/private/server-wop.key

We have a server certificate, we need at least one client certificate for testing if our OpenVPN is working as expected and test our network.

\# we will also generate our client certificate  
/usr/local/share/easy-rsa/easyrsa build-client-full client

OpenVPN support TLS auth key. This file will be shared with all client and ensure another layer of security based on a shared secret.

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

OpenVPN can be used in many ways. We can manually start it with a long argument list like any command, or just create configuration file containing our those arguments. The last one seems easier to understand and modify. This configuration will be stored in /etc/openvpn/server.conf.

\# we can now create our configuration file  
touch /etc/openvpn/server.conf  
cat > /etc/openvpn/server.conf < EOF  
local ${YOUR\_IP\_ADDRESS}  
port 1194  
proto udp  
dev tun  
ca /etc/openvpn/pki/ca.crt  
cert /etc/openvpn/pki/issued/server.crt  
key /etc/openvpn/pki/private/server.wop.key  
dh /etc/openvpn/pki/dh.pem  
server 10.0.1.0 255.255.255.0  
; push "route 10.0.2.0 255.255.255.0 10.0.1.1"  
ifconfig-pool-persist ipp.txt  
client-to-client  
keepalive 10 120  
tls-auth /etc/openvpn/ta.key 0  
cipher AES-256-CBC  
max-clients 100  
user \_openvpn  
group \_openvpn  
persist-key  
persist-tun  
topology subnet  
status openvpn-status.log  
verb 3  
explicit-exit-notify 1  
EOF

For this example, I commented the push route directive. If you have multiple connected network to your server, enabling that could be a nice idea. OpenVPN server will share these routes to OpenVPN client, and your client will be able to talk to other network easily.

OpenBSD use rcctl command to manage internal services. This command will automatically edit for you /etc/rc.conf.local with your options.

\# enable openvpn  
rcctl set openvpn flags "--config /etc/openvpn/server.conf"

Our OpenBSD service is now active, we can start it manually.

\# start our service  
rcctl start openvpn

Our OpenVPN service should run now. We can check it by using rcctl again

rcctl check openvpn

If your server doesn’t run… You can start to debug it in standalone mode and try to understand what’s going on!

openvpn --config /etc/openvpn/server.conf

Don’t forget to use other command like ifconfig or netstat to investigate and see if you don’t have made a mistake in your server configuration.

\# check network interface  
ifconfig -a

\# check listening ipv4 sockets  
netstat -nla -finet

\# check listening ipv4/udp sockets  
netstat -nla -finet -pudp

\# check routing table  
netstat -rn

I always enable OpenBSD Packet Filter (opens new window) firewall at startup, we will add some rules to

  • Allow our OpenVPN to listen on UDP/1194 port

  • Allow all traffic flow in our VPN network

  • NAT our traffic to the outside world

\# configure packet filter  
cat > /etc/pf.conf << EOF  
external="myinterface"  
vpn\_network="10.0.1.0/24"

\# don't apply our rules on lo\* interfaces  
set skip on lo

\# don't apply our rules on tun\* interfaces  
set skip on tun

\# create a NAT rules, all packet from VPN network  
\# will be translated to the external interface IP address  
match out inet from $vpn\_network \\  
               to any nat-to ($external) static-port source-hash

\# OpenVPN listen on port 1194, we allow it  
pass in quick proto udp from any to port 1194  
EOF

Our packet filter configuration was modified, but, can be sure about our syntax? The good way before reload our firewall configuration is to test it.

\# check packet filter configuration  
pfctl -nf /etc/pf.conf

If our firewall configuration is okay… We can now start packet filter with the new configuration.

\# start packet filter  
pfctl -ef /etc/pf.conf

We have a working OpenVPN service, listening on UDP/1194 port, a working PKI, you can now generate all your server or client certificates based on previous commands and we have a working firewall configuration. Now, the client configuration…

# Client Configuration on FreeBSD

This part will show you how to configure a simple OpenVPN client with certificate authentication only. In this article, I will not show you how to connect it to another kind of authentication (e.g. LDAP or PAM).

Installing and configuring OpenVPN as client is straight forward. The first thing to do, is to install OpenVPN, you can do it, like OpenBSD, in different ways:

\# install openvpn package  
pkg install openvpn

On FreeBSD, OpenVPN package doesn’t create any kind of users or groups, you need to create them manually. To make things easier, you can create them with the same uid/gid present on OpenBSD (577). Just to be clear, _openvpn user and group, starting with an underscore, will not work on some systems (underscore is not allowed in names).

\# create default openvpn user and group  
pw group add \_openvpn -g 577   
pw user add \_openvpn -u 577 -s /sbin/nologin 

Like our server configuration, we need to create our directory, this one will contain OpenVPN client configuration.

\# create our configuration directory  
mkdir -p /usr/local/etc/openvpn/pki  
cd /usr/local/etc/openvpn

OpenVPN can act as server or client only by enable a switch, the configuration file is practically the same than the server configuration.

\# create our configuration file  
touch /usr/local/etc/openvpn/client.conf  
cat > /usr/local/etc/openvpn/client.conf << EOF  
client  
dev tun  
proto udp  
remote ${YOUR\_IP\_ADDRESS}  
resolv-retry infinite  
nobind  
user \_openvpn  
group \_openvpn  
persist-key  
persist-tun  
ca /usr/local/etc/openvpn/pki/ca.crt  
cert /usr/local/etc/openvpn/pki/issued/client.crt  
key /usr/local/etc/openvpn/pki/private/client.wop.key  
remote  
tls-auth /usr/local/etc/openvpn/ta.key 1  
cipher AES-256-CBC  
verb 3  
EOF

Our configuration is ready but we need to copy our certificates and our keys from our server. This is not the good way, in practice, our client will give us a Certificate Signing Request (opens new window) (CSR), we will sign it with our Certificate Authority and give it the requested certificate (CRT).

\# on our server, create a tarball containing our test certificate  
cd /etc/openvpn  
tar czvf ~/client-cert.tar.gz ta.key \\  
                              pki/ca.crt \\  
                              pki/issued/client.crt \\  
                              pki/private/client.key \\  
                              pki/reqs/client.req

If you want to create your OpenVPN tunnel at startup, you need to configure our service in /etc/rc.conf, [sysrc](http://www.freebsd.org/cgi/man.cgi?query=sysrc) gives your the ability to do that easily.

\# enable openvpn service   
sysrc openvpn\_enable="YES"  
sysrc openvpn\_if="tun"  
sysrc openvpn\_configfile="/usr/local/etc/openvpn/client.conf"

Everything seems good! It’s the time to start our OpenVPN client service and watch if all is working as expected!

\# we can now start openvpn  
service openvpn start

If you don’t want to tip your password key every time when are starting your server or your client configuration, you can remove this protection with openssl command.

\# on server side  
cd /etc/openvpn/pki/keys  
openssl rsa -in server.key -out server.wop.key

\# on client side  
cd /usr/local/etc/openvpn/pki/keys  
openssl rsa -in client.key -out client.wop.key

You can now create numbers of new client and connects them to your fresh OpenVPN server. Its a good start for our infrastructure!

# Monitoring tunnel

I think a best practice is to monitor and automatize everything just after all is working. You can monitor your tunnel in multiple way, personally, I like [monit](https://mmonit.com/monit/), a small and open-source monitoring tool. Here 2 small examples to ensure our tunnel is up and running:

\# we check if the process openvpn is running  
check process openvpn matching "/usr/local/sbin/openvpn"

\# we check if our network is reachable  
check network openvpn-local address 10.0.1.1

If our OpenVPN crash, or, for some reason, we can’t reach our listening address, monit will send you an alert (mail by default).

# Monitoring connected client

Our VPN is now up and running! You have created lot of certificate, and all your hardware is connected to your new beautiful server! But… How to supervise your client on server side?

OpenVPN create a status file in /var/log/openvpn/openvpn-status.log containing all information about connected client by adding status openvpn-status.log parameter in its configuration file.

If you want to do more, you can also enable management interface (opens new window) by adding management ${hostname} ${port} in your OpenVPN configuration file. This will give you access to a dynamic command prompt accessible via telnet.

# Android Clients

How to connect a mobile phone or a tablet on Android? You can use OpenVPN for Android (opens new window), also available on FDroid (opens new window). I think, if you did all the work before, configuring a graphical OpenVPN client will be not complicated.

# Next Time

VPN is a really interesting topic! This is the first one of a probably long series. This part was dedicated to client/server tunnel based on OpenVPN. In another parts, I will show you how to create a distributed network with Tinc on OpenBSD/FreeBSD, and how to share route with OSPF and bird/openospfd. We will talk about some other tunnel technology like IPSec, OCServ, MLVPN, ll other small tools to make tunnel everywhere (like netcat, socat, stunnel…) and much more (hiding a VPN or a tunnel, automatic deploy with salt/ansible…)!

# Thanks

  • Thanks to Calomel website, help me a lot! ❤
  • Thanks to OpenBSD, its really easy to create anything on it! ❤
  • Thanks to OpenBSD Amsterdam, nice project, I’m using your server to build my distributed VPN, and it just works. ❤
  • Thanks to FreeBSD and HardenedBSD projects. ❤
  • Thanks to you, anonymous reader, to follow me and all my adventures in the digital world!

# Resources