Freitag, 11. Februar 2022

Wireguard - verbundene Netzwerke

Einfach eine vor konfigurierte Box in das Netzwerk des Freundes oder Kunden stecken und dann ruhig und sicher dieses Netzwerk von der Ferne überwachen und administrieren können - das war die Idee. Eine Box, die der andere jederzeit entfernen und auch wieder stecken kann. Man muss im anderen Netzwerk nichts weiter tun

  • keine Manipulation im Netzwerk, 
  • keine Portfreigabe,
  • kein Router / Fritzbox VPN-Verbindung einrichten. 

Schnell, transparent und einfach soll es auch noch sein! IPv4 und IPv6 sollen funktionieren.

Es braucht nicht viel: Hardware: einen Raspberry Pi als Client und eine debian Maschine (virtuell oder physisch) im eigenen Netzwerk. Software: wireguard, PiVPN, etwas gewusst wie. 

Funktionen

Ich habe zunächst alles nur mit IPv4 getestet, d.h. man braucht "zu Hause" eine von überall erreichbare IPv4 Adresse. Um zu prüfen ob man eine solche Adresse hat, kann man einfach die IPv4 Adresse angezeigt im Router mit dieser im Browser vergleichen:

https://v4.ident.me/

Die hier beschriebene Einrichtung ermöglicht folgende Funktionen:

Der VPN Tunnel endet auf dem VPN Server im eigenen Netzwerk. Ein PC zur Administration muss entweder: 

  • eine Route in das Client Netzwerk (hinter dem VPN Tunnel) haben (manuell aktiviert),
  • oder er muss selbst als VPN Client am VPN Server verbunden sein,
um das Clientnetzwerk zu erreichen. Der Zugang könnte noch mit einem Firewall Eintrag gesichert werden.

Der VPN Tunnel auf Client Seite endet auf der dortigen Box. Aus dem Tunnel ist das Client Netzwerk per NAT erreichbar. In die andere Richtung kann kein Gerät des Clientnetzwerkes eine selbstständige Verbindung aufbauen.

Hinweis: Wireguard an sich unterscheidet nicht zwischen Server und Client, der VPN Tunnel ist ein separates Netzwerksegment. Es entsteht so eigentlich immer eine Site to Site Verbindung.

Server einrichten

Für dieses Beispiel habe ich als Server ein debian 11 basiertes System (debian 11, Raspberry OS ... ) verwendet auf dem wireguard mit Hilfe von PiVPN installiert wird.

Beim interaktiven Setup von PiVPN müssen ein paar Parameter auch für den späteren Betrieb angegeben werden. Diese Einstellungen können jederzeit in der Datei /etc/pivpn/wireguard/setupVars.conf geändert werden. Sie dient als Vorlage für die PiVPN Befehle (Scripte).

curl -L https://install.pivpn.io | bash

Damit der VPN Server über das Internet erreichbar ist, muss eine eingehende UDP Port (Standard 51820) Freigabe im Router aktiviert werden. 

Es ist auch möglich, Wireguard als Docker Container zu betreiben, allerdings bietet Docker im Standard Setup kein IPv6.

Client einrichten

Auf den Client wird Raspberry Pi OS Lite installiert - nach Belieben mit dem Raspberry Pi Imager interaktiv oder per Text- bzw. Skriptdatei

  • ssh aktivieren, 
  • WLan Zugang Konfiguration oder Ethernet Adapter verwenden und
  • Pi ins lokale Netz bringen
  • System aktualisieren, Grundeinrichtung (siehe Skript)

Nach dem Start per ssh anmelden und wireguard installieren. Bei anderen Systemen als Raspberry OS kann es sein, dass noch Tools fehlen:

sudo apt install wireguard
sudo apt install iptables openresolv # nur falls nicht Raspberry OS

VPN testen

Am VPN Server kann man eine VPN Client Konfiguration (Beispiel my1Client.conf) erstellen und auf den Client kopieren. Der letzte Befehl zeigt die vorhanden Clients und den Status an. Nachdem der Client verbunden ist, kann man damit leicht den Erfolg/Status prüfen. 

client='my1Client'
pivpn -a -n ${client}
scp configs/${client}.conf user@host:
pivpn -c

Jetzt den Client testweise per VPN verbinden (das funktioniert auch im eigenen Netzwerk)

client='my1Client'
wg-quick up ./${client}.conf
traceroute 8.8.8.8
wg-quick down ./${client}.conf

