07 September 2019
Dieses Dokument beschriebt die Konfiguration eines virtuelles privates Netzwerk (VPN) mit OpenVPN.
Im Folgenden wird ein typische Setup beschrieben, bei der ein VPN-Client auf ein (oder mehrere) Netzwerk(e) hinter dem VPN-Server zugreifen kann:
Ein Tunnel verbindet zwei Netzwerke über ein unsicheres drittes Netzwerk (=Internet). Anhand eines SSH-Tunnels lässt sich dieses Prinzip veranschaulichen:
Abbildung 1: Quelle: https://de.wikipedia.org/wiki/Tunnel_(Rechnernetz)
Die zwei Tunnel-Endpunkte (hier: Firewall 1 und Firewall 2) bauen dazu eine Verbindung zueinander auf und 'tunneln' gewünschte Verbindungen hindurch. Aus technischer Sicht werden dazu die zu tunnelnde Pakete (i.d.R. verschlüsselt und anschließend) in das VPN-Tunnel-Protokoll als Nutzdaten eingebettet.
Bei einem VPN wird dafür eine virtuelle Netzwerkschnittstelle erzeugt, welches eine Punkt-zu-Punkt-Verbindung zu der Gegentelle aufbaut. Diese virtuelle Schnittstellen können genau wie pysikalische Schnittstellen behandelt werden, d.h. es lassen sich z.B. Routing, IPTables, Trafficshaping, aber auch Tools wie tcpdump, iptraf usw. darauf anwenden.
OpenVPN ist für nahezu alle Betriebsssteme und Plattformen verfügbar.
OpenVPN baut Tunnel über SSL auf und unterscheidet sich damit grundlegend von anderen VPN-Implementationen, wie z.B. IPSec (z.B. FritzVPN), L2TP oder WireGuard.
(Siehe auch: Vergleich Openvpn/WireGuard https://plocki.org/blog/linux/ovpn-wireguard-vergleich.html)
Für den Server-Betrieb wird ein einzelner Port (Standard: 1194/UDP) verwendet. Portnummer sowie Transportokoll (TCP/UDP) können bei Bedarf individuell angepasst werden.
Zunächst müssen folgende Grundvoraussetzungen erfüllt sein:
Öffentliche, errreichbare IP oder Portforwarding am Router einrichten. Bei einer dynamischer IP ist ein dyndns-Dienst nötig.
Systemzeit der Tunnelendpunkte muss korrekt sein
Firewall auf VPN Server System für eingehenden openVPN Port anpassen
Die Netzwerkadresse des Serversystems und auch des Tunnelsystems müssen eindeutig sein. Daher gängige Adressbereiche möglichst vermeiden. Beispiele:
192.168.0.0/24
192.168.1.0/24
192.168.2.0/24 (Speedport)
192.168.176.0/24 (Fritzbox Standard)
10.0.0.0/24 (VPN Anonymisierungsdienste)
10.8.0.0/24 (VPN Anonymisierungsdiensts)
sudo yum update
sudo yum upgrade
sudo yum install openvpn easy-rsa iptables
sudo mkdir /etc/openvpn
sudo apt-get update
sudo apt-get upgrade
sudo apt-get install openvpn easy-rsa iptables
Achtung: Da der Server direkt vom Internet zugänglich ist, sollte regelmäßig sichergestellt werden, dass die eingestezten Versionen sicher und aktuell sind, insbesondere auch OpenSSL:
openvpn --version
Beispielausgabe:
OpenVPN 2.4.4 x86_64-pc-linux-gnu [SSL (OpenSSL)] [LZO] [LZ4] [EPOLL] [PKCS11] [MH/PKTINFO] [AEAD] built on May 14 2019
library versions: OpenSSL 1.1.1 11 Sep 2018, LZO 2.08
(Für reines Host2Host VPN nicht nötig) Datei /etc/sysctl.conf editieren:
net.ipv4.ip_forward=1
Aktivieren:
sysctl -p
Verzeichnisse anlegen:
sudo mkdir /etc/openvpn
sudo mkdir /etc/openvpn/server
sudo mkdir /etc/openvpn/clients
easy-rsa
cd /etc/openvpn/
cp -r /usr/share/easy-rsa /etc/openvpn/
cd /etc/openvpn/easy-rsa/3/
vim vars
Inhalt von ./vars anpassen:
set_var EASYRSA "$PWD"
set_var EASYRSA_PKI "$EASYRSA/pki"
set_var EASYRSA_DN "cn_only"
set_var EASYRSA_REQ_COUNTRY "DE"
set_var EASYRSA_REQ_PROVINCE "PROVINCE"
set_var EASYRSA_REQ_CITY "CITY"
set_var EASYRSA_REQ_ORG "ORGNAME"
set_var EASYRSA_REQ_EMAIL "email@domain"
set_var EASYRSA_REQ_OU ""
set_var EASYRSA_KEY_SIZE 2048 # 4096 ist besser
set_var EASYRSA_ALGO rsa
set_var EASYRSA_CA_EXPIRE 7500
set_var EASYRSA_CERT_EXPIRE 3650
set_var EASYRSA_NS_SUPPORT "no"
set_var EASYRSA_NS_COMMENT "ORGNAME CERTIFICATE AUTHORITY"
set_var EASYRSA_EXT_DIR "$EASYRSA/x509-types"
set_var EASYRSA_SSL_CONF "$EASYRSA/openssl-1.0.cnf"
set_var EASYRSA_DIGEST "sha256"
chmod +x vars
./easyrsa init-pki
./easyrsa build-ca
./easyrsa gen-req myhome-server nopass
Sign:
./easyrsa sign-req server myhome-server
Verifizieren:
openssl verify -CAfile pki/ca.crt pki/issued/myhome-server.crt
Client Schlüssel erstellen und signieren und verifizieren:
./easyrsa gen-req client01 nopass
./easyrsa sign-req client client01
openssl verify -CAfile pki/ca.crt pki/issued/client01.crt
Diffie-Hellman Schlüssel erstellen (dauert ggf. lange):
./easyrsa gen-dh
An richtige Stelle kopieren:
cp pki/ca.crt /etc/openvpn/server/
cp pki/issued/myhome-server.crt /etc/openvpn/server/
cp pki/private/myhome-server.key /etc/openvpn/server/
cp pki/dh.pem /etc/openvpn/server/
cp pki/crl.pem /etc/openvpn/server/
cp pki/ca.crt /etc/openvpn/client/
cp pki/issued/client01.crt /etc/openvpn/client/
cp pki/private/client01.key /etc/openvpn/client/
Beispielkonfiguration:
port 1194
proto udp
dev tun0
ca server/ca.crt
cert server/myhome-server.crt
key server/myhome-server.key # Keep secure
dh server/dh.pem
server 10.4.4.0 255.255.255.0
ifconfig-pool-persist ipp.txt
cipher AES-256-CBC
float
# push local params
push "route 192.168.8.0 255.255.255.0"
push "dhcp-option DNS 192.168.8.2"
# push SIP routes (example)
;push "route 217.0.23.68 255.255.255.255"
;push "route 217.0.0.143 255.255.255.255"
;push "route 217.0.0.129 255.255.255.255"
# redirect defaultroute though tunnel
;push "redirect-gateway def1 bypass-dhcp"
keepalive 10 60
comp-lzo
max-clients 10
;client-to-client
persist-key
persist-tun
# chown?
user nobody
group nogroup
status openvpn-status.log
log-append /var/log/openvpn-server.log
verb 1
;mute 20
client-config-dir ../clients
;tun-mtu 1500
;tun-mtu-extra 32
;mssfix 1450
fast-io
Anmerkungen:
In der OpenVPN Reference https://openvpn.net/community-resources/reference-manual-for-openvpn-2-4/ oder auch in der man-page werden alle Optionen ausführlich erklärt. Daher hier nur grob zusammengefasst:
Das obige Beispiel zeigt eine Serverkonfiguration, bei der sich Clients über udp/1194 zum Server verbinden können. Der Tunnel ist RSA Verschlüsselt und durch 'lzo.comp' werden Datenpakete komprimiert.
Mit dem Schlüsselwort 'server' definiert man das Tunnelnetzwerk, also den Adressbereich, mit dem die virtuellen Schnittstellen miteinander verbunden werden. Dieses muss eindeutig sein, d.h. es darf nicht mit bereits bestehenden Netzwerken kollidieren.
Serverseitig können über das Schlüsselwort "push" diverese Optionen an die Clients übergeben werden. In obigen Beispiel wird exemplarisch das Lokale Netzwerk sowie der lokale DNS 'gepusht'. Sofern der Client diese nicht explizit ablehnt, werden Routen auf dem Client eingerichtet. (Für DNS und weitere DHCP Opions sind zusätzliche Schritte notwendig, siehe Kapitel update-resolv-conf)
client
dev tun
proto udp
remote vpnserver.domain.net 1194
resolv-retry infinite
nobind
persist-key
persist-tun
cipher AES-256-CBC
ns-cert-type server
comp-lzo
ca ca.crt
cert client01.crt
key myhome-server.key
TODO… aber ist eigentlich selbsterklärend ¯\_(ツ)_/¯
Anstelle von externen Schlüssel.- und Zertifikatsdateien können diese auch 'Inline' eingetragen werden. Beispiel:
<ca>
-----BEGIN CERTIFICATE-----
MIIDXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXX==
-----END CERTIFICATE-----
</ca>
Mittels up.- und down.-Skripten können bei Bedarf Aktionen bei erfolgreichem Tunnelauf.- bzw. Abbau gestartet werden. Einträge in Konfig:
script-security 2
up ./up.sh
down ./down.sh
Typische Aktionen sind:
Routen setzten/löschen
IPTables Reglen setzten/löschen
DNS-Server integrieren/entfernen
Es gibt zwei verschiedene Möglichkeiten, wie man ein Routing zwischen Roadwarrior und LAN realisieren kann.
Mit einem iptables Eintrag wird ein (Source)NAT eingerichtet, um auf den Remote-LAN zuzugreifen. Beim Source-NAT wird die Quell-Adresse des verbindungsaufbauenden Computers umgeschrieben. Beispiel ./up.sh (Server)
#!/bin/sh
iptables -t nat -A POSTROUTING -s 10.4.4.0/24 -o bond0 -j MASQUERADE
Vorteil: LAN benötigt keine Rückrouten
Vorteil: einfaches Fall-Backsystem möglich
Nachteil: Dienste im LAN "sehen" Anfragen immer nur von der IP des VPN-Servers.
Alternativ zu einer NAT-Regel können auch Routen im LAN konfiguriert werden. Hierfür muss allerdings jeder zu erreichender Host eine korrekte Rückroute ins VPN kennen. Beispiel-Route für LAN:
sudo ip route add 10.4.4.0/24 via 192.168.8.1 dev eth0
Idealerweise konfiguriert man solche Routen zentral über einen DHCP Server im LAN.
Vorteil: Transparentes Net2Net VPN möglich
Nachteil: Verteilung der Routen im LAN (Manche 'Baumarktrouten' können das nicht)
Ein Client kann DNS Server vom Server empfangen. Hierfür wird (für Linux) ein Skript benöigt: https://github.com/alfredopalhares/openvpn-update-resolv-conf
Wird die NAT-Variante verwendet, lässt sich der Server relativ einfach mit einem Fallback-Server ausfallsicher machen. Benötigt wird nur ein weiterer Server im (selben) LAN mit gleicher Konfiguration (aber natürlich unterschiedliche LAN-IP & Tunnel-Netzwerk).
In der Client-Konfiguration wird anschließend ein weiter "remote"-Eintrag hinzugefügt. Alle Remote-Einträge werden bei Verbindungsaufbau der Reihe nach durchprobiert, bis eine Verbindung zustande kommt. D.h.: Wenn ein OpenVPN-Server deaktiviert ist, wird einfach der Nächste verwendet.
Durch die NAT-Regel kann dann ohne weitere "Routing-Klimmzüge" und unabhängig vom verwendeten VPN Server auf das LAN zugegriffen werden.
Wichtig: Sobald ein virtuelles Interface erstellt ist, greift ggf. die Default-Policy von IPtables (iptables -P ACCEPT|DROP|REJECT). Oder anderes herum ausgedrück: Sind keine Default-Policies definiert, erlangt man über das Tunnelinterface vollen LAN Zugriff.
Hier noch weiterführene Informationen für Hardening-OpenVPN: https://openvpn.net/community-resources/hardening-openvpn-security/
https://www.crc.id.au/openvpn-otp-with-a-yubikey/ TODO: noch nicht ausprobiert!
OpenVPN protokolliert standardmäßig einige Ausgaben. Sollte OpenVPN also einmal nicht starten, unbedingt als Erstes ins Protokoll zu schauen! Eine erfolgreiche Tunnel-Verbindung wird immer mit
Initialization Sequence Completed
protokolliert.
Durch hinzufügen/editieren der Zeile
verb 5
In der Konfigurationsdatei kann die Log-Ausgabe bei Bedarf erhöht werden. Je höher die Zahl, um so mehr Debug-Ausgaben werden erzeugt. Hilfreich bei ungewöhnlichen Fehlern. Hinweis: Nach dem Debuggen diese Zeile wieder entfernen, da sonst unnötig viele Daten im Logfile landen.
Netzadressbereich |
CIDR |
Kurzform |
Anzahl |
10.0.0.0 bis 10.255.255.255 |
10.0.0.0/8 |
10/8 |
2^24 = 16.777.216 |
172.16.0.0 bis 172.31.255.255 |
172.16.0.0/12 |
172.16/12 |
2^20 = 1.048.576 |
192.168.0.0 bis 192.168.255.255 |
192.168.0.0/16 |
192.168/16 |
2^16 = 65.536 |
Quelle: Wikipedia [2]
Notation |
Adressen |
Anzahl |
Subnet Dez |
Subnet Bin |
/1 |
2.147.483.648 |
128.0.0.0 |
255.0.0.0 |
10000000.00000000.00000000.00000000 |
/8 |
16.777.216 |
16.777.214 |
255.0.0.0 |
11111111.00000000.00000000.00000000 |
/16 |
65.536 |
65.534 |
255.255.0.0 |
11111111.11111111.00000000.00000000 |
/24 |
256 |
254 |
255.255.255.0 |
11111111.11111111.11111111.00000000 |
/27 |
32 |
30 |
255.255.255.224 |
11111111.11111111.11111111.11100000 |
/30 |
4 |
2 |
255.255.255.252 |
11111111.11111111.11111111.11111100 |
/32 |
1 |
0 |
255.255.255.255 |
11111111.11111111.11111111.11111111 |
Beispiele:
Host-Route:
/sbin/ip route add 192.168.9.1/32 dev eth0
Netz-Route
/sbin/ip route add 192.168.8.0/24 dev eth0
Subnetz über Gateway:
/sbin/ip route add 192.168.21.0/24 via 192.168.9.1
Defaultroute überdecken:
/sbin/ip route add 0.0.0.0/1 via 10.8.8.1
/sbin/ip route add 128.0.0.0/1 via 10.8.8.1
Veranschaulichung 10.10.1.32/27:
Zu 10.10.1.32/27 gehört 10.10.1.44, aber nicht 10.10.1.90 [3]
Siehe auch:
ipcalc -4 -b -m -n 10.10.1.32/27
OpenVPN (genauer OpenSSL) skaliert nicht über Multi-Core CPUs, d.h. es wird pro Tunnel immer nur ein Kern verwendet. Allerdings werden CPUs mit AES-NI unterstützt:
openSSL Verschindigkeit messen:
openssl speed -evp aes-256-cbc
Beispielausgaben:
Intel Atom D510 (kein AES)
type 16 bytes 64 bytes 256 bytes 1024 bytes 8192 bytes
aes-256-cbc 17808.94k 19034.69k 19237.38k 19470.68k 19507.88k
Intel Core i5 (mit AES)
type 16 bytes 64 bytes 256 bytes 1024 bytes 8192 bytes
aes-256-cbc 422739.39k 448582.40k 453674.85k 455750.38k 456448.98k
ethtool zeit Verbindungsgeschwingigkeit immer mit 10MB/s an. Das ist in den virtuellen Interfaces begründet, denn diese haben kein auto-negotiating. Dieser Wert stellt kein Limit dar und kann ignoriert werden.
[1] Wikipedia - OpenVPN: https://de.wikipedia.org/wiki/OpenVPN
[2] Wikipedia - Private Adressen: https://de.wikipedia.org/wiki/Private_IP-Adresse
[3] Wikipedia - CIDR: https://de.wikipedia.org/wiki/Classless_Inter-Domain_Routing