Dezentrale VPNs
Neben dem klassischen Setup, in dem sich VPN Clients bei einem zentralen VPN Endpoint einwählen, existieren seit einiger Zeit ebenfalls verteilte VPN Systeme, welche eine sichere Verbindung zwischen den einzelnen Teilnehmern eines Netzwerks umsetzen. Eine bekannte Umsetzung eines Peer2Peer VPNs ist Tinc. Hierbei wird häufig ein sogenanntes Mesh-Routing verwendet. Das heißt, eine Verbindung zwischen zwei Knoten ist innerhalb eines Meshes über mehrere Routen möglich. Dies hat den großen Vorteil, dass das VPN selbst dann bestehen bleibt, wenn eine der Verbindungen ausfallen würde.
Ein typisches Mesh Netzwerk kann z.B. so aussehen:
Würde die Verbindung zwischen Node 1
und Node 3
unterbrochen werden, kann der Traffic immer noch über Node 2
oder Node 4
weitergeleitet werden.
Das Setup eines Tinc Meshes erfordert allerdings recht viel Aufwand, weil die Knoten gegenseitig ihre Zertifikate kennen müssen.
Ein typisches Setup von Tinc liest sicht wie folgt:
- Install tinc VPN on each node.
- Create the VPN’s working directory on each node.
- Create tinc. conf and host files on every node.
- Create VPN control scripts for all tinc instances.
- Create systemd unit files.
- Exchange host files amongst all nodes.
- Enable tinc systemd unit(s).
Es können hierzu zwar auch Automatisierungslösungen wie Ansible verwendet werden, allerdings ist die Einrichtung eines Tinc basierten Meshes auch dann nicht trivial und erfordert beim Hinzufügen von neuen Knoten ein Update der anderen Nodes.
Nebula VPN
Ende letzten Jahres hat die Firma Slack ihre interne Lösung für ein verteiltes VPN, welches auch als Overlay für ihre Backend Services verwendet wird, unter dem Namen Nebula VPN als Open Source Software der Allgemeinheit zur Verfügung gestellt. Die Sofware selbst findet sich auf Github und wird dort auch weiter entwickelt.
Aber was ist Nebula nun?
Nebula is a scalable overlay networking tool with a focus on performance, simplicity and security. It lets you seamlessly connect computers anywhere in the world. Nebula is portable, and runs on Linux, OSX, and Windows.
Demnach sind die Hauptziele von Nebula Performanz, Einfachheit und Sicherheit. Es wird ausdrücklich betont, dass diese Software innerhalb von Slack auch für die Anbindung der Laptops von mobilen Mitarbeitern verwendet wird.
Arstechnica hat recht zeitnah zur Veröffentlichung ein Tutorial online gestellt, welches die groben Punkte eines Setups durchgeht.
Darauf aufbauend hier also die deutsche Version, in der ein paar einzelne Schritte noch mal detailierter beleuchtet werden:
Zunächst ein paar Details:
- Alle Verbindungen werden direkt zwischen den einzelnen Peers aufgebaut. Hierdurch entsteht ein großflächiges Mesh, welches eine Verbindung der Clients über unterschiedliche Wege ermöglicht.
- Die Datenübertragung selbst ist Packet-basiert (UDP), das heißt, dass eventuell Firewalls weniger Probleme bei Clients verursachen, als andere VPNs (wie z.B. IPsec).
- Nebula verwendet das Noise Protocol Framework.
- Nebula verwendet Zertifikate, um IPs von Knoten, den Namen und die Zugehörigkeit zu (selbst-definierten) Gruppen zu validieren.
- Der Schlüsselaustausch selbst basiert auf elliptic curve Diffie-Hellman key exchange und AES-256-GCM.
- Jeder Knoten baut für sich selbst eine eigene Routing Table auf, welche er mit denen von anderen Knoten aktualisieren kann.
- Es existieren Discovery nodes (
lighthouse
genannt), welche Verbindungen zwischen Knoten hinter einem NAT-Layer ermöglichen. * Danach können weitere Funktionen (wie z.B. UDP hole punching) verwendet werden.
Setup der Basis
Das Setup gliedert sich in vier Schritte:
- Aufsetzen der PKI Infrastruktur
- einen Plan erstellen
- Aufsetzen von (mindestens) einem Lighthouse Knoten
- Setup der restlichen Knoten
Alle notwendigen Binaries können bei den Releases vom Projekt gefunden werden. Nach Entpacken des Archives erhalten wir zwei Binaries:
-
nebula
: Die eigentliche Anwendung um das VPN aufzubauen. -
nebula-cert
: Ein Tool, welches für die Zertifikatsverwaltung verwendet wird.
Aufsetzen der PKI Infrastruktur
Als allererstes gilt es ein Root Zertifikat zu erstellen. Mit dem privaten Schlüssel lassen sich dann alle weitere Zertifikate provisionieren.
./nebula-cert ca -name “ACME Nebula Mesh Network”
Wir verschieben die beiden erstellten Dateien ca.crt
und ca.key
in ein separates Verzeichnis certs. Dieses Root Zertifikat ist ein Jahr gültig.
Bestehen gute Gründe, den Gültigkeitszeitraum zu verändern, lässt sich dies mit dem Parameter -duration
machen. (z.B. ./nebula-cert ca -duration "10000h" …
.
Es ist empfehlenswert den Root CA Schlüssel nur verschlüsselt abzulegen (z.B. per git-crypt).
einen Plan erstellen
Bevor wir fortfahren, sollten wir uns ein paar Gedanken über die Netzwerkkonfiguration machen. Jeder Client erhält eine (fixe) IP Adresse. In einem normalen Subnetz sind dies 254 freie Adressen. Da die IP Adresse eines VPN Nodes bei der Erstellung seines Zertifikats vergeben wird, empfiehlt es sich demnach - insbesondere bei größeren Netzen - eine Liste mit der Adressverteilung anzulegen. Diese Tabelle kann ebenfalls die Node Groups enthalten, welche eine detailiertere Zugriffskontrolle ermöglichen (dazu später mehr).
Folgende Annahmen gelten für unser Beispiel:
- Es gibt zwei interne Systeme,
service.dev
undservice.prod
. - Weiterhin gibt es zwei Entwickler
Anna
undAnton
. - Beide wollen untereinander (und mit anderen Entwicklern) per ssh (GIT) und http(s) kommunizieren.
-
Anton
soll per SSH nur aufservice.dev
Zugriff haben. -
Anna
, hat nebenservice.dev
auch SSH Zugriff aufsevice.prod
. -
service.dev
undservice.prod
sind für alle Teilnehmer im VPN unter http(s) erreichbar. - Zusätzlich gibt es noch eine lighthouse Instanz
lighthouse1
.
Wir definieren nun folgende Gruppen:
-
dev
: Die Gruppe an Entwicklern. -
support-dev
: SSH Zugriff auf Dev. -
support-prod
: SSH Zugriff auf Prod.
Wir können nun folgende Tabelle erstellen:
Host | IP | Groups |
---|---|---|
lighthouse1 | 192.168.100.10 | |
service.prod | 192.168.100.20 | |
service.dev | 192.168.100.30 | |
anna | 192.168.100.101 | dev, support-dev, support-prod |
anton | 192.168.100.102 | dev, support-dev |
Betrachten wir das Setup in einer Netzwerk Übersicht, sieht das dann so aus:
Aufsetzen eines Lighthouse Knoten
Das Setup vom Lighthouse Knoten unterscheidet sich wenig vom Setup eines anderen Clients. Der einzige Unterschied ist eine andere Konfiguration.
Die Konfiguration selbst wird in einer Datei namens config.yml
angelegt.
Bevor wir uns näher mit der Konfiguration befassen, müssen wir erst ein Zertifikat für den neuen Knoten erstellen.
Für unseren lighthouse Knoten erfolgt dies mit:
Kommen wir nun zur Konfiguration. Ein Template hierfür stellt das Projekt Repository zur Verfügung.
Die Konfiguration gliedert sich in die einzelne Blöcke (pki, static_host_map, lighthouse, listen, tun, und firewall).
Der erste Bereich gilt dem PKI Setup. Neben dem Root-CA Zertifikat, dem Node Zertifikat und -Schlüssel, lassen sich hier auch Blacklist erstellen, falls einem Node Zertifikat nicht mehr vertraut werden soll.
Im nächsten Block wird eine statische Host Map erstellt. Dies ist das initiale Mapping, welches jeder Client zum Auffinden der Peers verwendet.
Hier sollte dann das Mapping der einzelnen lighthouse Knoten eingetragen werden.
Jeder Lighthous Knoten sollte eine statische, public IP Adresse besitzen, welche hier auf seine interne IP gemappt wird.
Der nächste Block ist die Konfiguration, die für einen lighthouse
Node notwendig ist.
Entweder ist ein Node ein lighthouse
, oder der Node erhält eine Liste aller lighthous IPs.
Weiterhin lassen sich die (UDP) Ports definieren, über den das Mesh aufgebaut werden soll. Dies ist ein kritisches Setting für lighthouse
Nodes - da diese immer erreichbar sein sollten. Alle anderen Knoten können dies auch dynamisch zuordnen lassen.
Es folgt ein Block, in dem sich das Netzwerk Device konfigurieren lässt.
Ebenso das Logging:
Am Ende gibt es noch einen Block firewall
.
Über diese Konfiguration lässt sich die Absicherung der einzelnen Knoten im internen Netzwerk des VPNs (192.168.100.0/24) steuern.
Jeder Client erstellt für das VPN Interface eine eigene Firewall.
Über diese lässt sich steuern, welche Ports geöffnet sind und welche Client Gruppen auf diese Ports Zugriff haben.
Der lighthouse
Node soll nur per ping
cmd erreichbar sein (icmp
).
Und weiterhin allen ausgehenden Verkehr zulassen.
Bei den anderen Knoten werden wir eine detailiertere Konfiguration verwenden.
Am Ende können wir unseren lighthouse
Node starten. Da wir ein Netzwerk-Device erstellen müssen, benötigt dies erweiterte Access-Rights.
Setup der restlichen Knoten
Die Konfiguration der Clients geschieht in ähnlicher Art und Weise wie beim lighthouse
(wir erinnern uns: es ist ein peer2peer VPN, ein lighthouse
ist auch nur ein Client).
Wichtig ist, dass in der config.yml
weiterhin unser lighthouse
als static Host eingetragen wird:
Was sich allerdings unterscheidet ist der Block lighthouse
in der config.yml
:
Der aktuelle Client ist kein lighthouse
, die IP 192.168.100.10
ist die (VPN) interne IP unseres lighthouse
Knoten, an welchen unser Client andere peer2peer nodes bekannt machen kann.
Da die Knoten mit dem Services (service.prod
und service.dev
) zusätzliche Firewall Regeln beinhalten, ergänzen wir in deren config.yml
Datei den Block firewall
:
Der nächste Block für SSH unterscheidet sich nun für service.dev
und service.prod
jeweils:
service.prod
:
service.dev
:
Theoretisch lassen sich hier auch mehrere Gruppen kombinieren.
Der Rest der Konfiguration ist identlisch.
Damit nun auch unsere obigen Regeln greifen, müssen wir beim Erstellen der Client Zertifikate natürlich auch die entsprechenden Gruppen verwenden. Zusätzlich empfiehlt es sich auch, die Gültigkeit der Zertifikate einzuschränken - z.B. für die mobilen Clients auf zwei Wochen (336 Stunden), bzw. 6 Monate (4032 Stunden) für die Services.
Für unseren Produktion Service sieht der Befehl nun so aus:
Die weiteren Befehle setzen sich nun wie folgt zusammen:
Wir haben nun für jeden konfigurierten Client ein Paar aus crt
und key
Dateien. Beide Dateien können nun mit dem Binary der jeweiligen Plattform verpackt werden und zur Provisionierung verteilt werden.
Gestartet werden die anderen Nodes mit dem gleichen Befehl, wie auch die lighthouse
node:
Wir sehen, dass neben einer anderen IP auch die anderen Firewall Regeln angezeigt werden.
Weiterhin unterschiedlich ist der Handshake Request zu dem konfigurierten lighthouse
node.
Fazit
In den letzten Wochen haben die Berichte über eingeschränkte Möglichkeiten bei der Remote-Arbeit aufgrund von Limitierungen der Infrastruktur sehr zugenommen.
Die bisher angeschafften, zentralisierten Lösungen sind nicht für eine breite Verwendung dimensioniert.
Zentrale Einwahlknoten stellen immer einen potenziellen Flaschenhals dar.
Slack hat mit Nebula einen VPN Ansatz als OSS veröffentlich, der im Produktivsetup von Slack selbst bewiesen hat, dass er in den Punkten Durchsatz, Stabilität und Koordination mit anderen kommerziellen Produkten mithalten kann.
ArsTechnica erwähnen in ihrem Artikel einige kritische Punkte, denen ich mich allerding ebenfalls anschließen kann:
- Das Setup ist bisher noch nicht ohne weiteres für einen Endbenutzer geeignet. Bislang existieren weder passende Launcher noch UI Anwendungen, die ein einfaches Einwählen ermöglichen, wie es andere Vergleichsprodukte tun.
- Windows benötigt zusätzliche Komponenten (tap-windows6 driver), damit eine Einwahl in ein Nebula VPN möglich ist.
Positiv bleibt hervorzuheben, dass:
- Der Durchsatz im Vergleich zu anderen peer2peer VPNs hoch ist.
- Die Software komplett OpenSource ist.
- Eine Einwahl über Zertifikate abgesichert ist (welche ein Ablaufdatum haben).
- Durch den P2P Ansatz diese Lösung deutlich besser skalliert als zentralisierte Ansätze mit Einwahlknoten.
Mittlerweile findet Nebula auch auf anderer Ebene Verwendung. Die Jitsi Knoten von Freifunk München sind mittlerweile über ein internes Nebula VPN verbunden, hier wird es sicher in absehbarer Zeit weitere Erkenntnisse aus den Tests geben.
https://twitter.com/FreifunkMUC/status/1268103249330089984
Als letzter Punkt sei erwähnt, dass eine moderne Systemarchitektur lieber ohne eine Absicherung über ein VPN auskommen sollte.
Ein Zero-Trust Ansatz ist hier sicherlich erstrebenswert und ermöglich auch im Nachhinein die Öffnung des eigenen Serviceangebots für weitere Parteien, ohne dass weitere zusätzliche Anpassungen notwendig sind.