Setup OpenVPN server

It happens that this installation was done on Fedora25 server with single NIC connected to a switch passing all VLANs as trunk. Then there will be NetworkManager and selinux stuff here.

I still not feel good with firewalld, then I am usually replacing it with iptables-services*rpm. Then here will be an iptables stuff also.

Prepare network, remove all unneccesary connections and define correct definitions. Hint: do this on console.

# nmcli connection delete "Wired connection 1"
# nmcli connection add con-name INTERNET type vlan id 20 ifname INTERNET \
    dev ens192 ipv4.method manual ipv4.addresses 15.15.15.15/24 ipv6.method ignore \
    ipv4.gateway 15.15.15.1

I know that 15.15.15.15 belongs to HP, I will use it here only for example. Use your real IP address, mask and gateway information.

Configure firewall, make remote access possible. You can use this "SSH, MOSH backdoor access to your server" memo as reference.

Authentication

It is important part to decide how to authenticate vpn connections. Thanks to PAM, you can choose almost any user authentication with OVPN. I've selected to use certificate based authentication without dealing with real users creation and password caring.

Read Making your own CA using openssl how to make your own CA and certificates. You can use any certificates, for example, get them from AD. You will need the following certificates before continue with OVPN configuration:

It is good idea to make your own CA only for OVPN usage, then you can fully control it.

Put all files at /etc/pki/CA/ (default place for CA on Fedora) or /etc/ssl/ (I likes this slightly more). Make all of them owned by root with 644 mode. The private unlocked key have to be 400 mode. Apply to them selinux policy:

# restorecon /etc/ssl/*
# ls -lZ /etc/ssl/cacert.pem
-rw-r--r--. 1 root root unconfined_u:object_r:cert_t:s0 424 Apr 23 15:51 /etc/ssl/cacert.pem

OVPN in routing configuration

This type of configuration suits when OVPN server installed on office default gateway. Then there is no needs to add routes to remote addresses on every internal server.

Add internal interface and give it internal IP address:

# nmcli connection add con-name LAN type vlan id 30 ifname LAN \
    dev ens192 ipv4.method manual ipv4.addresses 192.168.0.1/24 ipv6.method ignore

Configure NAT and firewall, this server will give internet access to internal LAN, not only VPN. Add additional services, if you want. Usually I adding caching DNS server, NTP server, DHCP server. Update firewall to allow desired protocols on relevant interfaces.

Copy example config file to /etc/openvpn/server/ and apply selinux policy:

# cp -v $(rpm -qd openvpn | grep /server.conf) /etc/openvpn/server/
# restorecon /etc/openvpn/server/server.conf
# ls -lZ /etc/openvpn/server/server.conf
-rw-r--r--. 1 root root unconfined_u:object_r:openvpn_etc_t:s0 621 Apr 23 16:24 /etc/openvpn/server/server.conf

Edit the example configuration file as you want. Mine resulting file looks as:

# egrep -v "^$|^#|^;" /etc/openvpn/server/server.conf
port 11940
proto udp
dev tun
ca /etc/ssl/cacert.pem
cert /etc/ssl/server.pem
key /etc/ssl/unlocked_server_key.pem
dh /etc/ssl/dh2048.pem
tls-server
server 100.99.1.0 255.255.255.0
ifconfig-pool-persist ipp.txt
push "route 192.168.0.0 255.255.255.0"
keepalive 10 120
cipher AES-256-CBC
compress lz4
push "compress lz4"
user nobody
group nobody
persist-key
persist-tun
status openvpn-status.log
verb 3
explicit-exit-notify 1

My OVPN server will listen UDP port 11940. Of course, you have to allow it in firewall ! But this is not enough. You should add it to selinux too:

# semanage port -a -t openvpn_port_t -p udp 11940

A DH file (/etc/ssl/dh2048.pem) should be created according to instructions in example file, a selinux policy should be applied to it:

# openssl  dhparam -out /etc/ssl/dh2048.pem 2048
 ..
# restorecon /etc/ssl/dh2048.pem

Skip to "Starting server" part.

Bridge mode configuration

Bridge mode is most flexible VPN configuration. You should not play with any route tables, nor on server, neither on client side. A VPN client will get IP address from internal subnet and will work directly.

