VPN mit WireGuard in einer Client-Server-Architektur mit Ubuntu 19.10

Vor kurzem stand ich vor der Wahl bei der Neueinrichtung eines virtuellen privaten Netzwerks (VPN), das eine virtuelle Maschine (VM) im internen, privaten und nicht zuletzt heimischen Netzwerk mit einer VM bei meinem Hosting-Provider verbinden sollte. Würde sich das VPN wieder auf die bisher verwendete Lösung mit OpenVPN stützen, oder statt dessen auf das modernere und in der letzten Zeit vielfach propagierte WireGuard? Da ich einerseits gerne neue Technologien ausprobiere und es sich bei der Anwendung nicht um ein Unternehmens-Umfeld handelt, in dem andere Regeln gelten, andererseits WireGuard Vorteile wie höhere Geschwindigkeit im Vergleich zu OpenVPN und eine einfache Installation und Konfiguration verspricht, fiel die Entscheidung nicht schwer – das neue VPN sollte mit WireGuard eingerichtet werden.

Zu den grundlegenden Eigenschaften wurden bereits etliche Artikel (z.B. c’t – Übersicht, teilweise kostenpflichtig) veröffentlicht, daneben bietet die Website von WireGuard natürlich ebenfalls eine grobe Übersicht. Ich werde hier versuchen, auf die Installation und Einrichtung von WireGuard auf Linux-Systemen mit Ubuntu 19.10 (“Eoan Ermine”) einzugehen, und zwar in einer Client-Server-Struktur. WireGuard ist nach wie vor in steter Entwicklung, eine “stabile” Fassung, die sich durch eine Versionsnummer 1.0 auszeichnet, ist noch nicht erreicht. WireGuard setzt sich unter Linux aus einem Kernel-Modul und den CLI-Tools wg und wg-quick zusammen. Über die Aufnahme von WireGuard in den Linux-Kernel wird seit längerer Zeit viel diskutiert, eine Lösung scheint in Sichtweite, jedoch kann dies demnächst auch wieder anders aussehen. Auch dieser Umstand sollte beachtet werden, so könnte in einigen Monaten mit einer neuen Kernel-Version die folgende Anleitung überholt sein. Um genau zu sein ist mir es ähnlich ergangen, als ich mir etliche Artikel zur Installation durchgelesen habe – vielfach wurden wesentlich mehr Schritte beschrieben als sie aktuell tatsächlich notwendig sind. Daher möchte ich hier die Einrichtung so beschreiben, wie sie mit der aktuellen Ubuntu-Distribution bei mir funktioniert haben, ohne zu berücksichtigen, dass es auch dabei viele und unterschiedliche Wege zum Ziel gibt.

Ziel und Einsatz von WireGuard

Doch zunächst zum Ziel selbst, denn das VPN mit WireGuard dient bei mir primär einem Zweck, und zwar dem Verbergen der IP-Adresse des Zugangsproviders beim Versand von Mails von internen Servern bzw. Diensten. Wer jetzt an die dunkle Seite der Macht und SPAM-Versand denkt, liegt jedoch komplett falsch. Vielmehr werden beispielsweise Status-Mails von internen VMs versendet, oder auch Aktualisierungen vom Ticketsystem usw.. Dabei würden die Mails an irgend einer Stelle die IP-Adresse des Zugangsproviders in sich tragen, denn der interne Mailserver verbindet sich mit dem Mailserver des Empfängers, wobei die IP-Adresse aus dem DSL-Pool aufgezeichnet wird. Beim Reverse-Lookup von der IP auf den DNS-Eintrag entsteht wiederum ein unschöner Eintrag, der den DSL-Zugang kennzeichnet, etwa in der Form “xdsl-aa-bb-cc-dd.provider.de”. Das sieht einerseits unprofessionell aus, andererseits muss der Mail-Empfänger auch gar nicht wissen, wann ich mit welcher IP-Adresse vom heimischen Netz aus online war. Darüber hinaus erfolgt die Zwangstrennung nach 24 Stunden, so dass die IP-Adresse stetig wechselt. Da manche Mailserver den Empfang von Mails von DSL-Zugängen gar nicht zulassen, wird auf der externen VM ein eigener Mailserver betrieben, der als Relay dient, also eine Station zur Weiterleitung der Mails. Doch selbst dann würde die IP-Adresse aus dem DSL-Pool noch im Mail-Header auftauchen, und genau das soll vermieden werden. Zur Übersicht der gewünschten Konfiguration siehe folgende Skizze:

