Heute möchte ich darüber berichten, was für ein großartiges Tool wireguard ist. Ich beschreibe hier, was es macht, wie man es konfiguriert und welche Möglichkeiten sich daraus ergeben.

Wireguard wird gerne als das neue, schnelle VPN des Linux Kernels beschrieben. Dabei gibt es aber zwei Probleme. Patches liegen für den mainline Linux Kernel schon seit einiger Zeit vor. Dennoch dauern die Diskussionen um eine Aufnahme weiter an, da wireguard eine neue crypto-api einführen möchte. Zweitens vermuten Menschen unter VPN eine Lösung, die einen Client mit einem Netz oder zwei Netze untereinander verbindet, dies leistet wireguard aber gar nicht von Haus aus.

Was macht wireguard?

WireGuard® is an extremely simple yet fast and modern VPN that utilizes state-of-the-art cryptography. It aims to be faster, simpler, leaner, and more useful than IPsec, while avoiding the massive headache.

wireguard.com

Die wireguard Entwickler sind da schon etwas präziser, was die Software macht. Sie stellt eine Punkt-zu-Punkt Verbindung zwischen zwei Interfaces zweier an das Internet angeschlossener Geräte her. Die Authentifizierung erfolgt dabei mit einem public/private Key-Verfahren ähnlich zu SSH. Dabei kommen moderne, gut auditierte Kryptofunktionen wie Noise protocol framework, Curve25519, ChaCha20, Poly1305, BLAKE2, SipHash24, HKDF zum Einsatz. Und diese werden auch automatisch ohne Benutzerinteraktion mit sicheren Einstellungen benutzt.

Mit OpenVPN gemein hat wireguard, dass es sich genauso einfach und komfortabel durch (NAT-)Firewalls durchschleusen lässt. Ein einzelner, frei konfigurierbarer UDP Port reicht hier aus.

Und das schließt den Funktionsumfang für das Tool auch schon ab.

wireguard installieren

Später wird es genügen, auf jedem unixoiden System, die „wireguard-tools“ zu installieren und das mitgelieferte Kernelmodul zu laden. Solange dies nicht der Fall ist, muss man je nach Distribution etwas basteln. Fedora hat es bereits in RPM Fusion drin, für die meisten andere Systeme findet sich ein Fingerzeig auf der Webseite des Projekts. Bei Debian und Raspbian kann man sich das Paket gut aus unstable pinnen.

Den Raspberry Pi erwähne ich nicht umsonst, denn darauf teste ich wireguard derzeit als VPN Gateway. Insbesondere möchte ich die beworbene, hohe Geschwindigkeit testen. Hier gibt es allerdings zu beachten, dass man den Kernel der Raspbian Paketquellen verwendet und nicht jenen, den rpi-update zieht. Für letzteren kann man sich zwar auch die Quellen und Header besorgen, allerdings bekam ich so immer ein angeblich nicht zur Architektur passendes Kernelmodul (.ko) raus.

[ 2422.674108] wireguard: version magic '4.19.30+ mod_unload modversions ARMv6 p2v8 ' should be '4.19.30-v7+ SMP mod_unload modversions ARMv7 p2v8 '

wireguard konfigurieren

Zuerst generieren wir uns für jedes teilnehmende Gerät einen Satz aus public und private key. Diese Schlüssel können wir auf einem beliebigen Gerät erstellen. Die Dateien müssen nicht auf den beteiligten Systemen liegen bleiben, weil die enthaltenen Strings in die Konfigurationsdateien geschrieben werden. Desgalb sollten die Configs auf dem System vor Zugriffen durch unprivilegierte Nutzer geschützt werden.

root@battery:~ $ mkdir wgkeys
root@battery:~ $ cd wgkeys  
root@battery:~/wgkeys $ wg genkey > server_private.key  
Warning: writing to world accessible file.
Consider setting the umask to 077 and trying again.

root@battery:~/wgkeys $ wg pubkey > server_public.key < server_private.key
root@battery:~/wgkeys $ wg genkey > client1_private.key  
Warning: writing to world accessible file.
Consider setting the umask to 077 and trying again.
root@battery:~/wgkeys $ wg pubkey > client1_public.key < client1_private.key
root@battery:~/wgkeys $ ls
client1_private.key client1_public.key server_private.key server_public.key

Nun können wir auf dem Server die Konfigurationsdatei unter /etc/wireguard/wg0.conf erstellen.

