Kontakt aufnehmen

Als unser VPN-Härtungsprojekt den VPN abschoss – und was wir über Fail-Open gelernt haben

Ein VPN sollte sicherer werden und stand drei Stunden später komplett still – inklusive der eigenen Admin-Zugänge. Warum auth-user-pass-optional nicht das tut, was man denkt, und warum jedes Security-Control am Connect-Pfad fail-open sein muss.

03.06.2026 · 7 min Lesezeit

Wir wollten den VPN sicherer machen. Drei Stunden später kam niemand mehr rein – wir selbst auch nicht. Das ist die Sorte Tag, über die man hinterher ungern redet, aus der man aber am meisten mitnimmt. Also schreiben wir lieber auf, was wirklich passiert ist, statt es zu beschönigen.

Am Anfang stand kein riskanter Plan, sondern ein Routine-Projekt: Das VPN-Gateway sollte auf neue Hardware und ein aktuelles Betriebssystem umziehen. Bei der Gelegenheit wollten wir das in die Jahre gekommene Setup modernisieren – die alte Easy-RSA-2-CA auf Easy-RSA 3 heben, die Zertifikate sauber neu strukturieren, eine WireGuard-Site-to-Site-Strecke ergänzen und die Cert-Rotation automatisieren. Und ganz nebenbei sollte noch ein „kleiner zweiter Faktor“ dazukommen: optional Benutzername und Passwort zusätzlich zum Zertifikat.

Dieses „optional“ ist der Punkt, an dem die Geschichte kippt.

Wie aus einem kleinen Zusatz ein Totalausfall wurde

Der Plan klang harmlos. Zertifikate blieben das Hauptmerkmal, Username/Passwort sollte nur ergänzend obendrauf. Niemand sollte ausgesperrt werden, der bisher mit Zertifikat reinkam.

Nach dem Ausrollen war das Ergebnis eindeutig und unschön: Alle Clients flogen mit AUTH_FAILED raus. Nicht ein paar, nicht die mit Passwort – alle. Und weil unsere eigenen Management-Zugänge ebenfalls durch genau diesen VPN laufen, haben wir uns im selben Moment mit ausgesperrt. Aus „kleiner zweiter Faktor“ wurde innerhalb von Minuten ein vollständiger Betriebsstillstand mit zugeschlagener Tür von innen.

Das Gemeinste daran kam erst bei der Diagnose: Die Clients schickten überhaupt keine Passwörter. Trotzdem brach alles zusammen. Der Mechanismus verhielt sich schlicht anders, als der Name vermuten lässt.

Der OpenVPN-Gotcha, der alles ausgelöst hat

Hier lohnt es sich, genau hinzusehen, weil der Denkfehler verbreitet ist.

auth-user-pass-verify macht Passwörter für alle Clients verpflichtend. So weit erwartbar. Die Falle ist auth-user-pass-optional. Das heißt eben nicht „falsche oder fehlende Passwörter werden toleriert“. Es heißt nur: „kein Passwort ist auch in Ordnung“. Schickt ein Client trotzdem Credentials und die scheitern, ist das Ergebnis ganz normal AUTH_FAILED.

Und es kommt noch eine Stufe dazu: Steht das verify ohne die optional-Zeile da – etwa weil ein Konfigurations-Template einen Schalter auf require statt auf optional rendert – dann ist das Passwort für jeden Pflicht. In dem Moment ist jeder reine Zertifikats-Client sofort draußen.

Das ist der Kern: Diese Logik ist all-or-nothing pro Port. Es gibt keinen sanften Übergang, kein „für manche schon, für andere noch nicht“. Ein einziger falsch gerenderter Schalter trifft nicht ein paar Nutzer, sondern jeden gleichzeitig.

Die eigentliche Moral: Fail-open statt fail-closed

Der technische Auslöser war OpenVPN-Verhalten. Die eigentliche Lektion ist aber grundsätzlicher und gilt unabhängig von der konkreten Software.