VPN mit WireGuard in einer Client-Server-Architektur mit Ubuntu 19.10 1

Das Ziel lautet somit, einen WireGuard-Server auf der externen VM aufzusetzen, mit dem sich der WireGuard-Client einer internen VM verbindet, so dass ein VPN zwischen diesen beiden Maschinen entsteht. Insbesondere ist kein Routing des kompletten Internet-Traffics erwünscht, was von Anbietern als “anonymes Surfen” bezeichnet wird – das wäre in diesem Fall sogar kontraproduktiv, da sich die externe VM beim Hosting-Provider eindeutig auf mich als Kunde zurückführen lässt. WireGuard selbst kann jedoch auch diese Aufgabe übernehmen, tatsächlich existieren bereits VPN-Anbieter, die auf WireGuard aufsetzen, und letztlich handelt es sich um die Änderung von zwei Zeilen in einer Konfigurationsdatei, die das Routing ermöglichen.

Eine Mail würde somit von einem Dienst auf einer internen Maschine gesendet und vom internen Mail-Relay aufgenommen. Dieser Postfix-Mailserver läuft in einem Docker-Container auf der “VM intern”. Von dort aus wird die Mail über das WireGuard-VPN auf das externe Mail-Relay – erneut ein Docker-Container, in dem Postfix betrieben wird – weiter geleitet. Dieses Mail-Relay übernimmt dann den weiteren Transport. Für die folgenden Abschnitte spielt diese Anwendung jedoch keine Rolle, da hier die Einrichtung des WireGuard-Servers und -Clients gezeigt werden soll, und diese ist letztlich unabhängig vom jeweiligen Anwendungsszenario.

Installation von WireGuard

Bei der Installation stellt sich zunächst die Frage, aus welchen Paketquellen WireGuard bezogen werden soll. Zwar bietet Ubuntu 19.10 bereits eine recht aktuelle Fassung von WireGuard im Standard-Lieferumfang, jedoch sind die Versionen aus dem PPA (Personal Package Archive) noch einmal aktueller. Momentan werden die Versionsnummern mit 0.0.YYYYMMDD” angegeben, das Datum ist somit in der Versionskennung enthalten. Auf der Website mit Hinweisen zur Installation auf unterschiedlichen Betriebssystemen sind die aktuellen Versionen in grüner Schrift gekennzeichnet, während bei veralteten Versionen rote Schrift sowie eine Warnung angegeben ist. Tatsächlich war zum Zeitpunkt des ersten Besuchs der Seite das Ubuntu-PPA noch als veraltet angegeben – wenige Stunden später war dies jedoch aktualisiert worden, weshalb wiederum die Wahl nicht schwer fiel.

Die folgenden Schritte beziehen sich auf alle Rechner, auf denen WireGuard eingerichtet werden soll, d.h. Server sowie Client bzw. im o.g. Beispiel auf die “VM extern” und die “VM intern”.

Zunächst wird das PPA hinzugefügt:

geschke@demmin:~$ sudo add-apt-repository ppa:wireguard/wireguard

 WireGuard is a novel VPN that runs inside the Linux Kernel. This is the Ubuntu packaging for WireGuard. More info may be found at its website, listed below.

More info: https://www.wireguard.com/
Packages: wireguard wireguard-tools wireguard-dkms

Install with: $ apt install wireguard

For help, please contact <email address hidden>
 More info: https://launchpad.net/~wireguard/+archive/ubuntu/wireguard
