Zum Inhalt springen

Blog ·

Gegen die Portweiterleitung zu Ihrem Panel

Ein Agent, der sich nach außen verbindet, braucht zwei ausgehende Regeln und keinen eingehenden Port. Was das bringt, was es kostet und was es nur verschiebt.

Von Provibr

Wenn eine Management-Plattform Ihre Hypervisoren betreiben soll, muss etwas die Grenze zwischen deren Netz und Ihrem überqueren. Es gibt zwei Richtungen zur Auswahl, und diese Wahl bestimmt fast alles andere am Sicherheitsmodell.

Die überlieferte Richtung ist nach innen. Die Plattform hält Zugangsdaten für Ihren Proxmox-Cluster, Ihre DirectAdmin-Maschine und Ihr Gamepanel und verbindet sich über das Internet zu jedem davon. Das bedeutet eine API, die ins Internet antwortet, eine Firewallregel oder ein VPN und eine Steuerungsebene, die für jeden erreichbar ist, der sie findet.

Die andere Richtung ist nach außen. Sie betreiben einen kleinen Agenten in Ihrem eigenen Netz. Er öffnet eine Verbindung zur Plattform und hält sie offen, Befehle reisen diese Verbindung hinunter und Ergebnisse wieder hinauf. Auf Ihrer Seite lauscht nichts.

Dieser Text handelt davon, was die zweite Möglichkeit kostet und was sie Ihnen gibt, aus der Erfahrung, eine gebaut zu haben.

Die Firewalländerung sind zwei Regeln, beide ausgehend

Die gesamte Netzanforderung eines ausgehenden Agenten passt in eine Tabelle:

RichtungRegelWann
AusgehendTCP 50051 zum Gateway der PlattformEinmal, bei der Registrierung
AusgehendTCP 50052 zum selben HostDauerhaft, das ist die Sitzung
EingehendKeine

Zwei Ports statt einem sind eine bewusste Trennung. Die Registrierung findet statt, bevor der Agent ein Client-Zertifikat hat, dieser Port kann also nur serverseitiges TLS anbieten. Der Sitzungsport verlangt beidseitiges TLS und weist alles ab, was kein gültiges Client-Zertifikat vorlegt. Ein Listener für beides hieße ein Listener, an dem das Client-Zertifikat optional und die Autorisierungsentscheidung an eine Bedingung geknüpft ist. Zwei machen die Grenze strukturell: Auf 50052 gibt es keinen Codepfad, auf dem eine nicht authentifizierte Gegenstelle am Handshake vorbeikommt.

Ist Ihre Egress-Filterung streng, sind diese zwei Regeln die gesamte Bitte. Es gibt keine eingehende Regel zu schreiben, keinen NAT-Eintrag, keinen VPN-Konzentrator und nichts zu erneuern, wenn sich Ihre öffentliche Adresse ändert.

Was „ausgehend“ heißt, wenn das Netz feindlich ist

Eine ausgehende TCP-Verbindung durch NAT ist nicht umsonst: Der Zustand, der sie funktionieren lässt, wohnt in der Tabelle von jemand anderem, und diese Tabelle hat eine Zeitgrenze. Carrier-NAT, eine Unternehmensfirewall und ein Cloud-Loadbalancer vergessen alle still eine untätige Verbindung, und die Art des Ausfalls ist die schlimmste, denn beide Enden halten den Socket weiterhin für in Ordnung.

Zwei Mechanismen fangen das auf, und Sie brauchen beide.

Der erste ist HTTP/2-Keepalive, im Abstand von 30 Sekunden mit einer Zeitgrenze von 10 Sekunden. Das ist die Schicht, die NAT- und Loadbalancer-Zeitgrenzen schlägt, und die einzige, die eine TCP-Verbindung bemerkt, die unter dem Stream still gestorben ist.

Der zweite ist ein Heartbeat der Anwendung alle 20 Sekunden, mit einem Wachhund, der die Sitzung beendet, wenn innerhalb von 45 Sekunden keine Bestätigung eintrifft. Keepalive beweist, dass der Socket lebt; der Heartbeat beweist, dass die Gegenseite noch verarbeitet.

Endet die Sitzung tatsächlich, verbindet sich der Agent mit exponentiellem Backoff und vollem Jitter neu: Die Wartezeit wird gleichverteilt aus null bis zur aktuellen Obergrenze gezogen, die sich von einer Sekunde auf sechzig verdoppelt. Der Jitter ist keine Verzierung. Ohne ihn verbindet sich nach einem Neustart des Gateways jeder Agent jedes Kunden im selben Augenblick neu, und Ihre Erholung wird zur selbst verursachten Massenpanik.

Ein Detail, das erst im Betrieb auftaucht: Der Backoff-Zähler wird erst zurückgesetzt, nachdem eine Sitzung eine volle Minute gesund war. Ohne diese Regel verbindet sich ein Agent mit halb kaputter Verbindung, stirbt, setzt seinen Zähler auf eine Sekunde zurück und hämmert für immer einmal pro Sekunde gegen das Gateway.

Identität: ein Zertifikat, kein Passwort