However, there is a lot of limitations in implementation. Bridge mode puts network interface in promiscous mode and if it is not allowed, the solution will not work. For example, this is not possible on any cloud provider. An existing solutions for VmWare guest to use promiscous mode for network interface caused many other problems to me, therefore I decide that bridge mode VPN do not suit for use in VmWare guest.

A LAN network interface that was simply defined in chapter above, should be configured in different way. Remove all internal interfaces (it was named LAN in previous example):

# nmcli connection delete LAN

Create bridge and assign IP to it, create VLAN interface then attach it to bridge:

# nmcli connection add con-name BR30 type bridge ifname BR30 \
    ipv4.method manual ipv4.addresses 192.168.0.201/24 ipv6.method ignore
# nmcli connection modify BR30 bridge.stp no
# nmcli connection modify BR30 bridge.forward-delay 0
# nmcli connection add con-name V30 type vlan id 30 ifname V30 dev \
    ens192 ipv4.method disabled ipv6.method ignore
# nmcli connection modify V30 type bridge-slave master BR30

You have not have to assign any address at all. If you do not want OVPN server itself access or be accessible by this VLAN, then no IP required. But for the first time, it is good to assign any IP to check connectivity.

For some reason, nmcli does not write bridge parameters well in configuration file. Check it (/etc/sysconfig/network-scripts/ifcfg-BR30) and verify that:

STP=no
DELAY=0

The virtual interface, created by OVPN will be attached to bridge using external script. You have to put this script to /etc/openvpn/scripts directory to fits selinux rules.

root:/etc/openvpn/scripts # cat add_to_BR.sh 
#!/bin/bash
#
# called by openvpn with parms:
# cmd tap_dev tap_mtu link_mtu ifconfig_local_ip ifconfig_netmask [ init | restart ]

BR=${BRIDGE:-BR30}
echo " BR=$BR ; BRIDGE=$BRIDGE ;" | logger -t "add_to_BR.sh"

/usr/bin/nmcli connection modify $BR bridge.forward-delay 0
/usr/sbin/ip link set $1 master $BR up

root:/etc/openvpn/scripts # ls -lZ add_to_BR.sh
-rwxr-xr-x. 1 root root unconfined_u:object_r:openvpn_unconfined_script_exec_t:s0 357 May 10 22:49 add_to_BR.sh

Make script executable and run "restorecon" on it.

It's time to write configuration file:

root:/etc/openvpn/server # cat bridgevpn.conf
mode server
tls-server

# to change:
max-clients 5
ifconfig-pool 192.168.0.241 192.168.0.249 255.255.255.0
port 11940
setenv BRIDGE BR30

verify-client-cert require
ca /etc/ssl/cacert.pem
cert /etc/ssl/server.pem
key /etc/ssl/unlocked_server_key.pem
dh /etc/ssl/dh2048.pem
dev tap
syslog
verb 2
compress lz4
push "compress lz4"

# bind address:
local 15.15.15.15
proto udp

script-security 2
# set using setenv var BRIDGE passed to script
up /etc/openvpn/scripts/add_to_BR.sh

user openvpn
group openvpn

Do not forget to run "restorecon" on configuration file. The UDP listening port should be opened in firewall and enabled in selinux:

# semanage port -a -t openvpn_port_t -p udp 11940

Site to site configuration

TBD

Starting OVPN server

Openvpn services are autogenerated services based on configuration files you've been created. Therefore, ask systemd to rescan files:

# systemctl daemon-reload
# systemctl list-units | grep openvpn
Now you can start it as usual.

Creating user.ovpn file

Now you will need a user's certificate, we talked about in authentication chapter. Create user.ovpn using text editor:

client
dev tun # <- use this for routed 
dev tap # <- use this for bridged
proto udp
remote 15.15.15.15 11940
persist-key
cipher AES-256-CBC # <- should match server's definitions
verb 2
compress lz4
auth-nocache
<ca>
-----BEGIN CERTIFICATE-----
Copy-Paste here CA Certificate
-----END CERTIFICATE-----
</ca>
<cert>
-----BEGIN CERTIFICATE-----
Copy-Paste here User Certificate
-----END CERTIFICATE-----
</cert>
<key>
-----BEGIN ENCRYPTED PRIVATE KEY-----
Copy-Paste here User's encrypted key
-----END ENCRYPTED PRIVATE KEY-----
</key>

Updated on Sun Sep 3 13:20:46 IDT 2017 More documentations here