Ein Security-Control am Connect-Pfad eines VPN ist standardmäßig fail-closed: Geht irgendetwas schief – ein Skript hängt, ein Exit-Code stimmt nicht, ein Tippfehler in der Config – wird abgewiesen. Bei einem normalen Dienst ist das sogar das gewünschte Verhalten. Bei einem VPN, über das auch die Administration läuft, ist es eine Selbstaussperrung mit Ansage.

Daraus haben wir eine Regel gemacht, von der wir nicht mehr abweichen: Security-Controls am Connect-Pfad müssen fail-open sein. Im Zweifel durchlassen und alarmieren, niemals stumpf blocken. Ein Schutz, der im Fehlerfall den Zugang abschneidet, ist im Betrieb schlimmer als gar kein Schutz – weil er genau dann zuschlägt, wenn man am wenigsten drauf vorbereitet ist.

Wie wir wieder reingekommen sind

Gerettet hat uns am Ende, dass es einen Weg an der eigenen Falle vorbei gab: ein Out-of-band-Zugang über die öffentliche IP, unabhängig vom VPN. Darüber konnten wir zurück auf den vorherigen Stand – reine Zertifikats-Authentifizierung, ohne den Passwortzwang.

Ein zweites Problem zeigte sich erst danach: Manche Clients hatten sich nach den wiederholten AUTH_FAILED selbst stillgelegt und versuchten keinen erneuten Verbindungsaufbau mehr. Dafür brauchte es einen kleinen Watchdog, der die Verbindung clientseitig wieder anstößt. Sonst wäre der Server zwar längst repariert gewesen, die Geräte aber trotzdem stumm geblieben.

Wer regelmäßig an solchen Strecken schraubt, kennt diesen Reflex: Bevor man überhaupt anfängt, prüft man, ob es einen zweiten, unabhängigen Weg ins System gibt. Bei uns war das die Lehre Nummer eins – vor der eigentlichen Härtung den Notausgang sicherstellen, nicht danach suchen.

Beobachten gehört nicht in den Connect-Pfad

Eigentliches Ziel des Projekts war nie der Passwortzwang, sondern Anomalie-Erkennung: auffällige Logins erkennen, bevor jemand Schaden anrichtet. Beim zweiten Anlauf haben wir das Ziel behalten, aber den Weg komplett gedreht.

Der naheliegende Integrationspunkt wäre der client-connect-Hook gewesen. Genau das ist die Falle. Ein Hook, der einen Fehler liefert oder hängt, lehnt den Client ab. Für reine Beobachtung ist das tödlich, weil das bloße Hinschauen plötzlich über Verbinden oder Nicht-Verbinden entscheidet.

Die saubere Lösung war, die Erkennung vollständig aus dem Connect-Pfad herauszunehmen. Ein separater Prozess liest die Verbindungs-Logs out-of-band – angestoßen über einen systemd-Timer, abseits vom eigentlichen Login. So kann die Erkennung per Konstruktion keinen einzigen Verbindungsaufbau blockieren, egal wie kaputt sie selbst gerade ist. Observe-first, nicht enforce-first.

Anomalie-Erkennung, die den Betrieb nicht gefährdet

Wenn die Connect-Logs erst einmal sicher und off-path ausgewertet werden, lässt sich erstaunlich viel erkennen, ohne dass irgendwer Gefahr läuft, ausgesperrt zu werden. Mit ein bisschen GeoIP- und ASN-Anreicherung sind das vor allem:

  • Impossible Travel: derselbe Nutzer verbindet sich aus zwei Orten, zwischen denen er physikalisch nicht so schnell gewechselt haben kann. Klingt einfach, ist aber voller Stolperfallen – GeoIP ist im Mobilfunk gern mal hunderte Kilometer daneben, Reisen ist völlig legitim, und zwei fast gleichzeitige Logins sind eben keine „Reise“.
  • Verdächtige Herkunft: ein Connect aus einem Hosting- oder VPN-ASN statt aus dem typischen Endkunden-Netz des Nutzers.
  • Allowlist pro Nutzer: erlaubte Länder oder feste IPs je Person, wobei eine ausdrücklich gesetzte Regel immer die automatisch gelernte Baseline schlägt.

