LXD-Container kann /dev/net/tun nicht öffnen? Prüfen Sie den unix-char-Eintrag
LXD muss das TUN-Gerät des Hosts in den Container durchreichen, bevor ein VPN-Client es nutzen kann. Lesen Sie, was unix-char hinzufügt, was nicht, und wie Sie es prüfen.
LXD stellt dem Container ein Zeichengerät des Hosts bereit, indem es einen Geräteknoten hinzufügt, nicht indem es den Gast lehrt, einen zu erzeugen. Fehlt im Container /dev/net/tun, kann der Host das Gerät haben und der Gast es trotzdem nicht öffnen. Der unix-char-Eintrag ist die verwalterseitige Hälfte dieses Weges, und er ist bewusst enger als ein privilegierter Container. Deshalb verdienen der Host-Knoten und der Container-Knoten getrennte Prüfungen.
Der Mechanismus ist kurz genug, um ihn im Blick zu behalten: LXD löst einen Host-Pfad auf, erzeugt einen passenden Knoten in der Instanz und nimmt das Gerät in die Geräte-cgroup des Containers auf. Danach braucht der Gastprozess seine eigene Berechtigung und Fähigkeit, um den Knoten für irgendetwas zu nutzen.
Was der unix-char-Eintrag tatsächlich ändert
Ein unix-char-Gerät weist LXD an, ein Zeichengerät des Hosts unter einem gewählten Pfad im Container bereitzustellen. Der Eintrag hat drei wesentliche Teile: die Gerätebezeichnung, die der Verwalter nutzt, den Pfad source auf dem Host und den path, den der Gast sieht. Nur die letzten beiden beschreiben das Gerät selbst. Ein Tippfehler in einem der beiden erzeugt einen Knoten an einer Stelle, die der Client nie öffnet.
Auf dem Host ist das Gerät normalerweise /dev/net/tun. Im Container können Sie denselben Pfad behalten oder einen anderen wählen, aber der Pfad muss zu dem passen, was der VPN-Client erwartet. /dev/net/tun beizubehalten vermeidet ein zweites Konfigurationsproblem, weil die meisten Clients diesen Pfad ohne Nachfrage öffnen.
Der Verwalter wendet den Eintrag beim Start der Instanz oder beim Hotplug des Geräts an. Er kopiert keinen Treiber in den Gast und legt keine Tunnel-Schnittstelle an. Er macht den Knoten sichtbar und erlaubt den Zugriff über die Geräte-Kontrollgruppe des Containers.
Deklarieren Sie das Gerät auf der Instanz, nicht im Gast
Fügen Sie den Eintrag aus dem LXD-Verwaltungskontext hinzu und nennen Sie die Instanz sowie eine Bezeichnung, die Sie später wiedererkennen. Für einen Container namens vpnbox lautet der Befehl:
lxc config device add vpnbox tun unix-char source=/dev/net/tun path=/dev/net/tun
lxc config device show vpnbox
Die Bezeichnung tun gilt nur für die Konfiguration der Instanz. Sie ist kein Schnittstellenname und muss zu nichts im Gast passen. Stellt ein Profil dasselbe Gerät bereits bereit, erzeugt ein zweiter Eintrag einen Konflikt statt Redundanz; sehen Sie sich daher zuerst die wirksame Konfiguration an.
Dateien im Container zu bearbeiten ist die falsche Ebene. Ein mknod in einem Startskript kann auf einem privilegierten Container zu funktionieren scheinen, dann beim Neuerstellen verschwinden oder auf einem weniger privilegierten scheitern. Der Verwalter besitzt das Geräteset der Instanz; lassen Sie ihn auch den Knoten besitzen.
Passen Sie Eigentümer und Modus an den Gastprozess an
Der unix-char-Eintrag kann uid, gid und mode für den Knoten im Container setzen. Nutzen Sie sie, um zum Konto zu passen, das den VPN-Client ausführt, statt das Gerät für alle Nutzer zu öffnen oder den Container in den privilegierten Modus zu schalten.
Sichtbarkeit ist nicht dasselbe wie Berechtigung. Ein Knoten im Eigentum von root mit Modus 600 ist für den Dienst sichtbar, der als unprivilegierter Nutzer läuft, und dennoch von ihm nicht zu öffnen. Prüfen Sie zuerst das Gastkonto, setzen Sie dann den Eigentümer auf dieses Konto und halten Sie den Modus nicht weiter als nötig.
Der Prozess braucht außerdem die Fähigkeit, eine Tunnel-Schnittstelle zu konfigurieren, typischerweise CAP_NET_ADMIN im Netzwerk-Namespace des Containers. Das Durchreichen des Geräts verleiht diese Fähigkeit nicht, und die Fähigkeit zu verleihen liefert das Gerät nicht; es sind unabhängige Voraussetzungen.
Wissen Sie, was der Eintrag nicht gewährt
Ein sichtbarer Knoten ist kein funktionierendes VPN. Das Client-Paket muss weiterhin installiert werden, das Profil muss weiterhin gültig sein, und der Dienst muss weiterhin starten. Authentifizierung, Routen und DNS bleiben Aufgabe des Clients, und ein Fehler dort ist kein Beweis, dass der Geräteeintrag falsch ist.
systemd kann eine weitere Einschränkung hinzufügen. Eine Unit mit DeviceAllow oder einer gehärteten Geräterichtlinie kann den Zugriff auf einen Knoten verweigern, den der Container-Verwalter bereitgestellt hat. Prüfen Sie die Geräterichtlinie der Unit, wenn der Knoten existiert, der Dienst aber einen Berechtigungsfehler meldet, und ändern Sie diese Richtlinie, statt den Container zu erweitern.
Hotplug ist optional und ausdrücklich. Ein Eintrag mit required=false braucht einen Quellpfad und kann erscheinen oder verschwinden, während sich das Host-Gerät ändert. Dieser Lebenszyklus passt zu Hardware, die kommt und geht; für ein TUN-Gerät, das das VPN beim Start braucht, kann ein optionaler Eintrag den Dienst starten lassen, bevor seine Voraussetzung existiert.
Prüfen Sie Sichtbarkeit, Öffnen und Schnittstelle in dieser Reihenfolge
Bestätigen Sie zuerst den Knoten im vorgesehenen Container. Pfad, Major- und Minor-Nummer sowie Eigentümer sollten zum Host-Gerät und zum hinzugefügten Eintrag passen. Ein fehlender Knoten bedeutet, dass der Verwalter den Eintrag nicht angewendet oder auf eine andere Instanz angewendet hat.
lxc exec vpnbox -- ls -l /dev/net/tun
lxc exec vpnbox -- sh -c 'test -c /dev/net/tun && echo char-device-ok'
Bestätigen Sie als Nächstes, dass das Dienstkonto ihn öffnen kann. Ein kurzer Test unter diesem Konto trennt ein Eigentumsproblem von einem Dienstproblem. Starten Sie zuletzt den Client und bestätigen Sie, dass eine Tunnel-Schnittstelle erscheint; nur dieser dritte Schritt beweist den ganzen Weg, weil die ersten beiden bestehen können, während Client-Profil oder Fähigkeit noch falsch sind.
Notieren Sie Instanz, Gerätebezeichnung, Host-Quelle, Gast-Pfad und das besitzende Konto, wenn die Änderung genehmigt wird. Diese fünf Werte muss ein späteres Neuerstellen, eine Migration oder eine Profiländerung bewahren, und sie sind viel leichter zu vergleichen als ein Berechtigungsfehler ohne Kontext.