Für einen normalen VPN Zugang zum eigenen Netzwerk wäre man hier fertig. Wireguard ist für alle gängigen Systeme verfügbar, wie schon gesagt: Client oder Server unterscheidet nur der Typ des  Verbindungsaufbaus.

Der Client hat jetzt eine Default Route in den VPN Tunnel, jeder Verkehr wird darüber geleitet. Vom Server erreicht man den Client derzeit nur über die IP des Tunnels (10.6.0.x). 

Der Server hat keine Route ins Client Netzwerk und es gibt noch keinen Zugriff auf die Netzwerkumgebung im Clientnetzwerk, das müssen wir ändern. Allerdings macht dies erst wirklich Sinn, wenn sich der Client in einem anderen Netzwerk als der Server befindet.

Feinkonfiguration

Die Konfigurationsdatei hat zwei Abschnitte [Interface] [Peer]. Beim VPN Server taucht der [Peer] Abschnitt mehrfach, für jeden aktivierten Client auf. Für die Netzwerkverbindung sind vor allem zwei Einträge in der conf Datei von Bedeutung:

[Interface]
...
DNS = 10.x.x.1

[Peer]
...
AllowedIPs = 0.0.0.0/0

DNS bestimmt die Namensauflösung und damit auch - ob lokale Netzwerknamen aufgelöst werden können. Vorsicht mit diesem Eintrag: Im Zweifelsfall sollte man ihn besser weglassen!

AllowedIPs bestimmt das Routing und damit die Bereiche für die der Tunnel verwendet wird. Besonders den Admin PC sollte man hier aufmerksam konfigurieren, um sich nicht aus dem eigenen Netzwerk auszusperren.

Client

Der Peer öffnet in unserem Scenario den Tunnel zum Server, bei Inaktivität wird der Tunnel geschlossen. Damit der Tunnel aktiv bleibt, ergänzen wir die conf Datei um einen Eintrag:

echo "PersistentKeepalive = 25" >>./${client}.conf

Der Client bekommt noch eine NAT Konfiguration, damit der Zugriff auf andere Hosts im Clientnetzwerk transparent möglich wird. Man kann die Einträge direkt in den [Interface] Abschnitt eintragen, da mir das etwas unübersichtlich ist, habe ich es mit einem Shell Skript gelöst. 

Der folgende Code mit HereDoc erzeugt dieses Skript an Ort und Stelle. Vor der Ausführung muss man noch das Interface ermitteln:

ip addr | awk '/state UP/ {print $2}' | sed 's/.$//'

und entsprechend setzen! (meine Codeboxen sind direkt editierbar)

cat <<'EOI' | sudo tee /etc/wireguard/wg0.sh
#!/bin/sh
interface='eth0' # eth0 / wlan0 - change it to the real Interface Name
if [ "$2" = "A" ] ;then on=1;else on=0;fi
sysctl -q net.ipv4.ip_forward=$on
iptables -$2 FORWARD -i $1 -j ACCEPT
iptables -$2 FORWARD -o $1 -j ACCEPT
iptables -t nat -$2 POSTROUTING -o $interface -j MASQUERADE
EOI

Die Client conf Datei muss im Abschnitt  [Interface] am Ende (vor [Peer] ) um diese beiden Zeilen mit dem Editor ergänzt werden. 

PostUp= sh /etc/wireguard/wg0.sh %i A
PostDown= sh /etc/wireguard/wg0.sh %i D

Oder man erledigt auch diesen Schritt mit einem Skript:

cmd='sh \/etc\/wireguard\/wg0.sh %i'
sed -i "s/^\[Peer\]$/PostUp= $cmd A\nPostDown= $cmd D\n\n\[Peer\]/" ./${client}.conf


Automatischer Start

Jetzt muss nur noch die Konfiguration an Ort und Stelle kopiert und der Start automatisiert werden. Dazu nehmen wir einfach die installierte systemd unit wg-quick@wg0. Hinweis: @wg0 wirkt als Übergabeparameter! Es können so mehrere Interfaces automatisch gestartet werden.

Der erste Start erfolgt interaktiv, danach wird der Dienst gestartet und bei Erfolg aktiviert. 

Achtung: mehrfaches Starten gleicher Konfigurationen führt zu eigenartigen Ergebnissen - bis hin zu Systemabstürzen des Clients. Vor dem nächsten Schritt unbedingt prüfen das nicht bereits eine VPN Verbindung aktiv ist! Schritt für Schritt:

WG_CONF=my1Client
WG_IF=wg0
### prüfen ob ein Interface aktiv ist
sudo wg show 
### wenn nichts aktiv conf kopieren und testen
sudo cp ${WG_CONF}.conf /etc/wireguard/${WG_IF}.conf
wg-quick up ${WG_IF}
wg-quick down ${WG_IF}
### wenn der Test erfolgreich war: aktivieren und starten 
sudo systemctl enable --now wg-quick@${WG_IF}

DNS - Namensauflösung

Achtung! Nachträgliche Korrekturen erfolgen in der client.conf.

Entweder der Eintrag DNS = IP im Interface Abschnitt einfach aus kommentiert oder geändert.

Am Wireguard VPN Server (pivpn, docker) kann für die Clientkonfiguration als Standard der DNS Server des Servernetzwerkes gesetzt werden. Die IP Adresse (z.B. 10.6.0.1) des wireguard Server im Tunnel Segment ist meist keine gute Option, es sei denn, da läuft ein DNS Server.

  • pivpn
    • In den Installation Settings der Eintrag  pivpnDNS1= 
  • docker
    • Die Umgebungsvariable PEERDNS

Mit Namen aus dem Clientnetz vom Admin Netzwerk aus zu arbeiten, wird aufwendig. Man müsste mit FQDN, unterschiedlichen Zonen und Delegation im DNS Server arbeiten. 

Server

Der Server muss noch eine Route ins Clientnetzwerk erhalten. Das erledigt der Eintrag AllowedIPs im Peer Abschnitt des jeweiligen Clients in der Server Konfiguration /etc/wireguard/wg0.conf

Achtung! Das Clientnetzwerk kann das gleiche Netzwerksegment wie der Server haben, es kann auch mehrere Clientnetzwerke mit gleichem IP Segment geben. Dank separatem Tunnelsegment kann man in dem Fall aber nur über die Tunneladresse auf den VPN Client zugreifen! Ein Zugriff auf einzelnen IP Adressen wäre möglich, die Konfiguration ist aber sehr Anspruchsvoll! Das Segment des Servers darf in keinem Fall komplett in die AllowedIPs wie nachfolgenden gezeigt eingetragen werden!

Identifizieren kann man den richtigen Abschnitt durch die Kommentarzeilen und der jeweiligen Tunnel IP Adresse. Mehrere Einträge erfolgen kommagetrennt in der CIDR Notation für Netzmasken

Beispiel:

  • 10.6.0.3/32 - Client IP des VPN Tunnels
  • 192.168.12.0/24 - Subnet Adresse des Clientnetzwerkes

Der Eintrag kann manuell geändert werden:

vorher AllowedIPs = 10.6.0.3/32
nachher AllowedIPs = 10.6.0.3/32,192.168.12.0/24

Damit der Eintrag wirksam wird: muss man das VPN Tunnel Interface neu starten, dabei werden bestehende Verbindungen unterbrochen!

sudo systemctl restart wg-quick@wg0
Nur zur Info: Die Konfiguration neu anwenden mit reload erzeugt keinen neuen Routing Eintrag, da hier wg syncconf wg0 <(wg-quick strip wg0) ausgeführt wird und wg kann Routing und Iptables usw. nicht behandeln. 
sudo systemctl reload wg-quick@wg0

Beides Zusammen geht auch per Skript (Hinweis auf subnet weiter oben beachten):

ip=10.6.0.3
subnet=192.168.12.0
sudo cp /etc/wireguard/wg0.conf /etc/wireguard/wg0.save    # Sicherheitskopie erzeugen
sudo sed -i "s/$ip\/32/$ip\/32,$subnet\/24/" /etc/wireguard/wg0.conf
sudo systemctl restart wg-quick@wg0

Zugriff vom Admin-Netzwerk 

Der wireguard VPN Server erreicht jetzt das Clientnetzwerk. Damit man von einer Station aus dem eigenen Netzwerk auf das Clientnetzwerk zugreifen kann, gibt es zwei Möglichkeiten:

  1. VPN Verbindung aufbauen, das funktioniert auch "lokal". Das ist vielleicht die homogenste und einfachste  Lösung, da es egal ist, ob man "zu Hause" oder woanders in einem Netzwerk sitzt. Hier muss man je nach Einsatzfall eventuell auch nacharbeiten, Stichworte split tunnel, DNS, AllowedIPs.
  2. Eine IP Route zum wireguard VPN Server erzeugen. Das hab ich nicht hinbekommen, wenn der wireguard VPN Server als Docker Container läuft.

Windows

route add 192.168.12.0 mask 255.255.255.0 192.168.178.11

Für Powershell habe ich hier ein kurzes Script als Wrapper für den Aufruf einer Admin Umgebung.

Linux

route add -net 192.168.12.0 netmask 255.255.255.0 gw 192.168.178.11 dev eth0

Danach kann jede Anwendung auf die IP Adresse des Clientnetzwerkes zugreifen - geschafft!

Wireguard administrieren

Wireguard-tools bringt im Wesentlichen zwei "Admin Befehle":  wg und wg-quick. Beide liefern mit -h Hilfe, auch zu den sub Befehlen mit danach angehängtem -h . Der contrib Ordner wird lokal nach /usr/share/doc/wireguard-tools/examples/ installiert, dort findet man scripts und Programmierbeispiele. 

Die Beschreibung der conf Dateien ist in beiden Manpage Beschreibungen enthalten. 

Will man sich mal anschauen, was das Interface gerade "tut", hilft einem dieser Befehl

sudo wg show wg0

Neue Clientkonfigurationen erstellen

  • wireguard pure - mit dem wg Utility 
  • PiVPN - hat den pivpn -a Befehl, mit dem man eine Konfiguration erstellen und auch als QR Code anzeigen kann.
  • wireguard-docker  - hat die Environment Variable PEERS= , beim Start/recreate des Containers werden die conf Dateien und die qr Codes im Ordner /config abgelegt. 

Client Konfiguration auf den Client bringen

Für Mobilgeräte kann man den QR Code anzeigen und scannen.

  • qrencode -t ansiutf8 -r peer_name.conf
  • pivpn -qr 
  • docker exec -it wireguard /app/show-peer name

Auf den Windows Client sollte man die Textdatei über einen sicheren Weg bringen (scp, USB Stick).

Weitere Informationen findet man in der jeweiligen Doku bzw. Hilfe

Problemfall

Es wird zum Verbindungsabbruch beim Client kommen, wenn Server- und Clientseitig NAT verwendet wird (Regelfall) und auf der Serverseite der Router neu gestartet wird bzw. anderweitig eine neue IP bekommt. Siehe dazu diese Erklärung.

Achtung: Wird durch den wireguard Client ein DNS Server Eintrag gesetzt, kann es passieren, dass dies der einzige DNS Server Eintrag ist. In dem Fall kann bei Wegfall der VPN Verbindung auch der Hostname des wireguard Server nur aufgelöst werden, wenn dieser DNS Server erreichbar ist! Diese Konfiguration sollte vermieden werden!

Um zu verhindern, dass man den autarken Client dauerhaft verliert, muss man diesen Zustand am Client ermitteln und das Interface neu verbinden. Ich habe dazu zunächst ein simples Script erstellt und dies über crontab im 5 min Abstand ausgeführt. Das Script und eine kurze Erklärung findet man auf meiner GitHub Seite als keepwg.sh .

Alternativ kann man das Script reresolve-dns.sh aus dem oben erwähnten contrib Ordner verwenden und z.B. so wie hier gezeigt einsetzen. Ich habe daraus mal ein komplette Einzeiler Setup gemacht:

wget -qO- https://raw.githubusercontent.com/heinz-otto/scripts/master/Bash/install-wireguard-reresolve-dns.sh | sudo bash -

Vorteil: Dieses Script handelt filigraner und prüft die einzelne Verbindungen separat (falls mehrere existieren). Es startet nicht einfach das komplette wg Interface neu.

Schreibschutz

Eventuell wird mit der kleinen Box nicht schonend umgegangen, es empfiehlt sich die SD Card vor unbeabsichtigtem Schreibvorgängen zu schützen. Eine Möglichkeit ist das Overlay Filesystem, welches sich mit raspi-config Menügeführt einrichten lässt: 4 Performance Options / P3 Overlay File System /Yes ...

Danach muss man neu starten. Vor Veränderungen (Installation, Updates) muss man den Vorgang rückgängig machen. Hat man auch die Boot Partition mit Schreibschutz versehen, muss man zweimal neu starten. Nach dem Update muss man das Overlay System wieder aktivieren. 

Trouble bei der Verbindung?

Das Tool tcpdump leistet Hilfe die Pakete zu orten:

sudo tcpdump -i eth0 port 51820

