Extended Brain Storage

OpenBSD: WireGuard Server

Posted on June 6, 2020

This is a brief tutorial to set up a WireGuard® service in OpenBSD...

Introduction

WireGuard® is a free, open-source and an extremely simple yet fast and modern VPN software application, which utilises state-of-the-art cryptography.

In OpenBSD 6.7, it was implemented in user space only (wireguard-go-0.0.20200320v0.tgz). OpenBSD 6.8 finally introduced the built in kernel support.


WireGuard Interface Configuration

All server configuration is kept in the appropriate /etc/hostname.wgX file and the related ifconfig command and is dead simple:

$ cat /etc/hostname.wg0
inet IPv4_ADDRESS_OF_THIS_SERVER IPv4_MASK
wgkey PUBLIC_KEY_OF_THIS_SERVER wgport UDP_PORT_NUMBER
wgpeer PUBLIC_KEY_OF_PEER_ONE wgpsk PRE-SHARED_KEY wgpka KEEPALIVE-SECONDS wgaip IPv4_ADDRESS_OF_PEER_ONE
wgpeer PUBLIC_KEY_OF_PEER_TWO wgpsk PRE-SHARED_KEY wgpka KEEPALIVE-SECONDS wgaip IPv4_ADDRESS_OF_PEER_TWO

where wgpsk (default none) and wgpka (default zero) are optional.

Using the 192.0.2.0/24 (TEST-NET-1) documentation address block (see RFC 5737 for more details), the network configuration can look as follows:

...and the configuration transforms into:

$ cat /etc/hostname.wg0
inet 192.0.2.1 255.255.255.0
wgkey RandomlyGeneratePrivateKeyOfThisServer====== wgport 1194
wgpeer PublicKeyOfPeer1GeneratedFromItsPrivateKey== wgpsk RandomlyGeneratedPresharedKey9876543210===== wgpka 25 wgaip 192.0.2.2/32
wgpeer PublicKeyOfPeer2GeneratedFromItsPrivateKey== wgpsk RandomlyGeneratedPresharedKey9876543210===== wgpka 25 wgaip 192.0.2.3/32

WireGuard Keys Management

Private keys for WireGuard can be generated from any sufficiently secure random source. The Curve25519 keys and the preshared keys are both 32 bytes long and are commonly encoded in base64 for ease of use. Therefore, they can be generated using the OpenSSL library as follows (somewhere outside of the WireGuard server):

$ mkdir ~/wireguard
$ chmod 0700 ~/wireguard/
$ openssl rand -base64 32 > ~/wireguard/server-private.key
$ openssl rand -base64 32 > ~/wireguard/peer1-private.key
$ openssl rand -base64 32 > ~/wireguard/peer2-private.key
$ openssl rand -base64 32 > ~/wireguard/preshared.key

Although a valid Curve25519 key must have 5 bits set to specific values, this is done by the interface and so it will accept any random 32-byte base64 string.

When an interface has a private key set with wgkey (i.e. in the appropriate /etc/hostname.wgX file), the corresponding public key is shown in the status output of the interface, e.g.:

# ifconfig wg0 | grep wgpubkey
	wgpubkey PublicKeyOfThisServerGeneratedFromItsPrivate

In order to get the necessary public keys fo all peers, the following commands need to be run for each peer:

$ ifconfig wg1 create wgkey "$(cat ~/wireguard/peerX-private.key)" wgport 50005
$ ifconfig wg1 | grep wgpubkey | cut -d ' ' -f 2 > ~/wireguard/peerX-public.key
$ ifconfig wg1 destroy

WireGuard Tools

As an alternative to the OpenSSL, the WireGuard tools package can be used to generate the key pairs described above and can be installed as follows:

$ pkg_add wireguard-tools
...
New and changed readme(s):
	/usr/local/share/doc/pkg-readmes/wireguard-tools

WireGuard keys can be generated and configured using the previously installed tools as follows:

$ mkdir ~/wireguard
$ chmod 0700 ~/wireguard/
$ cd ~/wireguard
$ wg genkey | tee ~/wireguard/server-private.key | wg pubkey > ~/wireguard/server-public.key
$ wg genkey | tee ~/wireguard/peer1-private.key | wg pubkey > ~/wireguard/peer1-public.key
$ wg genkey | tee ~/wireguard/peer2-private.key | wg pubkey > ~/wireguard/peer2-public.key
$ wg genpsk > ~/wireguard/preshared.key

WireGuard Client Setup (Using QR Codes)

Client (peer) configuration can be configured as follows (e.g. for a mobile smartphone):

$ cat ~/wireguard/peer1.conf
[Interface]
#Phone private key
PrivateKey = PEER1-PRIVATE-KEY
Address = 192.0.2.3/32
DNS = 192.0.2.1

[Peer]
#WireGuard server public key
PublicKey = SERVER-PUBLIC-KEY
PresharedKey = SERVER-PRESHARED-KEY
AllowedIPs = 0.0.0.0/0, ::/0
Endpoint = SERVER-PUBLIC-IP-OR-FQDN:UDP-PORT
PersistentKeepalive = 25

Leveraging the libqrencode to generate pictures for phones can be achieved as follows:

$ pkg_add libqrencode
$ qrencode -t ansiutf8 < ~/wireguard/peer1.conf

Packet Filter and DNS Server Configuration Updates

The IP forwarding should be taken care of as part of packet filter setup, the firewall rules (in the pf.conf file) should be updated accordingly and the rules re-applied using the pfctl command, e.g.:

wgd_if = "tun1"                         # WireGuard
wrgd_ports   = "1194"
...
### Tunnels traffic
# simple IP spoofing prevention and filtering
pass in  quick on $wgd_if inet from $wgd_if:network to any
# deny any other traffic
block return in  quick on $wgd_if inet all
...
### General services setup on egress inwards and filtering out bruteforce
pass in  quick on egress inet proto udp from any to (egress) port $wrgd_ports \
        keep state \
        (max-src-conn 30, max-src-conn-rate 10/1, \
        overload <bruteforcetemp> flush global)
...

If using a private Caching DNS Resolver, the unbound.conf file should be updated as follows (at least) and the daemon restarted:

...
server:
        interface: 192.0.2.1
	...
        access-control: 192.0.2.0/24 allow
	...

Putting Everything Together

Bringing the interface up:

$ chmod 640 /etc/hostname.wg0
$ sh /etc/netstart wg0

Service Exposure Verification

The WireGuard service is more or less undetectable. The verification can be performed using:

$ nc -uvz SERVER-IP-OR-FQDN PORT
$ sudo nmap -sS -sU -Pn -O SERVER-IP-OR-FQDN -p PORT
Starting Nmap 7.80 ( https://nmap.org ) at 2020-06-06 11:38 CEST
Nmap scan report for SERVER-FQDN (SERVER-IP)
Host is up (0.0098s latency).

PORT     STATE         SERVICE
PORT/udp open|filtered service
Warning: OSScan results may be unreliable because we could not find at least 1 open and 1 closed port
Device type: specialized
Running (JUST GUESSING): Comau embedded (86%)
Aggressive OS guesses: Comau C4G robot control unit (86%)
No exact OS matches for host (test conditions non-ideal).
Network Distance: 9 hops

OS detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 4.80 seconds

Tags: #OpenBSD #WireGuard #VPN #security #hardening

⏴ Previous Post