Der Dienst startet, liest das Profil ohne Beanstandung und stirbt dann an einer Zeile, die unzusammenhängend wirkt: Er kann ca.crt nicht öffnen. Am Zertifikat hat sich nichts geändert, und der Profilpfad in der Unit-Datei ist absolut. Genau diese Kombination ist der Hinweis. Der übergebene Pfad lokalisiert eine Datei, und die Namen in dieser Datei werden ganz woanders aufgelöst, sodass ein Start, der voll qualifiziert aussieht, seine Schlüssel trotzdem aus einem Verzeichnis lesen kann, das niemand vorgesehen hat.

Der Fehlschlag hat wenige Ursachen, und es lohnt sich, sie der Reihe nach zu trennen: das Basisverzeichnis, das der Prozess tatsächlich hatte, der Startkontext des Dienstes und die Berechtigungen oder Sandbox um die Datei, sobald der Pfad stimmt. Jede hinterlässt eine andere Spur — in der Unit, im Prozess und im Dateisystem.

Der Profilpfad ist kein Basisverzeichnis

Stellen Sie sich einen Prozess vor, der in /tmp startet und /etc/vpn/prod/tenant-a.ovpn erhält. In diesem Profil benennt die Zeile ca ca.crt einen relativen Pfad. Nichts an dem Argument, das das Profil gefunden hat, schreibt diesen Namen um, also sucht der Prozess /tmp/ca.crt und meldet eine fehlende Datei.

Verwirrend ist die Reihenfolge der Fehler. OpenVPN parst zuerst die Konfiguration und öffnet referenzierte Dateien, sobald es sie erreicht, sodass ein Tippfehler im Profil gemeldet wird, bevor ein Schlüssel berührt wird, während ein fehlendes Zertifikat erst auftaucht, wenn das Parsen so weit kommt. Ein Profil, das lädt, ist daher ein Beleg für korrekte Syntax, nicht dafür, dass die genannten Dateien gefunden wurden.

Was das Handbuch trennt: --config und --cd

Das Handbuch zu OpenVPN 2.6 beschreibt zwei verschiedene Optionen. Die eine lädt eine Konfigurationsdatei. Die andere wechselt das Prozessverzeichnis, bevor Konfiguration, Schlüssel, Skript und weitere Dateien gelesen werden, und verlangt ein absolutes Verzeichnis ohne Bezug auf das aktuelle.

openvpn --cd /etc/vpn/prod --config tenant-a.ovpn

Dieser Aufruf ist eine Form, keine Anweisung, ein fremdes Profil zu starten. Was er bringt, ist Determinismus: die Basis für jeden relativen Namen in der Kette steht im Befehl, statt von der Shell oder dem Manager geerbt zu werden, der den Prozess gestartet hat. Die Alternative ist ebenso gültig und für einen Dienst oft besser: das Arbeitsverzeichnis in Ruhe lassen und jede referenzierte Datei im Profil absolut machen.

Was auch immer Sie wählen, prüfen Sie die ganze Kette statt des ersten Fehlschlags. Ein Profil kann eine weitere Konfigurationsdatei einbinden, und die relativen Namen der eingebundenen Datei werden gegen dasselbe Prozessverzeichnis aufgelöst, nicht gegen das Verzeichnis der Datei, die sie eingebunden hat. Protokollpfade, Authentifizierungsdateien und Hilfsskripte folgen derselben Regel.

Der Dienst startet woanders

Eine interaktive Shell im Profilverzeichnis beweist nichts über eine paketierte Unit. Manager setzen ihr eigenes Arbeitsverzeichnis, und ein Wrapper-Skript kann es erneut ändern, bevor die Binärdatei läuft. Die fehlschlagende Unit ist der einzige Start, über den nachzudenken sich lohnt.

systemctl show -p WorkingDirectory -p ExecStart --value openvpn@tenant-a
ls -l /proc/$(pgrep -n openvpn)/cwd

Der zweite Befehl zeigt das Verzeichnis, das der laufende Prozess tatsächlich hält, und das ist verlässlicher als die Unit-Datei, wenn ein Wrapper im Spiel ist. Widersprechen sich beide, ist der Wrapper die Antwort und die Unit eine falsche Fährte.

Nach dem Nachschlagen: Rechte, chroot und Sandboxing

Ein korrektes Basisverzeichnis kann dieselbe Meldung erzeugen, denn Auflösung und Zugriff sind getrennte Schritte. Der Prozess braucht Ausführungsrechte auf jedem übergeordneten Verzeichnis und Leserechte auf der Datei, und eine Service-Unit, die einen Teil des Dateisystems verbirgt, ändert, was der Prozess überhaupt sehen kann.

Drei häufige Varianten erzeugen denselben Fehler. Die Datei ist nur für root lesbar, während der Dienst vor dem Öffnen Privilegien abgibt. Die Unit setzt eine schützende Dateisystemsicht, die das Profilverzeichnis nicht enthält. Der Daemon läuft mit chroot, sodass der Pfad, der auf dem Host existiert, innerhalb dieser Sicht nicht existiert.

Diagnostizieren Sie über Dateieigentümer und Prozessidentität, nicht durch Lockerung der Rechte. Einen privaten Schlüssel für alle lesbar zu machen, um diesen Fehler zu dämpfen, tauscht einen lauten Fehlschlag gegen einen stillen, und der Schlüssel ist der Teil des Verzeichnisses, den Sie am wenigsten preisgeben wollen.

Beweisen Sie die Korrektur mit dem eigenen Start

Starten Sie die echte Unit aus einem Verzeichnis ohne Bezug zum Profil neu und beobachten Sie dieselbe Startzeile. Bestätigen Sie dann, dass der Prozess im Betrieb das beabsichtigte Verzeichnis hält und das geladene Zertifikat das erwartete ist.

systemctl restart openvpn@tenant-a
systemctl status openvpn@tenant-a --no-pager
journalctl -u openvpn@tenant-a -n 20 --no-pager

Wenn das Laden der Pfade gelingt, bleiben Authentifizierung und Routing getrennte Stufen mit eigenen Fehlschlägen, und eine Verbindung, die zustande kommt, aber keinen Verkehr durchlässt, ist eine andere Untersuchung. Die Korrektur hier betrifft nur, aus welchem Verzeichnis die Dateien kamen, und sollte im Aufruf sichtbar sein, statt von dem erinnert zu werden, der ihn zuletzt von Hand ausführte.

Wird das Profil von einem Konfigurationsmanager ausgerollt, legen Sie das Basisverzeichnis oder die absoluten Dateinamen auch dort ab. Eine manuelle Korrektur auf einem Host ist die Version dieses Problems, die nach dem nächsten Rebuild zurückkehrt.

Ähnliche Artikel