VPN setup

Installation

OpenVPN

Ubuntu tutorial | html

sudo apt-get install openvpn easy-rsa

Alternative for site-to-site (requires public addresses): StrongSwan

Key generation

Generate all server and client(s) keys on a dedicated host, using easy-rsa script

Preparation

sudo su
make-cadir /etc/openvpn/easy-rsa
cd /etc/openvpn/easy-rsa

vi vars
# Edit KEY specific info

# fix cnf file check with latest open-ssl versions
ln -s openssl-1.0.0.cnf openssl.cnf

. ./vars
./clean-all

Certificate Authority key

CA uses the follwing files:

CA key is used by neither server nor clients, it is only used to sign/revoque each device keys.

# generate the self-signed CA key pair
./build-ca

Server keys

Server uses the follwing files:

.csr (Certificate Signing Request) are not used/needed after key generation.

# generate and sign server key pair
./build-key-server server

# generate the Diffie Hellman parameters file
./build-dh

# generate client authentication key
openvpn --genkey --secret ta.key

# pack server keys
tar cvzf server-keys.tgz ta.key -C easy-rsa/keys ca.crt server.crt server.key dh2048.pem

Client key

Generates the following files:

We generate one Client key set per client host.

# generate and sign client key (one for each client)
./build-key client-x

# pack client keys
tar cvzf client-x-keys.tgz ta.key -C easy-rsa/keys ca.crt client-x.crt client-x.key

To check key status:

sudo openssl x509 -in client_dart.crt -text -noout

Server configuration

OpenVPN sample server conf file is a good starting point.

# use the sample server file
cd /etc/openvpn/
cp /usr/share/doc/openvpn/examples/sample-config-files/server.conf.gz .
gunzip server.conf.gz

# get the keys
ssh user@keyhost cat private/server-keys.tgz | tar xvzf -

# start the server
systemctl start openvpn@server

# check current server status
systemctl status openvpn@server

Client configuration

Some adjustment are needed on the client side

# use the sample client file
cd /etc/openvpn/
cp /usr/share/doc/openvpn/examples/sample-config-files/client.conf .

# get the keys
ssh user@keyhost cat private/client-x-keys.tgz | tar xvzf -
vi client.conf
remote my-server-1 1194
remote server.com 1194

cert client.crt
key client.key
cert client-x.crt
key client-x.key

;tls-auth ta.key 1
tls-auth ta.key 1

;cipher x
cipher AES-256-CBC

comp-lzo
# comp-lzo

Start the client

# start the client
systemctl start openvpn@client

# check current client status
systemctl status openvpn@client.service

Testing

From client

Server is 10.8.0.1 (as per config file), interface is tun0

ip addr show tun0
13: tun0:  mtu 1500 qdisc pfifo_fast state UNKNOWN group default qlen 100
    link/none
    inet 10.8.0.6 peer 10.8.0.5/32 scope global tun0
       valid_lft forever preferred_lft forever

ip -s link show tun0
13: tun0:  mtu 1500 qdisc pfifo_fast state UNKNOWN mode DEFAULT group default qlen 100
    link/none
    RX: bytes  packets  errors  dropped overrun mcast
    8774       88       0       0       0       0
    TX: bytes  packets  errors  dropped carrier collsns
    9421       68       0       0       0       0

ping 10.8.0.1 -c 4
PING 10.8.0.1 (10.8.0.1) 56(84) bytes of data.
64 bytes from 10.8.0.1: icmp_seq=1 ttl=64 time=95.8 ms
64 bytes from 10.8.0.1: icmp_seq=2 ttl=64 time=91.1 ms
64 bytes from 10.8.0.1: icmp_seq=3 ttl=64 time=90.7 ms
64 bytes from 10.8.0.1: icmp_seq=4 ttl=64 time=90.6 ms

--- 10.8.0.1 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3003ms
rtt min/avg/max/mdev = 90.637/92.112/95.897/2.214 ms

From server

ip addr show tun0
4: tun0:  mtu 1500 qdisc pfifo_fast state UNKNOWN group default qlen 100
    link/none
    inet 10.8.0.1 peer 10.8.0.2/32 scope global tun0
       valid_lft forever preferred_lft forever
    inet6 fe80::8b05:3440:a279:508d/64 scope link flags 800
       valid_lft forever preferred_lft forever

