
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 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:
with official builded packages and
[pkg install](https://www.freebsd.org/cgi/man.cgi?query=pkg-install)command;with poudriere (opens new window) (if you want to create your own repository).
\# 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!