Ein eingehendes Modell authentifiziert die Plattform gegenüber Ihrem Panel, meist mit einem API-Schlüssel, den Sie in ein Formular einfügen. Ein ausgehendes Modell muss den Agenten gegenüber der Plattform authentifizieren, und dafür kann es etwas Besseres nehmen als ein geteiltes Geheimnis.

Der Agent registriert sich einmal mit einem Einmal-Token: 36 zufällige Bytes, 48 base64url-Zeichen, serverseitig nur als SHA-256-Hash gespeichert und 72 Stunden gültig. Er wird innerhalb einer Transaktion verbraucht, die die Bedingungen erneut prüft, nach denen er ausgewählt wurde, denn zwischen dem Lesen und dem Schreiben kommt eine doppelte Registrierung herein.

Zurück kommt ein Client-Zertifikat. Von da an ist die Sitzung beidseitig authentifiziert, und das Gateway pinnt die genaue Gegenstelle: Es nimmt den SHA-256-Fingerabdruck des vorgelegten Zertifikats und schlägt den Agenten über diesen Fingerabdruck nach, bevor der Agent gesagt hat, wer er zu sein glaubt. Die Identität steht durch das Zertifikat fest; die erste Nachricht auf dem Stream kann sie nur bestätigen.

Die Rotation läuft auf der eigenen Uhr des Agenten: Zertifikate leben 90 Tage, und die Erneuerung beginnt auf halbem Weg, an Tag 45. Das lässt 45 Tage für erneute Versuche, bevor etwas in Gefahr ist, und das Panel warnt einen Menschen erst bei 21 verbleibenden Tagen, die Erneuerung muss also drei Wochen lang fehlgeschlagen sein, bevor jemand behelligt wird. Jede Rotation erzeugt ein neues Schlüsselpaar: auf demselben Schlüssel zu erneuern verlängert das Leben von etwas, das vielleicht längst abgeflossen ist.

Der Widerruf verdient einen eigenen Satz, denn die ehrliche Fassung ist weniger elegant als das Schaubild. Es gibt keine CRL und kein OCSP. Einen Agenten zu widerrufen ist eine Änderung in der Datenbank, und eine verbundene Sitzung wird einmal pro Minute dagegen geprüft. Diese Prüfung ist fail-closed, mit einem Budget von drei aufeinanderfolgenden Fehlversuchen, ein Schluckauf der Datenbank kann einen widerrufenen Agenten also nicht still am Leben halten, und der schlimmste Fall ist begrenzt und ausrechenbar: sechzig Sekunden mal drei.

Genau einmal, über eine Verbindung, die abreißen wird

Sobald Sie hinnehmen, dass die Strecke ein langlebiger Stream über einen unzuverlässigen Weg ist, hört die Zustellsemantik auf, eine theoretische Sorge zu sein. Die Plattform wird einen Befehl nach einem Wiederverbinden erneut zustellen, denn von ihrer Seite ist der Unterschied zwischen „der Agent hat ihn nicht bekommen“ und „das Ergebnis kam nicht zurück“ unsichtbar.

Also merkt sich der Agent etwas. Abgeschlossene Befehle werden mit ihren Ergebnissen auf der Platte gehalten, geschlüsselt nach Befehls-ID, in einem begrenzten LRU. Die Wiederholung eines fertigen Befehls liefert das zwischengespeicherte Ergebnis und führt nichts aus. Die Wiederholung eines noch laufenden Befehls wird ignoriert, denn die Antwort ist bereits unterwegs.

Auf der Platte, und zwar ausdrücklich, denn darum geht es: Ein Zwischenspeicher im Arbeitsspeicher ist genau dann leer, wenn die Plattform alles erneut anbietet, und das ist direkt nach einem Neustart.

Die Gegenrichtung passt dazu. Ereignisse verlassen den Agenten über einen sequenzierten Ausgangskorb; beim Wiederverbinden nennt die Plattform die Sequenznummer, die sie hat, und der Agent spielt ab da erneut ab. Der Ausgangskorb ist begrenzt, und fällt etwas heraus, sagt der Agent das beim nächsten Verbinden, indem er die niedrigste Sequenz nennt, die er noch hält, minus eins, damit die Plattform aufhört, auf Ereignisse zu warten, die es nicht mehr gibt.

Es gibt einen ehrlichen Riss in diesem Versprechen, und der gehört genannt statt versteckt: Scheitert das Schreiben des Dedupe-Eintrags auf die Platte, wird das Ergebnis trotzdem gesendet. Die Alternative wäre, das Ergebnis eines abgeschlossenen Befehls fallen zu lassen, um eine Zusage zu schützen, und schlimmstenfalls führt eine spätere erneute Zustellung ihn ein zweites Mal aus.

Zugangsdaten bleiben auf Ihrer Seite

Das ist der Teil, der die Form eines Einbruchs verändert.

Im eingehenden Modell speichert die Plattform Zugangsdaten, die Kontrolle über Ihre Infrastruktur geben, und dieser Speicher ist die Beute. Im ausgehenden Modell leben die Zugangsdaten für Ihre Hypervisoren und Panels in einem verschlüsselten Tresor auf Ihrem eigenen Host, einmal dorthin geschoben, wenn Sie eine Integration hinzufügen.