Press [ENTER] to continue or Ctrl-c to cancel adding it.

OK:1 https://download.docker.com/linux/ubuntu disco InRelease
OK:2 http://de.archive.ubuntu.com/ubuntu eoan InRelease
Holen:3 http://de.archive.ubuntu.com/ubuntu eoan-updates InRelease [97,5 kB]
Holen:4 http://ppa.launchpad.net/wireguard/wireguard/ubuntu eoan InRelease [15,9 kB]
Holen:5 http://de.archive.ubuntu.com/ubuntu eoan-backports InRelease [88,8 kB]
OK:6 http://security.ubuntu.com/ubuntu eoan-security InRelease
Holen:7 http://ppa.launchpad.net/wireguard/wireguard/ubuntu eoan/main i386 Packages [924 B]
Holen:8 http://ppa.launchpad.net/wireguard/wireguard/ubuntu eoan/main amd64 Packages [928 B]
Holen:9 http://ppa.launchpad.net/wireguard/wireguard/ubuntu eoan/main Translation-en [800 B]
Es wurden 205 kB in 1 s geholt (272 kB/s).
Paketlisten werden gelesen... Fertig

Netterweise werden dabei gleich noch Hinweise über WireGuard und die verfügbaren Pakete angegeben. Danach erfolgt die Installation des WireGuard-Metapackages, das wiederum die Pakete wireguard-dkms für das Kernel-Modul und wireguard-tools für die CLI-Tools beinhaltet:

geschke@demmin:~$ sudo apt install wireguard

Mit der DKMS (Dynamic Kernel Module Support) bezeichneten Technologie werden Kernel-Module automatisch aktualisiert, sobald das System einen neuen bzw. aktualisierten Kernel erhält. Da das WireGuard-Kernel-Modul dafür sowohl bei der Ersteinrichtung als auch bei späteren Updates zunächst kompiliert werden muss, werden bei der Installation alle abhängigen Pakete mit eingerichtet – letztlich wird damit die komplette Entwicklungsumgebung auf jeden WireGuard-Rechner gepackt.

Nach der etwas längeren Installationsphase mit entsprechend vielen Meldungen wird auch der Erfolg der Aktion vermeldet:

Loading new wireguard-0.0.20191127 DKMS files...
Building for 5.3.0-24-generic
Building initial module for 5.3.0-24-generic
Done.

wireguard.ko:
Running module version sanity check.
 - Original module
   - No original module exists within this kernel
 - Installation
   - Installing to /lib/modules/5.3.0-24-generic/updates/dkms/

depmod....

DKMS: install completed.
[...]
wireguard (0.0.20191127-wg1~eoan) wird eingerichtet ...

Das Kernel-Modul ist danach zwar noch nicht geladen, aber zumindest im angegebenen Verzeichnis vorhanden:

geschke@demmin:/etc/wireguard$ ls -l /lib/modules/5.3.0-24-generic/updates/dkms/
insgesamt 264
-rw-r--r-- 1 root root 267208 Dez  3 21:05 wireguard.ko

Bis hierhin verlief die Installation analog zu den zahlreichen Anleitungen, die in den Weiten des Netzes zu finden waren. Zur weiteren Einrichtung werden jedoch mitunter Schritte genannt, die im einfachsten Fall gar nicht notwendig sind. Insbesondere nutzt Ubuntu seit der Version 17.10 zur Konfiguration der Netzwerkschnittstellen das Tool Netplan, das sich auf Konfigurationsdateien im yaml-Format im Verzeichnis /etc/netplan stützt. Vielfach wird in anderen Beiträgen jedoch auf die Konfiguration mittels /etc/network/interfaces eingegangen. Derartige Änderungen sind jedoch inzwischen bzw. im konkreten Fall gar nicht notwendig.

Generierung der Schlüssel und einfache Konfiguration

Zunächst müssen jedoch die Schlüssel auf den beteiligten Rechnern, d.h. Server und Client, eingerichtet werden. Dazu dient das Tool wg, eine Übersicht über die verfügbaren Kommandos zeigt wg --help:

geschke@demmin:~$ sudo wg --help
Usage: wg <cmd> [<args>]

Available subcommands:
  show: Shows the current configuration and device information
  showconf: Shows the current configuration of a given WireGuard interface, for use with `setconf'
  set: Change the current configuration, add peers, remove peers, or change peers
  setconf: Applies a configuration file to a WireGuard interface
  addconf: Appends a configuration file to a WireGuard interface
  syncconf: Synchronizes a configuration file to a WireGuard interface
  genkey: Generates a new private key and writes it to stdout
  genpsk: Generates a new preshared key and writes it to stdout
  pubkey: Reads a private key from stdin and writes a public key to stdout
You may pass `--help' to any of these subcommands to view usage.

Die Generierung des privaten und öffentlichen Schlüssels kann wie folgt kombiniert werden:

geschke@demmin:~$ cd /etc/wireguard/
geschke@demmin:/etc/wireguard$ umask 077
geschke@demmin:/etc/wireguard$ wg genkey | sudo tee privatekey | wg pubkey | sudo tee publickey

Der private- als auch public-Key befindet sich danach im Verzeichnis /etc/wireguard:

geschke@demmin:/etc/wireguard$ ls -la
insgesamt 20
drwxr-xr-x   2 root root   41 Dez  3 22:57 .
drwxr-xr-x 102 root root 8192 Dez  3 21:06 ..
-rw-------   1 root root   45 Dez  3 22:57 privatekey
-rw-------   1 root root   45 Dez  3 22:57 publickey

Die Keys müssen nachfolgend in den Konfigurationsdateien von Server und Client eingetragen werden. Zunächst empfiehlt es sich jedoch, einen gemeinsamen, so genannten “Pre-Shared”-Key zu generieren, der in den Konfigurationsdateien aller beteiligten Rechner Platz findet:

geschke@demmin:/etc/wireguard$ umask 077
geschke@demmin:/etc/wireguard$ sudo wg genpsk > psk.key

Zuletzt müssen die Konfigurationsdateien auf dem Client und Server angelegt werden. Das WireGuard-VPN-Netz lautet 10.11.12.0/24, die IP-Adresse des WireGuard-Server soll die 10.11.12.1 sein, der Client erhält die IP-Adresse 10.11.12.10.

Als Standard für den Namen der Konfigurationsdateien hat sich das Kürzel für das Interface etabliert. Bei Verwendung eines WireGuard-Interfaces lautet daher der Name /etc/wireguard/wg0.conf.

Auf dem Server sieht die entsprechende Datei wie folgt aus:

[Interface]
PrivateKey = [... PRIVATE Key des Servers eintragen ..]
Address = 10.11.12.1/24
ListenPort = 51820
# SaveConfig = true # don't save config in this file automatically, because I want
# to change the config file manually
# IPTables-rules are only necessary if you want to be able to surf the web through the VPN. If you only want a VPN between the machines, you can remove PostUp and PostDown.
# PostUp = iptables -A FORWARD -i wg0 -j ACCEPT; iptables -t nat -A POSTROUTING -o eno1 -j MASQUERADE; ip6tables -A FORWARD -i wg0 -j ACCEPT; ip6tables -t nat -A POSTROUTING -o eno1 -j MASQUERADE
# PostDown = iptables -D FORWARD -i wg0 -j ACCEPT; iptables -t nat -D POSTROUTING -o eno1 -j MASQUERADE; ip6tables -D FORWARD -i wg0 -j ACCEPT; ip6tables -t nat -D POSTROUTING -o eno1 -j MASQUERADE

# Client
[Peer]
PublicKey = [... PUBLIC Key des Clients eintragen ..]
PresharedKey = [... PRESHARED Key eintragen ..]
AllowedIPs = 10.11.12.10/32

Da kein Routing von Internet-Traffic erfolgen soll, sind die iptables-Kommandos deaktiviert, ebenso müssen die Optionen für die Weiterleitung von IP-Paketen net.ipv4.ip_forward=1 bzw.  net.ipv6.conf.all.forwarding=1 in der /etc/sysctl.conf nicht aktiviert werden.

