Dieser Artikel beschreibt die Konfiguration eines Wireguard - VPN-Servers auf debian 9 (stretch,stable). Sämtlicher IPv4- als auch IPv6-Verkehr eines Roadwarriors soll durch Wireguard getunnelt werden. Als Server kommt ein Hetzner-Cloud-server CX11 zum Einsatz. Für 2,96€ im Monat bekommt man genügend Leistung, eine fixe IPv4-Adresse und ein IPv6-Netz (/64) zugewiesen.

Wireguard ist eine moderne VPN-Lösung mit einer sehr schmalen Codebasis. Wireguard implementiert nur wenige, dafür aber aktuelle Verschlüsselungsverfahren und läuft, anders als zum Beispiel OpenVPN, im Kontext des Kernels. Eine detaillierte Beschreibung des Protokolls und eine Übersicht über die verwendeten kryptografischen Verfahren kann man im Wireguard-whitepaper nachlesen. In den nächsten Monaten (stand März 2019) soll Wireguard Aufnahme in den Linux-Kernel finden. Für debian 10 testing und unstable/sid stehen aktuelle Pakete in den debian-repositories bereit. Die Installation auf allen gängigen Linux-Distributionen und BSD-Systemen ist auf der Wireguard-Homepage beschrieben. Als Transportprotokoll setzt Wireguard ausschließlich auf UDP, möchte man stattdessen TCP einsetzen (einziger Grund wäre eine Blockierung von UDP), muss man Wireguard zum Beispiel über WebSockets tunneln.

Das Szenario

  1. Sämtlicher Verkehr soll über einen Tunnel geroutet werden.
  2. Die DNS-Auflösung und das Caching soll vom VPN-Server übernommen werden.
  3. Die Konfiguration auf dem VPN-Server soll persistent sein.
  4. Die Clientkonfiguration soll per QR-Code auf Apple-IOS/Android übertragen werden.

Installation

Da Wireguard ein Kernelmodul benötigt, muss das System zu dessen Übersetzung vorbereitet werden:

sudo apt-get install linux-headers-$(uname -r) build-essential

Für debian 9 stretch/stable existieren noch keine Pakete im offiziellen repository, daher muss das unstable-repository auf dem System verfügbar gemacht werden. Bei debian 10 kann dieser Schritt übersprungen werden. Dabei werden alle Pakete aus unstable jedoch so niedrig priorisiert, dass alle Pakete aus stable bei Updates den Vorzug erhalten, außer explizit installierten Paketen aus unstable:

$ sudo echo "deb http://deb.debian.org/debian/ unstable main" > /etc/apt/sources.list.d/unstable.list
$ sudo printf 'Package: *\nPin: release a=unstable\nPin-Priority: 90\n' > /etc/apt/preferences.d/limit-unstable

Im Anschluss wird Wireguard installiert und das Kernelmodul wird automatisch übersetzt und geladen:

$ sudo apt update && apt install wireguard

Ob das Kernelmodul geladen ist, lässt sich leicht überprüfen:

$ sudo lsmod | grep wireguard

Routing aktivieren

Damit der VPN-Server IPv4 und IPv6 Pakete weiterleitet muss diese Funktionalität dem Kernel mitgeteilt werden:

$ sysctl net.ipv4.ip_forward=1
$ sysctl net.ipv6.conf.all.forwarding=1

Um diese Einstellungen auch nach einem Neustart zu setzen, sind folgende Zeilen zur Datei /etc/sysctl.d/99-sysctl.conf zu ergänzen:

net.ipv4.ip_forward=1
net.ipv6.conf.all.forwarding=1

Erstellen der Schlüssel

Wireguard basiert auf dem Konzept des Crypto-Routing. Jeder Kommunikationsteilnehmer an einem VPN besitzt ein asymmetrisches Schlüsselpaar, der jeweilige öffentliche Schlüssel wird demjenigen Kommunikationspartner mitgeteilt, der über den Kommunikationskanal kommunizieren darf. Die Schlüssel sind sehr kurze base64-kodierte ECDH-Schlüssel. Die Schlüssel können auf jedem System, auf auf dem Wireguard verfügbar ist, generiert werden.

Schlüsselpaar für den VPN-Server:

$ wg genkey > vpn-server.seckey
$ wg pubkey < vpn-server.seckey > vpn-server.pubkey

Schlüsselpaar für einen weiteren Kommunikationsteilnehmer:

$ wg genkey > mobile.seckey
$ wg pubkey < mobile.seckey > mobile.pubkey

Optional ist die Generierung eines weiteren pre shared keys um eine weitere Schicht symmetrischer Verschlüsselung hinzuzufügen. Gründe hierfür werden in Abschnitt 5.2 des Wireguard-Whitepapers erläutert.

$ wg genpsk > vpn.psk

Wireguard-Konfiguration des VPN-Servers

Es existieren zwei Möglichkeiten Wireguard zu betreiben, man kann mithilfe von wg einen Tunnel etablieren und Kommunikationspartner (peers) hinzufügen. Alternativ dazu hat man die Möglichkeit eine Konfigurationsdatei zu erstellen, welche später von wg-quick eingelesen wird. Die zweite Möglichkeit hat den Vorteil, dass sich wg-quick auch gleich um die Erstellung und Konfiguration der Wireguard-Netzwerkschnittstelle (im Beispiel: wg0) kümmert. Zudem bringt das Debian-Paket auch gleich ein Systemd-Interface-Template mit, was ein Start des VPNs erleichtert und keine zusätzlichen Systemd-Kenntnisse erfordert.

Bevor die Konfiguration von Wireguard erfolgen kann, noch einige Worte zur IP-Adresskonfiguration von Hetzner. IPv4-Adressen werden durch Hetzner per DHCP vergeben, sind aber persistent. IPv6 Adressen werden stattdessen statisch konfiguriert, Hetzner verwendet dazu auf ihren debian Cloud-Servern die debian networking-scripte. Die IP-Adresskonfiguration findet sich unter: /etc/network/interfaces.d/50-cloud-init.cfg.

Exemplarisch sind folgende Adressen auf dem Interface eth0 konfiguriert:

IPv4: 203.0.113.1/32
IPv6: 2001:db8:ffff:ffff::1/64

Da Wireguard über das virtuelle Tunnelinterface wg0 kommuniziert, müssen, jeweils für IPv4 und IPv6, interne Tunnel-Netze und Adressen vergeben werden. Für IPv4 wählt man ein privates Netz gemäß RFC1918, in diesem Beispiel verwenden wir 172.16.100.0/24. Dem VPN-Server wird später die erste Adresse aus diesem Bereich zugewiesen. Die Adressen aus diesem privaten IPv4-Bereich müssen später noch einer Adressumsetzung auf die öffentliche Adresse 203.0.113.1 unterzogen werden.

Bei IPv6 hingegen reicht es aus das öffentliche Netz 2001:db8:ffff:ffff::/64 zu segmentieren. Zum Beispiel kann man das Netz in 256 Subnetze unterteilen: 2001:db8:ffff:ffff::/72. Die IPv6-Adresse auf eth0 ändert sich dadurch nicht, lediglich die Netzgröße. Daher muss diese in der Datei /etc/network/interfaces.d/50-cloud-init.cfg angepasst werden:

#address 2001:db8:ffff:ffff::1/64
address 2001:db8:ffff:ffff::1/72

Im Anschluss muss die Konfiguration neu eingelesen werden:

$ sudo systemctl restart networking.service

Das zweite Netz aus dem IPv6-Bereich (2001:db8:ffff:ffff:100:/72) wird für die internen Tunneladressen verwendet.

Die Konfigurationsdatei von Wireguard muss nach dem Wireguard-Interface benannt benannt werden: /etc/wireguard/wg0.conf. In diesem Beispiel lauscht der Wireguard-VPN-Server auf dem Port upd/443 auf eth0. Lediglich die Schlüssel müssen noch ergänzt werden:

[Interface]                                                                                  
Address = 172.16.100.1/24                                                                     
Address = 2001:db8:ffff:ffff:100::1/72                                                       
SaveConfig = true                                                                            
PostUp = iptables -A FORWARD -i %i -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
PostDown = iptables -D FORWARD -i %i -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE
ListenPort = 443                                                                             
PrivateKey = [vpn-server.seckey]                                   

[Peer]
PublicKey = [mobile.pubkey]
PresharedKey = [vpn.psk]
AllowedIPs = 172.16.100.0/24, 2001:db8:ffff:ffff:100::/72

Wireguard kann nun mittels wg-quick gestartet werden:

$ sudo wg-quick up /etc/wireguard/wg0.conf

Sollte der VPN-Server ohne Probleme starten, kann man die Konfiguration mittels Systemd persistent machen:

$ sudo systemctl enable wg-quick@wg0

DNS-Auflösung auf dem VPN-Server

Die Teilnehmer am VPN-Netzwerk sollen DNS-Anfragen durch den Tunnel an den VPN-Server richten können. In diesem Beispiel wird dnsmasq verwendet, aber auch andere resolver wie unbound können verwendet werden.

Eine exemplarische Konfiguration für dnsmasq (/etc/dnsmasq.conf):

# Quad9 - Initiative https://www.quad9.net/
server=9.9.9.9
server=149.112.112.112
server=2620:fe::fe
server=2620:fe::9

listen-address=127.0.0.1,172.16.100.1
bind-interfaces

cache-size=1000

Neustart von dnsmasq:

$ systemctl restart dnsmasq.service

Damit DNS-Anfragen an dnsmasq gerichtet werden, müssen auf dem VPN-Server die Nameserver in der Datei /etc/resolv.conf auf eine Loopbackadresse verweisen. Dazu wird in der Datei /etc/dhclient/dhclient.conf folgende Zeile auskommentiert:

#prepend domain-name-servers 127.0.0.1;
prepend domain-name-servers 127.0.0.1;

Im Anschluss muss die Konfiguration neu eingelesen werden:

$ sudo systemctl restart networking.service

Wireguard-Konfiguration des Clients

Die Datei kann auf einem beliebigen System erstellt werden:

[Interface]
Address = 172.16.100.2/24, 2001:db8:ffff:ffff:100::2/72
PrivateKey = [mobile.seckey]
DNS = 172.16.100.1

[Peer]
PublicKey = [vpn-server.pubkey]
PresharedKey = [vpn.psk] 
AllowedIPs = 0.0.0.0/0, ::/0
Endpoint = 203.0.113.1:443

Diese Datei kann nun als QR-Code kodiert werden und mithilfe der Android-/IOS-App eingelesen werden

$ qrencode -t ansiutf8 < client.conf

Next post: COVID-19 Plots

Previous post: certificate update