Die Doku ist für mich sehr "zart" - hier gibt es ein Tutorial, da gelingt mir aber auch nicht alles!?

Mit netcat kann man einfach mal UDP Pakete erzeugen

nc -z -v -u hostnameOderIP 51820

Mit beiden Befehlen ist es mir zumindest gelungen die Pakete durch den Router zu verfolgen. 

Routing und NAT kontrollieren:

sysctl net.ipv4.ip_forward
iptables -t nat -L

NAT Tutorial 


Client und Server tauschen

Hier wird noch gearbeitet!

Durch einen Providerwechsel musste ich die Richtung tauschen und aus einem Client einen Server sowie aus einem (Docker) VPN Server einen Client zu machen. Es sollte keiner etwas merken. 

Auf dem VPN Client hatte ich ja wireguard pure installiert. Ich musste mich tiefer mit der Konfiguration beschäftigen, sehr geholfen hat mir dabei u.a. dieser Artikel. Es traten ein paar Konfigurationen "unter der Decke" zu Tage:

  • pivpn arbeitet mit preshared keys, der docker Server nicht.
  • pivpn aktiviert ip forwarding (routing) und erzeugt einen festen NAT Eintrag in IPTables. Damit wird die Eigenschaft erzeugt, dass der VPN Server eine x-beliebige Maschine im Netzwerk sein kann und vom eingewählten Client das gesamte Netzwerk erreicht wird.

Nur die conf tauschen ist es also nicht! 

Der bisherige Client 

... müsste entweder ip forwarding aktiviert (sed s/#net.ipv4.ip_forward=./net.ipv4.ip_forward=1/ /etc/sysctl.conf) und einen iptables Eintrag statisch (iptables -t nat -A POSTROUTING -s 10.13.13.0/24 -o eth0 -m comment --comment wireguard-nat-rule -j MASQUERADE) bekommen, oder beides wird dynamisch mit wg-quick in der Config über PostUp und PostDown Einträge erzeugt.

sysctl -w net.ipv4.ip_forward=1

Ausgangspunkt ist der Inhalt der docker/config/wg0.conf Datei vom (Docker) Server. 

Vorsicht! Unbedingt vor dem ersten Test die AllowedIPs = Zeilen kontrollieren und erstmal zusätzliche Einträge entfernen damit man sich nicht aussperrt.

Drei Zeilen ändern und eine hinzufügen

Address = 10.13.13.1/24
# MTU = 1420 # ist die default Einstellung von wireguard
PostUp = iptables -t nat -A POSTROUTING -s 10.13.13.0/24 -o eth0 -m comment --comment wireguard-nat-rule -j MASQUERADE
PostDown = iptables -t nat -D POSTROUTING -s 10.13.13.0/24 -o eth0 -m comment --comment wireguard-nat-rule -j MASQUERADE

DynDNS Eintrag für den Endpunkt im Router umkonfigurieren.

conf zur wg0.conf machen und neu starten

Der bisherige Server

  1. Docker Container stoppen und wireguard auf dem Host installieren.
  2. Die conf vom bisherigen Client holen.
  3. AllowedIPs = anpassen/korrigieren.
  4. conf zur wg0.conf machen und neu starten

Erklärung zu MTU.

Backup Restore

Hier ist beschrieben wie man eine pivpn Installation per Backup und Restore auf einen anderen Server transferieren kann. Auch hier hat man das Problem, dass die NAT Regel anschließend nicht passt, weil pivpn neuerdings automatisch ein IP4 Segment wählt und nicht mehr stur 10.6.0.0 wählt. Trick: pivpn nicht interaktiv sondern mit eine conf Datei nicht interaktiv installieren.

iptables korregieren:

sudo iptables -t nat -S|grep wireguard

die Zeile mit  sudo iptables -t nat -D (anstatt -A) wieder anwenden und speichern, oder mit -R ändern.

sudo iptables -t nat -R POSTROUTING 1 ...
sudo iptables-save | sudo tee /etc/iptables/rules.v4

Literatur


ToDo Ideen Test Notizen

Nacharbeit der wireguard client.conf beim VPN PC / Admin PC / Notebook dokumentieren: Stichworte split tunnel, DNS, AllowedIPs. 

Backup über den Tunnel vom Client möglich.

WOL über den Tunnel? - funktioniert erstmal nicht. Lösung: Helfer vor Ort.

Wlan mit wpa_cli administrieren


Code Block


Keine Kommentare:

Kommentar veröffentlichen