07 September 2019

Einleitung

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:

Tunnel

Was ist ein VPN-Tunnel?

Ein Tunnel verbindet zwei Netzwerke über ein unsicheres drittes Netzwerk (=Internet). Anhand eines SSH-Tunnels lässt sich dieses Prinzip veranschaulichen:

Tunnel

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.

Allgemeines

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.ddns.net/howtos/linux/ovpn-wireguard-vergleich.html)

Für den Server-Betrieb wird ein einzelner Port (Standard: 1192/UDP) verwendet. Portnummer sowie Transportokoll (TCP/UDP) können bei Bedarf individuell angepasst werden.

Vorbereitungen

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)

Konfiguration OpenVPN Server

Installation

RHEL/CentOS

sudo yum update
sudo yum upgrade
sudo yum install openvpn easy-rsa  iptables
sudo mkdir /etc/openvpn

Debian

sudo apt-get update
sudo apt-get upgrade
sudo apt-get install openvpn easy-rsa  iptables

OpenVPN und openSSL Versionen prüfen

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

Forwarding am Server aktivieren

(Für reines Host2Host VPN nicht nötig) Datei /etc/sysctl.conf editieren:

net.ipv4.ip_forward=1

Aktivieren:

sysctl -p

Zertifikate (Self signed mit easy-rsa Version 3)

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/

openvpn.conf

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)

Konfiguration OpenVPN Client

Linux/Windows

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

Anmerkung zu Smartphone/Tablet

Android

Upload der Konfiguration

TODO…​ aber ist eigentlich selbsterklärend ¯\_(ツ)_/¯

Keys/Zertifikate Inline

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>

Erweiterte Konfiguration Routing/NAT/DNS

Aktionen bei Tunnel Auf.- und Abbau

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

Routing/IPtables

Es gibt zwei verschiedene Möglichkeiten, wie man ein Routing zwischen Roadwarrior und LAN realisieren kann.

IPtables

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.

Routing

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)

update-resolf-conf bzw. update-systemd-network

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

Einfache Fallback Möglichkeit

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.

Security/Hardening

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.

Hardening

Hier noch weiterführene Informationen für Hardening-OpenVPN: https://openvpn.net/community-resources/hardening-openvpn-security/

OpenVPN mit YubiKey

Häufige Fehler / FAQ

openVPN startet nicht

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.

Debug-Ausgaben erhöhen

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.

Private IP Adressen

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]

CIDR - Classless Inter-Domain Routing

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:

CIDR

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

Geschwindigkeit

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 mit tun-Interfaces

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.