ip -s link show tun0
4: tun0:  mtu 1500 qdisc pfifo_fast state UNKNOWN mode DEFAULT group default qlen 100
    link/none
    RX: bytes  packets  errors  dropped overrun mcast
    9925       74       0       0       0       0
    TX: bytes  packets  errors  dropped carrier collsns
    11034      123      0       0       0       0

ping 10.8.0.6 -c 4
PING 10.8.0.6 (10.8.0.6) 56(84) bytes of data.
64 bytes from 10.8.0.6: icmp_seq=1 ttl=64 time=91.0 ms
64 bytes from 10.8.0.6: icmp_seq=2 ttl=64 time=93.3 ms
64 bytes from 10.8.0.6: icmp_seq=3 ttl=64 time=99.6 ms
64 bytes from 10.8.0.6: icmp_seq=4 ttl=64 time=94.2 ms

--- 10.8.0.6 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3004ms
rtt min/avg/max/mdev = 91.040/94.575/99.673/3.173 ms

Expanding VPN scope to client/server subnets

Scenario

Next step is to use the VPN tunnel to allow hosts from server LAN to communicate with hosts from client LAN and vice versa.

Internet Server HostA RouterA LanA 192.168.0.xxx .99 .254 .2 Client RouterB HostB LanB 192.168.10.xxx .230 .200 .100 Vpn 10.8.0.1 10.8.0.2

As depicted, HostA (192.168.0.2) from LanA will use tunnel from VPN Server (192.168.0.99) to VPN Client (192.168.10.200) to reach HostB (192.168.10.230).

Server configuration:

Add to the server configuration:

sudo vi /etc/openvpn/server.conf
# Create the routed IP tunnel
proto udp
dev tun
mode server
tls-server
;topology subnet
topology subnet
server 10.8.0.0 255.255.255.0
ifconfig 10.8.0.1 255.255.255.0

# Configure client
;client-config-dir ccd
;route 10.9.0.0 255.255.255.252
client-config-dir ccd
route 192.168.10.0 255.255.255.0 10.8.0.2

Also create client configuration file (for each client, named after client certificate Common Name):

sudo mkdir /etc/openvpn/ccd
sudo vi /etc/openvpn/ccd/client-x
ifconfig-push 10.8.0.2 255.255.255.0
push "route 192.168.0.0 255.255.255.0 10.8.0.1"
iroute 192.168.10.0 255.255.255.0

Restart the server:

sudo systemctl restart openvpn@server

Client configuration

sudo vi /etc/openvpn/client.conf
client
dev tun
proto udp
topology subnet

Restart the server:

sudo systemctl restart openvpn@client

Additional config

Server and all clients need to have IP forwarding enabled:

# echo 1 > /proc/sys/net/ipv4/ip_forward
sudo sysctl -w net.ipv4.ip_forward=1
# sudo sysctl -w net.ipv6.conf.all.forwarding=1

To make the change permanent:

sudo vi /etc/sysctl.conf
# Uncomment the next line to enable packet forwarding for IPv4
#net.ipv4.ip_forward=1
net.ipv4.ip_forward=1

Local hosts need to have a route to openvpn added (either on the default gateway or on all accessible hosts)
Note: This is not required when OpenVPN is installed on the default gateway

sudo ip route add 192.168.10.0/24 via 192.168.0.99

When OpenVPN server is installed behind a NAT gateway, gateway port 1194 must be forwarded to OpenVPN host

Others

Port forwarding

To forward all traffic coming to a port to another host/port:

local=192.168.0.99
lport=8080
dest=10.8.0.6
dport=80

iptables -t nat -A PREROUTING  -p tcp --dst $local --dport $lport -j DNAT --to-destination $dest:$dport
iptables -t nat -A POSTROUTING -p tcp --dst $dest  --dport $dport -j SNAT --to-source $local
iptables -t nat -A OUTPUT      -p tcp --dst $local --dport $lport -j DNAT --to-destination $dest:$dport

Idle ping/keep alive

Keep alive may use significant bandwidth on limited plans. to limit:

By default, openvpn sends ping every 10s idle, means 64*26*60*24*31 = 35MB/month (significant is on a 50MB plan)

Switching to 1 ping per minute will reduce to .5M / month

iftop -p -N -n
# The keepalive directive causes ping-like
# messages to be sent back and forth over
# the link so that each side knows when
# the other side has gone down.
# Ping every 10 seconds, assume that remote
# peer is down if no ping received during
# a 120 second time period.
keepalive 10 120
keepalive 60 360
16-Jan-2020