[Interface]
Address = 192.168.128.1/24,fd16:b3a5:697e:5324::1/64
ListenPort = 51820
PrivateKey = <server-private-key>

[Peer]
# Client 1
PublicKey = <client1-public-key>
AllowedIPs = 192.168.128.10, fd16:b3a5:697e:5324::10

[Peer]
# Client 2
PublicKey = <client2-public-key>
AllowedIPs = 192.168.128.20, fd16:b3a5:697e:5324::20

Auf dem Client kommt die Datei an den gleichen Ort.

[Interface]
Address = 192.168.128.11/24,fd16:b3a5:697e:5324::11/64
DNS = 192.168.125.1
PrivateKey = <client1-private-key>

[Peer]
# Battery
PublicKey = <server-public-key>
Endpoint = vpn.commander1024.de:51820
AllowedIPs = 192.168.128.0/24, fd16:b3a5:697e:5324::0/64, 192.168.xxx.0/24, 192.168.125.1/32, 192.168.yyy.0/24, 2001:xyz:xyaz:xxx::/64, 2001:xyz:xyz:yyy::/64, 

# This is for if you're behind a NAT and
# want the connection to be kept alive.
PersistentKeepalive = 25

wireguard starten und Status überprüfen

Wenn der Raspberry Pi in einem Netz hinter der Firewall oder dem „Router“ steht, muss dort selbstverständlich der gewählte Port des Servers noch an seine internen IPs weitergeleitet werden. In diesem Fall wäre dies der Port UDP 51820. Das Stichwort in den meisten Heimroutern sollte „Port-forwarding“ sein.

root@battery:~# wg-quick up wg0
mscholz@Warrior:~# sudo wg-quick up wg0

Nun können wir den Status des Dienstes sowie der (nicht) verbundenen Peers mit dem tool wg abrufen.

root@battery:~# wg
interface: wg0
  public key: <server-public-key>
  private key: (hidden)
  listening port: 51820

peer: <client1-public-key>
  endpoint: 109.91.240.102:12813
  allowed ips: 192.168.128.11/32, fd16:b3a5:697e:5324::11/128
  latest handshake: 3 seconds ago
  transfer: 66.75 KiB received, 400.19 KiB sent

peer: <client2-public-key>
  endpoint: 109.40.3.183:3779
  allowed ips: 192.168.128.21/32, fd16:b3a5:697e:5324::21/128
  latest handshake: 39 seconds ago
  transfer: 676 B received, 1.51 KiB sent

peer: <client3-public-key>
  allowed ips: 192.168.128.10/32, fd16:b3a5:697e:5324::10/128


mscholz@Warrior:~# sudo wg
interface: wg0
  public key: <client1-public-key>
  private key: (hidden)
  listening port: 51244

peer: <server-public-key>
  endpoint: 109.91.240.102:51820
  allowed ips: 192.168.128.0/24, fd16:b3a5:697e:5324::0/64, 192.168.xxx.0/24, 192.168.125.1/32, 192.168.yyy.0/24, 2001:xyz:xyaz:xxx::/64, 2001:xyz:xyz:yyy::/64
  latest handshake: 25 seconds ago
  transfer: 156.29 KiB received, 31.00 KiB sent
  persistent keepalive: every 25 seconds

Installation absichern und Autostart einrichten

Zuerst schützen wir die Daten vor Zugriff durch andere lokale Benutzer.

root@battery:~# chown -R root:root /etc/wireguard/
root@battery:~# chmod -R og-rwx /etc/wireguard/*

Nun aktivieren wir den Autostart des Dienstes durch systemd, falls gewünscht.

root@battery:~# systemctl enable wg-quick@wg0.service

Starten und Stoppen kann man wireguard nun wie jeden anderen systemd Service.

root@battery:~# systemctl start wg-quick@wg0.service
root@battery:~# systemctl stop wg-quick@wg0.service

Nun können sich Client und Server jeweils gegenseitig pingen. Nicht aber die Clients untereinander oder mit anderen Netzen. Alles weitere müssen nun andere Tools und Systemdienste erledigen.

Routing und NAT Setup

Dazu schalten wir IP-Fowarding für IPv4 und IPv6 ein:

root@battery:~ $ sysctl net.ipv4.ip_forward=1
net.ipv4.ip_forward = 1
root@battery:~ $ sysctl net.ipv6.conf.all.forwarding=1 
net.ipv6.conf.all.forwarding = 1

Um die Änderungen permanent zu machen, ändern wir diese Zeilen in /etc/sysctl.d/99-sysctl.conf:

# Uncomment the next line to enable packet forwarding for IPv4
net.ipv4.ip_forward = 1

# Uncomment the next line to enable packet forwarding for IPv6
#  Enabling this option disables Stateless Address Autoconfiguration
#  based on Router Advertisements for this host
net.ipv6.conf.all.forwarding=1

Mit diesen Voraussetzungen könnte man jetzt weitermachen und ein geroutetes Layer 3 Netzwerk aufspannen. Dies halte ich persönlich für den Königsweg. Im besten Fall auch direkt mit öffentlichen IPv6 Adressen im VPN. Die generierten ULA Prefixe hier im Beispiel können nicht ins Internet gerouted werden. Für den ausschießlichen Zugriff auf interne Systeme eignen sie sich aber gut. Erstellen kann man solche Netze überall mit Generatoren wie diesem hier.

NAT

Für einfachen, schnellen Remotezugriff auf ein Netzwerk geht es vielleicht am schnellsten mit NAT. Ich rate allerdings in fast allen Situationen davon ab, NAT an Stellen zu verwenden, wo es nicht absolut notwendig ist. Auf dem Server reicht es aus, diese 2 Zeilen der /etc/wireguard/wg0.conf einzufügen. Am besten vor den Peers:

PostUp   = iptables -A FORWARD -i %i -j ACCEPT; iptables -A FORWARD -o %i -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
PostDown = iptables -D FORWARD -i %i -j ACCEPT; iptables -D FORWARD -o %i -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE

Brücken schlagen?

Selbstverständlich wäre es ebenfalls denkbar, mit Bridges herumzuspielen. Aber auch dies ist mit Vorsicht zu genießen. Steigen die Gerätezahlen in dem gemeinsamen Layer 2 Netz, nimmt der Broad- und Multicasttraffic alsbald messbar störende Volumina an. Sind die einzelnen Blasen dann auch noch latenzmäßig schlecht oder unterschiedlich gut angebunden, potenzieren sich die Probleme.

BGP, OSPF, MPLS, IS-IS, Link-Aggregation?

Um BGP oder OSPF durch wireguard Tunnel zu sprechen, braucht es gar keine Zusatzkonfiguration des wg* Interfaces an jeder Seite. Bekäme man das ISO-Protokoll als Adressfamilie auf das wg0 Interface, wäre auch IS-IS eine Option. Ebenso wäre denkbar, mehrere (unterschiedliche) Internetverbindungen mit Wireguard zu einem Aggregations-Server im Rechenzentrum zu verbinden. So könnte man mit anderen Techniken die Bandbreite bündeln und Ausfallsicherheit schaffen.

Auch die ersten kommerziellen VPN-Anbieter bieten bereits Konfigurationsoptionen mit wireguard an, einige allerding noch im Beta Stadium.

Der Möglichkeiten sind hier kaum Grenzen gesetzt.

Performance!

Wireguard ist schnell. Wireguard ist extem schnell! Auf durchschnittlichen Desktops und Notebooks erreicht man locker die 1Gbps Marke, moderne CPUs lassen sich kaum beeindrucken. Hier sind bestimmt auch Vielfache Gbit/s drin. Ein Raspberry Pi 3 B+ kommt durchaus an die 100Mbit/s heran. Im Umkehrschluss könnte dies auch zur Folge haben, dass mobile Geräte wie Handys und co. geringeren Akkuverbrauch im Vergleich zu anderen Lösungen haben könnten.

Ist das sicher?

Verwendet werden scheinbar weitgehend etablierte Techniken, die schon den einen oder anderen Audit bekommen haben. Auf den Code haben auch schon einige Leute draufgeguckt, auch namhafte aus der Szene. Bei den Diskussionen auf der Linux Kernel Mailingliste dreht es sich hauptsächlich um kleinere Reibungspunkte, statt um die Softwarequalität selbst. Ob das Einführen einer neuen crypto api so fürchterlich ist, wie einige meinen, vermag ich nicht abzuschätzen. Fest steht aber, dass eine gesunde Portion Skepsis gegenüber neuer Kryptographiesoftware angebracht sein sollte. Die findigen Hacker hatten ja noch gar nicht so viel Gelegenheit, das System so gründlich zu testen – zumal wireguard auch noch in einem einigermaßen regen Entwicklungsprozess steckt.