Reverse-Proxy auf Basis von OPNsense

Grund

Ich möchte 1) von der Firewallbasis Debian mit Shorewall wechseln zu OPNsense. Dazu gehört auch die Funktion des Reverse-Proxys am Eingang des Netzes. Dieser übernimmt auch weitere Aufgaben wie Dynamisches DNS, SSL-Offloading, Letsencrypt usw.

Auch eine Schule kann einen Reverse-Proxy gut gebrauche, da man doch mit der Zeit den einen oder anderen Webdienst auch nach außen verfügbar machen will. Mit ein wenig Aufwand erhält man dann aber mit OPNsense ein hervorragendes Ergebnis.

Übersicht zum Aufbau des Netzes

Die Debian-Web-Server, welche Dienste bereitstellen, sind im Bild ganz rechts.
Der benachbarte AdminPC kann irgendein Betriebssystem haben - solange ein Browser zur Firewallsteuerung läuft.
Die roten Netze existieren hier alle nur innerhalb des KVM-Systems als virtuelle Netze (ohne DHCP oder Hostverbindung). Von oben sind es Schulnetz, Demonetz und das winzige Management-Netz. Natürlich könnte nach rechts aus dem KVM-System auch eine echte Ethernetleitung herausführen, die ebenfalls von der OPNsense-Firewall kontrolliert wird und z.B. mit einem Servernetz verbunden ist.

Uns so erfolgt nun der Zugriff aus dem Internet:

Vom Clients ist zuerst die Fritzbox zu „überwinden“ um eine Verbindung zum Gatewayserver herzustellen. Dieser greift dann stellvertretend als Reverse-Proxy auf die Webserver zu und liefert das Ergebnis an den Client zurück. Welchen der Webserver er anspricht hängt von dem übertragenen FQHN ab (jedenfalls sind die im Folgenden verwendeten „Rules“ so angelegt).

Installation

Plane das Netzwerk und die Serveradressen! Die restlichen Maschinen außer OPNsense können bereits installiert sein, man kann sie ja dann in den virtuellen Netzen verschieben.

Mögliche IP-Adressen innerhalb des KVM-Servers (hier meine heimische Konfiguration):

Maschine Interface zum Netz IPv4-Adr.
(immer privat)
IPv6-Adr.
(public)
Kommentar
OPNsense LAN 192.168.2.200 dynamisch von Fritzbox via Präfix weitergegeben
OPNsense Management 192.168.1.1 - Standard bei OPNsense-Installation, Port ändern (s.u.)
OPNsense Schulnetz 192.168.3.1 -
OPNsense Demonetz 192.168.9.1 -
Admin-PC Management 192.168.1.100 -
Shellinabox Schulnetz 192.168.3.133 - Port 8080 per HTTP
DemoServer Demonetz 192.168.9.122 - Port 80 per HTTP
Technikserver Demonetz 192.168.9.123 - Port 80 per HTTP
DNS-Vorbereitungen
  • Dyn-DNS-Adresse besorgen / festlegen (z.B. gatewayexample.dynv6.net)
  • Zieladressen der Server per CNAME auf die Dyn-DNA-Adresse lenken (hier: remote.example.com und demo.example.com)
OPNsense: Installation und erste Konfiguration

(Stand: April 2020)

  • Konfigurieren der virtuellen Netze
  • OPNsense installieren als FreeBSD 11.2 auf KVM,
    • dabei virtuellen Netzwerkkarten schon vorher als virtio mit den entsprechenden Netzen verbinden. MAC-Adressen merken…
    • ich empfehle auf Englisch mit Deutscher Tastatur zu arbeiten.
  • Nach der Installation die Netzwerkschnittstellen inkl. DHCP konfigurieren (nicht Teil dieser Anleitung).
  • System→Settings→Administration (Web-Gui verlegen)
    • TCP port: 4433 (Unbedingt den Port (Standard: 443) verlegen - z.B. auf 4433.)
    • HTTP Redirect: ✓ (Unbedingt Haken setzen für Disable web GUI redirect rule)
    • Save (nun im Browser die neue Adresse aufrufen und Lesezeichen setzen)
  • Services → Dynamic DNS für z.B. Dynv6.com konfigurieren, ggf. getrennt für IPv4 und IPv6
  • System → Settings → Cron dort „+“:
    • enable: ja,
    • Minutes: eine Zahl<60
    • Hours: z.B. 4,6,12,18
    • Command: Dynamic DNS Updates
    • Description: Dyn DNS aktualisieren
    • Save
    • Apply
  • Jetzt sollte die Firewall die Server anpingen können und die IP-Adresse beim Dyn-DNS-Dienstleister aktualisieren. Testen! Morgen noch einmal testen!
Fritzbox
  • OPNsense für Freigaben auswählen
  • Port-Forwarding (http, https) und Ping6-Freigabe einrichten
  • noch nicht testbar…
OPNsense: Software nachinstallieren
  • System → Firmware → Plugins:
    • os-haproxy
    • os-acme-client

Konfiguration von Letsencrypt (acme-client) und von HAProxy

Es gibt es einige ausführliche Anleitungen - siehe am Ende der Seite unter Quellen. Meist sind es aber „klick dies - tipp das“-Anleitungen. Damit man weiß, was man überhaupt konfiguriert, betrachten wir folgende Grafik:

  • Ein einkommender Request (Anfrage eines Browsers) muss zuerst die Firewall von OPNsense überwinden, d.h. die Ports müssen freigegeben sein.
  • Der Request wird von einem der konfigurierten Public-Services verarbeitet:
    • Hier gibt es jeweils einen für Port 80 (HTTP) und Port 443 (HTTPS).
    • Der HTTPS-Public-Service arbeitet mit aktiviertem „SSL-Offloading“, d.h. er erwartet und verarbeitet das HTTPS-Protokoll (rot).
    • Jeder Public-Service enthält Rules, die zum Entscheiden auf Conditions (also geprüfte Bedingungen) zurückgreifen.
    • Typisch:
      • Condition url_ist_shellinabox prüft, ob der angefragte Host den Namen für den shellinabox-Server hat.
      • Rule server_shellinabox hängt von obiger Condition ab und leitet den Request bei „wahr“ an den passenden Backend-Pool weiter.
    • Viele Regeln steuern nun den Zugriff auf einen passenden Backend-Pool, der aus einem oder mehreren quasi identischen Servern (Real-Servers) besteht.
      • Die Idee ist, dass man die Arbeit auf mehrere identische Server verteilen kann inkl. Ausfallsicherheit.
      • Dann kann man sie z.B. der Reihe nach neu starten, ohne dass der Kunde eine Unterbrechung merkt. Daher das HA im Namen…
    • Der echte Server bekommt nun über das Netzwerk den Request und gibt eine Antwort zurück, die zum Client weitergeleitet wird. Im Falle von SSL-Offloading wird die Antwort natürlich verschlüsselt weitergeleitet (ohne dass der echte Server dies tut).
    • Ein spezieller Real-Server ist der vom Letsencrypt-Plugin eingerichtete acme_challenge_host, der in OPNsense selbst läuft. Er muss über Port 80 und HTTP erreicht werden, wenn ein bestimmtet Pfad angefragt wird. Dafür richtet das Plugin selbst eine Regel ein.
    • Die Verschlüsselung beim Public-Service greift auf das von Letsencrypt gelieferte Zertifikat zurück - sobald es da ist. Man kann den Public-Service für Port 443 also erst danach aktivieren!

Unnötig zu sagen, dass HAProxy natürlich deutlich komplexer ist, als hier dargestellt. So können auch Backend-Server eigene Regeln haben, Conditions können komplexer sein, Benutzeranmeldung kann gemacht werden usw.

Wenn es nicht funktioniert: Unten sind einige Fehler beschrieben.

Verschlüsselung optimieren

Voraussetzung: Es funktioniert!

Nun kann man die Verschlüsselung bei https://SSLLabs.com testen. Vermutlich erhält man eine B-Note. Bei T hat man etwas falsch gemacht… Um auf die Note A+ zu kommen sind nun wenige Optimierungen in den HAProxy-Settings nötig:

Bei Settings→Global Parameters:

  • Maximum SSL DH Size aus 2048 erhöhen
  • Bind options: no-tlsv11 ergänzen
  • Cipher List: Löschen und die Zeichenfolge von Mozilla „Intermediate“ (siehe unten) übernehmen.

Beim Virtual Service→Public Service→ NameMeinesPublicService:

  • Bind options: no-tlsv11 ergänzen
  • Cipher List: Löschen und die Zeichenfolge von Mozilla „Intermediate“ (siehe unten) übernehmen.
  • Enable HTTP/2

Schließlich kann man noch in dem DNS-Server der Domain (wo immer man die verwaltet, z.B. INWX oder beim eigenen Provider) einen CAA-Eintrag machen:

  example.org. CAA 128 issue "letsencrypt.org"

Fehler, die mir unterkamen und ihre Ursachen

  • Letsencrypt kann das Zertifikat nicht aktualisieren
    • → überprüfe, dass die URL (die mit /.well-known beginnt) von außen per HTTP (Port 80) erreichbar ist - z.B. mit cURL.
    • → findet für diese URL eine Weiterleitung zu https statt, so ist entweder
      • eine solche im HAProxy eingerichtet worden (dann ergänze die Rule so, dass beim acme-challenge-Verfahren nicht weitergeleitet wird) oder
      • oben der Haken bei „Disable web GUI redirect rule“ nicht gesetzt worden!
  • HAProxy lässt sich nicht starten (Kontrolle im Dashboard)
    • → Teste die Konfiguration mit dem Button
    • → Sind bei abgeschaltetem HAProxy die Ports 80 und 443 wirklich frei? D.h. nicht erreichbar?
    • Übrigens: Wenn fälschlicherweise immer noch die Administration auf 443 läuft, so bekommt man auch eine merkwürdige DNS-Rebind-Attack-Meldung. Daher „Unbedingt verlegen“.
  • Die Server sind aus dem LAN zwischen Fritzbox und OPNsense nicht zu erreichen.
    • Private Network Adresses für WAN-Interface gesperrt? (OPNsense-WAN-Interface-Konfiguration)
    • Namensauflösung gescheitert, da die Fritzbox interne IP-Adressen nicht auflöst? (testen mit host remote.example.com . Ausnahmeliste in der Fritzbox-Netzwerk-Konfiguration ergänzen)
  • Kein HTTPS-Zugriff mit Firefox möglich, mit anderen Browsern klappt es:
    • → In Letsencrypt OCSP Must Staple angeklickt? Sonst eine gute Idee, wird aber von HAProxy nicht unterstützt und Firefox beschwert sich zu Recht. Also Haken weg, Zertifikat neu ausstellen lassen, fertig.

Mozilla SSL-Konfiguration

  • Liefert eine Liste empfehlenswerter Verschlüsselungstechniken (Cipher).
  • „intermediate“ dürfte für die meisten Anwender praktikabel sein.
  • Man sollte die Einstellungen z.B. jährlich aktualisieren…
  • Derzeit (April 2020) lautet sie:
       ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384
       
1)
Der Wechsel ist u.a. ein Gebot der Vernunft, da z.B. die Weiterentwicklung der von mir verwendeten und geschätzten Shorewall fraglich ist. Bei der Konfiguration bin ich wegen des eher seltenen Aufbaus auf mich alleine gestellt - keine Firma würde das supporten. Da ist OPNsense erfolgversprechender.