Unser Tresor nutzt XChaCha20-Poly1305 mit einem Schlüssel, der über HKDF-SHA256 aus einer lokalen Schlüsseldatei und der Maschinen-ID abgeleitet wird, wobei die Agenten-ID in die Ableitungsinformation eingemischt ist. Eine Folge, die man aussprechen sollte: vault.enc auf eine andere Maschine zu kopieren gibt Ihnen eine Datei, die sich nicht entschlüsseln lässt, denn die Maschine, an die sie gebunden war, ist Teil des Schlüssels.

Und die Grenze, die wir in der Quelle neben die Umsetzung geschrieben haben, ist, dass das nicht gegen root auf dem Host schützt. Das muss es auch nicht. Dem Kunden gehört der Host, und ihm gehören die Zugangsdaten. Der Tresor schützt gegen eine abgeflossene Datei, nicht gegen den Eigentümer.

Die Prüfspur ist von derselben Regel geformt. Jeder Befehl ist eine Zeile, die nie hart gelöscht wird, und die Nutzlast einer Zugangsdaten-Übergabe wird geschwärzt gespeichert. Eine Prüftabelle, die die Geheimnisse enthält, die sie prüft, ist eine zweite Kopie des Problems.

Vier Dinge, die das nicht löst

Ein Architekturtext, der nur Vorteile aufzählt, ist Werbung. Hier ist, was sich verschiebt statt zu verschwinden.

Software auf Ihrem Host. Der Tausch ist echt: Sie legen keinen Port mehr offen und betreiben dafür eine Binärdatei, die installiert, aktualisiert und der vertraut werden muss. Das verschiebt die Frage von „wer kann mein Panel erreichen“ zu „wer signiert den Code, den ich ausführe“, und das ist die bessere Frage, aber keine kostenlose.

Weite Rechte. Ein Agent, der einen Hypervisor verwaltet, hält Zugangsdaten, die einen Hypervisor verwalten. Die Richtung der Verbindung ändert nichts daran, was diese Zugangsdaten können, nur wo sie leben und wer sonst an sie herankommt.

Ausgehend ist immer noch ein Ausgang. Eine Verbindung, die Ihr Netz verlässt, kann Daten daraus hinaustragen. Das Ziel steht fest, der Transport ist beidseitig authentifiziert und das Protokoll ist schmal, aber „zwei ausgehende Regeln“ ist eine kleinere Behauptung als „nichts geht hinaus“.

Antworten in Echtzeit. Das zeigt sich sofort in der API. Weil die Plattform den Agenten nicht anrufen kann, kann ein Schreibvorgang nicht mit seinem Ergebnis antworten: Die richtige Antwort auf „lege diese Maschine an“ ist eine Bestätigung und etwas zum Nachfragen. Lesevorgänge sind davon unberührt, denn die kommen aus der eigenen Datenbank der Plattform. Wer eine API auf einem ausgehenden Agenten entwirft, muss diese Asymmetrie annehmen, statt sie zu übertünchen.

Es gibt außerdem genau einen Fall, in dem der Agent doch lauscht, und etwas anderes zu behaupten wäre unehrlich. Blech über das Netz zu installieren heißt, DHCP zu beantworten und Dateien auszuliefern, und das geht aus einem ausgehenden Socket nicht. Der Agent bindet diese Dienste also, auf einer benannten Schnittstelle, nur für Maschinen mit einem laufenden Auftrag und nur, solange es Arbeit gibt. „Aktiviert“ heißt „hier erlaubt“, nicht „lauscht jetzt“.

Wann eingehend weiterhin die richtige Antwort ist

Betreiben Sie einen Hypervisor und verwalten ihn selbst, trifft nichts davon zu: Ein Agent bringt Ihnen nichts gegenüber einer Firewallregel und einem starken Passwort.

Der Fall wird schärfer mit Entfernung und mit Anzahl. Mehrere Standorte, Netze, die Ihnen nicht gehören, Adressen, die sich ändern, Kunden, deren Firewalls Sie nicht bearbeiten können, und eine Steuerungsebene, die Sie am liebsten überhaupt nicht im öffentlichen Internet hätten. An diesem Punkt ist der Agent kein zusätzlicher Baustein; er ist der Baustein, mit dem Sie den Rest löschen können.

So arbeitet Provibr: eine ausgehende Verbindung je Agent, kein eingehender Port und Zugangsdaten, die das Netz des Kunden nie verlassen. Die Agenten-Dokumentation behandelt Installation, Dimensionierung und Widerruf, Erste Schritte geht die erste Verbindung von Anfang bis Ende durch, und die API beschreibt die Form aus Bestätigen und Nachfragen, die der ausgehende Entwurf erzwingt.

Fangen Sie mit einem Host und einem Agenten an

Konto erstellen, den Agenten mit einem einzigen Befehl installieren und Ihren ersten Proxmox-Host verbinden. Die Testphase läuft 14 Tage und fragt nicht nach Zahlungsdaten.