Entscheidend ist die Haltung dahinter: alles läuft als Score plus Alarm, niemals als automatischer Block. Jeder einzelne Faktor kann danebenliegen, und solange Menschen reisen und Provider komische Routen fahren, wird er das auch gelegentlich tun. Ein Alarm, den jemand bewertet, richtet keinen Schaden an. Ein Auto-Block auf Basis eines wackeligen Signals schon.

Der unsichtbare Stolperstein: gegen welche Identität matchst du eigentlich?

Eine Detection ist nur so gut wie die Antwort auf die simple Frage „wer hat sich da gerade verbunden?“. Und genau da haben wir uns fast selbst ausgetrickst.

Das real ausgerollte Zertifikat trug noch eine alte Identität aus der Zeit vor dem CA-Umbau, während die neue Konfiguration die frisch abgeleitete Identität erwartete. Auf dem Papier sah alles korrekt aus – nur feuerte die Regel nie, weil sie auf einen Namen wartete, der so in den Logs gar nicht auftauchte.

Die Lehre ist unbequem, aber klar: Immer gegen die Identität matchen, die tatsächlich in den Logs steht – nicht gegen die, die man sich aus Stammdaten oder Soll-Zustand herleitet. Was man erwartet, ist egal. Was real durch die Leitung kommt, zählt.

Alarmierung mit dem, was ohnehin schon läuft

Für so etwas braucht es kein großes, neues SIEM. Wir haben die Findings bewusst auf die vorhandene Monitoring-Schiene gelegt: als Prometheus-Textfile über den ohnehin laufenden Exporter, dazu ein Check über die bestehende Monitoring-Anbindung und optional ein Webhook in den Chat – natürlich fail-open, damit auch die Benachrichtigung im Fehlerfall niemanden blockiert.

Sicherheits-Telemetrie muss nicht teuer und nicht kompliziert sein. Sie muss vor allem dort ankommen, wo ohnehin schon jemand hinschaut. Genau diese ruhige, nachvollziehbare Betriebsweise ist der Kern von gutem Managed IT – und der Grund, warum wir solche Schutzmechanismen lieber an bestehende Abläufe andocken, als ein weiteres Insel-System danebenzustellen.

Was wir mitgenommen haben

Der Tag war unangenehm, aber die Lektionen sind es wert. Wenn wir heute an einer VPN-Strecke schrauben, gelten diese Punkte:

  • Security am VPN immer fail-open bauen. Ein Schutz, der im Zweifel den Zugang killt, ist schlimmer als kein Schutz.
  • Erst beobachten, dann vielleicht erzwingen. Schwellwerte in Ruhe tunen, und wenn überhaupt blockiert wird, dann schrittweise, pro Nutzer und mit Kill-Switch.
  • Niemals im Connect-Pfad beobachten. Out-of-band oder gar nicht.
  • Gegen die echte Identität aus den Logs matchen, nicht gegen Stammdaten-Ableitungen.
  • Vor dem Härten einen zweiten, unabhängigen Zugang sicherstellen – Public-IP oder Konsole. Sonst sperrt man sich beim Sichern selbst aus.
  • All-or-nothing-Mechaniken vorher verstehen. Wer nicht weiß, dass OpenVPN-Auth pro Port alle gleichzeitig trifft, lernt es im ungünstigsten Moment.

Sicherer wurde die Strecke am Ende trotzdem – nur eben anders, als wir am ersten Tag dachten. Statt eines Schalters, der im Fehlerfall die Tür zuwirft, läuft jetzt eine Erkennung, die hinschaut, meldet und niemandem den Weg versperrt. Genau diese Reihenfolge – erst stabil, dann scharf – ist auch das, was wir bei einem IT-Sicherheits-Check als Erstes mitbringen. Und wie man so eine Strecke im Alltag dann sauber betreibt, ohne dass jede Änderung zum Drama wird, haben wir uns an anderer Stelle schon für die zentrale Pflege von WireGuard-Konfigurationen angeschaut.