September 17, 2019

OpenVPN on OpenBSD

Despite Wireguard being the hot new choice for a VPN on unixy systems, I’ve still stuck to OpenVPN. I’ll be trying WG at some point, but OVPN has mostly-worked for me, despite some painful past experiences.

As I’ve needed to move some servers around, I’ll be reinstalling OpenVPN and figured it’s best to document my actions this time.

For my purposes, I do not use OpenVPN to proxy traffic, mostly just to be able to access a few services from outside of my home network. Additionally, some hardening options are enabled, but this isn’t intended to be the most secure setup; Notably I’ve no CRL and I use tls-auth instead of tls-crypt.

Obvious step, installation:

pkg_add openvpn easy-rsa

Review and edit the easy-rsa vars file as needed:

cp /usr/local/share/easy-rsa/vars{.example,} && vim /usr/local/share/easy-rsa/vars

Creating directories as OpenBSD appears to not give us the courteousy, with a bit of an odd setup so we can chroot:

install -m 700 -d /etc/openvpn/clients
# ^ personal preference for creating new client configs on the server side, see script below
install -m 700 -o _openvpn -d /var/openvpn/var/log/openvpn
# ^ Not entirely sure if this is still necessary, openvpn opens logs before chroot
install -m 700 -d /var/openvpn/etc/openvpn/ccd
install -m 700 -o _openvpn -d /var/openvpn/tmp

touch /var/openvpn/var/log/openvpn/openvpn.log
ln -s /var/openvpn/etc/openvpn/ccd /etc/openvpn/ccd
ln -s /var/openvpn/var/log/openvpn/ /var/log/openvpn

Next we’ll generate our CA and associated certificates and keys using easy-rsa. You’ll want to go through this line-by-line, some parts are interactive:

alias easyrsa=/usr/local/share/easy-rsa/easyrsa
cd /etc/openvpn/
easyrsa init-pki
easyrsa build-ca nopass
easyrsa build-server-full server polynomial.space nopass
easyrsa gen-dh

openvpn --genkey --secret ta.key

Drop in a basic config, uncommented for brievety, probably best to reference some sample configs:

cat <<\EOF > /etc/openvpn.conf
ca		/etc/openvpn/pki/ca.crt
cert		/etc/openvpn/pki/issued/server.crt
key		/etc/openvpn/pki/private/server.key
dh		/etc/openvpn/pki/dh.pem
tls-auth	/etc/openvpn/ta.key 0

por	61194
proto	tcp
proto	udp
dev	tun

topology	subnet
server		172.16.32.0 255.255.255.0
push		"route 172.16.32.0 255.255.255.0"
keepalive	10 120
client-to-client

ifconfig-pool-persist	/var/log/openvpn/ipp.txt
client-config-dir	/etc/openvpn/ccd
status			/var/log/openvpn/openvpn.log
verb			2

tls-version-min		1.2
tls-ciphers		TLS-DHE-RSA-WITH-AES-256-CBC-SHA256
ncp-ciphers		AES-256-GCM
cipher			AES-256-GCM
auth			SHA256
persist-key
persist-tun

user	_openvpn
group	_openvpn
chroot	/var/openvpn

explicit-exit-notify	1
EOF

And now a script to generate client .ovpn files on the server side, optionally allowing static IP assignment.

#!/bin/sh

CLIENT="${1}"
IP="${2}"

if [ -z "${CLIENT}" ]; then
	exit 1
fi

cd /etc/openvpn

/usr/local/share/easy-rsa/easyrsa build-client-full "${CLIENT}" nopass

cat <<\EOF > clients/"${CLIENT}".ovpn
client
dev		tun
;proto		tcp
proto		udp
remote		104.207.150.221 61194 #CHANGEME
route		172.16.32.0 255.255.255.0
nobind
persist-tun
user		openvpn
group		openvpn
cipher		AES-256-GCM
auth		SHA256
persist-key
key-direction 1
verb 	2
mute 	20

EOF

echo '<ca>'                     >> clients/"${CLIENT}".ovpn
cat pki/ca.crt                  >> clients/"${CLIENT}".ovpn
echo '</ca>'                    >> clients/"${CLIENT}".ovpn

echo '<cert>'                   >> clients/"${CLIENT}".ovpn
cat pki/issued/"${CLIENT}".crt  >> clients/"${CLIENT}".ovpn
echo '</cert>'                  >> clients/"${CLIENT}".ovpn

echo '<key>'                    >> clients/"${CLIENT}".ovpn
cat pki/private/"${CLIENT}".key >> clients/"${CLIENT}".ovpn
echo '</key>'                   >> clients/"${CLIENT}".ovpn

echo '<tls-auth>'               >> clients/"${CLIENT}".ovpn
cat ta.key                      >> clients/"${CLIENT}".ovpn
echo '</tls-auth>'              >> clients/"${CLIENT}".ovpn

rm pki/private/"${CLIENT}".key  pki/issued/"${CLIENT}".crt

if [ -n "${IP}" ]; then
	echo "ifconfig-push ${IP} 255.255.255.0" > ccd/"${CLIENT}"
fi

echo "written to: $(pwd)/clients/${CLIENT}.ovpn"

After testing the server, enable as a service:

rcctl enable openvpn
rcctl set openvpn flags "--config /etc/openvpn.conf"
rcctl start openvpn