Die Option SaveConfig ist standardmäßig false gesetzt, was in diesem Fall auch erwünscht war. Mit der Einstellung true würden Änderungen, die mit dem Tool wg live durchgeführt werden, in die Datei übernommen, jedoch bin ich eher ein Freund von manuellen Anpassungen.

Der Port kann mit ListenPort frei gewählt werden, ggf. muss in der Firewall der zu nutzende Port freigeschaltet werden. Die Nutzung von Port 51820 hat sich ebenfalls als Standard heraus kristallisiert.

Die Konfigurationsdatei des Clients ist ebenso übersichtlich:

[Interface]
PrivateKey = [... PRIVATE Key des Clients ...]
Address = 10.11.12.10/24 # set client IP to allow traffic from server to client
#SaveConfig = true

# Server
[Peer]
PublicKey = [... PUBLIC Key des Servers ...]
PresharedKey = [... PRESHARED Key ...]
Endpoint = demmin.mushaake.org:51820
AllowedIPs = 10.11.12.0/24
PersistentKeepalive = 25 # Sendet die eigene IP Adresse an den Server

Analog zum Server ist im Bereich [Interface] jedoch der Private Key des Clients einzutragen, ebenso die IP-Adresse des VPN-Netzes, die vom Client genutzt werden soll. Im Abschnitt [Peer] hingegen finden der Public Key des Servers und der gemeinsame Pre-Shared-Key Platz.

Des Weiteren wird der Endpoint angegeben, wobei es sich um einen FQDN handelt, der im Falle der Server-Konfiguration auf eine feste IP verweist, die vom Provider für die VM vergeben wurde. Für weiter gehende Konfigurationen wie Peer-to-Peer oder dynamische IP-Adressen sei an dieser Stelle an die WireGuard-Artikel im ubuntuusers-Wiki verwiesen.

Zur Aufrechterhaltung der Verbindung trotz wechselnder IP-Adresse des Clients sorgt die Option PersistentKeepalive.

Die Rechte der Konfigurationsdateien sollten eingeschränkt werden:

geschke@demmin:/etc/wireguard$ sudo chmod 0700 wg0.conf

Anstatt nun mit dem wg-Tool alles Weitere in einzelnen Schritten durchzuführen, kann das Tool wg-quick genutzt werden, das wiederum die im vorherigen Schritt erstellte Konfigurationsdateien einliest und daraufhin die Einrichtung der Interfaces, Routen etc. vornimmt.

Da WireGuard einen systemd-Service für wg-quick mitbringt, kann dazu einfach systemctl genutzt werden:

geschke@demmin:/etc/wireguard$ sudo systemctl start wg-quick@wg0

Zur Erfolgskontrolle empfiehlt sich ein Blick in den Status:

geschke@demmin:/etc/wireguard$ sudo systemctl status wg-quick@wg0
● wg-quick@wg0.service - WireGuard via wg-quick(8) for wg0
   Loaded: loaded (/lib/systemd/system/wg-quick@.service; disabled; vendor preset: enabled)
   Active: active (exited) since Wed 2019-12-04 20:49:30 CET; 10s ago
     Docs: man:wg-quick(8)
           man:wg(8)
           https://www.wireguard.com/
           https://www.wireguard.com/quickstart/
           https://git.zx2c4.com/WireGuard/about/src/tools/man/wg-quick.8
           https://git.zx2c4.com/WireGuard/about/src/tools/man/wg.8
  Process: 14610 ExecStart=/usr/bin/wg-quick up wg0 (code=exited, status=0/SUCCESS)
 Main PID: 14610 (code=exited, status=0/SUCCESS)

Dez 04 20:49:30 demmin systemd[1]: Starting WireGuard via wg-quick(8) for wg0...
Dez 04 20:49:30 demmin wg-quick[14610]: [#] ip link add wg0 type wireguard
Dez 04 20:49:30 demmin wg-quick[14610]: [#] wg setconf wg0 /dev/fd/63
Dez 04 20:49:30 demmin wg-quick[14610]: [#] ip -4 address add 10.11.12.1/24 dev wg0
Dez 04 20:49:30 demmin systemd[1]: Started WireGuard via wg-quick(8) for wg0.

Gleiches gilt für den Client:

geschke@doelitz:/etc/wireguard$ sudo systemctl start wg-quick@wg0
geschke@doelitz:/etc/wireguard$ sudo systemctl status wg-quick@wg0
[...]
Dez 04 20:50:29 doelitz wg-quick[14470]: [#] ip -4 route add 10.11.12.0/24 dev wg0
Dez 04 20:50:29 doelitz systemd[1]: Started WireGuard via wg-quick(8) for wg0.

Damit sollten sich Client und Server nun über die jeweilige gegenseitige IP-Adresse im VPN erreichen können – tatsächlich funktioniert genau dies wie erhofft und erwünscht:

geschke@doelitz:~$ ping 10.11.12.1
PING 10.11.12.1 (10.11.12.1) 56(84) Bytes Daten.
64 Bytes von 10.11.12.1: icmp_seq=1 ttl=64 Zeit=23.6 ms
64 Bytes von 10.11.12.1: icmp_seq=2 ttl=64 Zeit=21.9 ms
64 Bytes von 10.11.12.1: icmp_seq=3 ttl=64 Zeit=22.2 ms
[...]

geschke@demmin:/etc/wireguard$ ping 10.11.12.10
PING 10.11.12.10 (10.11.12.10) 56(84) Bytes Daten.
64 Bytes von 10.11.12.10: icmp_seq=1 ttl=64 Zeit=23.2 ms
64 Bytes von 10.11.12.10: icmp_seq=2 ttl=64 Zeit=22.6 ms
[...]

Zur Kontrolle gibt der Aufruf des Kommandos wg ohne Parameter den Status aus:

geschke@doelitz:~$ sudo wg
interface: wg0
  public key: XXXXXXX
  private key: (hidden)
  listening port: 45794

peer: XXXXXXX
  preshared key: (hidden)
  endpoint: 2.56.98.161:51820
  allowed ips: 10.11.12.0/24
  latest handshake: 1 minute, 16 seconds ago
  transfer: 348 B received, 532 B sent
  persistent keepalive: every 25 seconds

Zu guter Letzt sollte der systemd-Dienst noch dauerhaft aktiviert werden, damit das WireGuard-VPN auch einen Reboot übersteht:

geschke@demmin:/etc/wireguard$ sudo systemctl enable wg-quick@wg0
Created symlink /etc/systemd/system/multi-user.target.wants/wg-quick@wg0.service → /lib/systemd/system/wg-quick@.service.

Wie immer muss dies natürlich auf Client und Server ausgeführt werden.

Vorläufiges Fazit

Insgesamt war das VPN mit WireGuard wesentlich schneller aufgesetzt als mit OpenVPN. Einen Benchmark-Test habe ich zwar nicht durchgeführt, aber es fühlt sich subjektiv performanter an, insbesondere was den Verbindungsaufbau anbetrifft. Zur Verwendung im oben genannten Szenario mussten nur noch die DNS-Einträge sowohl im heimischen Netzwerk als auch auf den DNS-Servern für die genutzte Domain eingerichtet werden. Schließlich soll im Mail-Pfad kein “unknown [10.11.12.10]” auftauchen, sondern die realen, wenngleich internen Hostnamen.

WireGuard hat bereits ein Versions-Update gut überstanden und läuft nach wie vor stabil. Es bleibt zu hoffen, dass sich WireGuard- und Kernel-Entwickler in Kürze einigen werden, so dass das zentrale Modul Bestandteil des Linux-Kernels wird.

Ein Gedanke zu „VPN mit WireGuard in einer Client-Server-Architektur mit Ubuntu 19.10“

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert

Tags: