
Wie ein einziger fehlerhafter API-Aufruf einen ganzen Ceph-Cluster lahmlegte
Es begann mit einem einzigen Befehl, einer simplen curl-Anfrage, die eigentlich nur ein paar harmlose Statistiken abrufen sollte. Stattdessen zwang sie einen ganzen Ceph-Cluster in die Knie.
Ein Homelab-Admin, der mit Cephs RESTful API herumbastelte, schickte, was eigentlich ein Routineaufruf hätte sein sollen:
curl -k -X POST "https://USERNAME:API_KEY@HOSTNAME:PORT/request?wait=1" -d '{"prefix": "df", "detail": 1}'
Gefährlich sieht diese Zeile nicht aus. Wohl jeder, der Ceph betreibt, hat so einen Einzeiler schon in irgendeiner Form benutzt oder getestet, um kurz auf die Pool-Statistiken zu schauen, die man sonst mit ceph df detail abrufen würde. Diesmal löste der winzige detail-Parameter "detail": 1 aber etwas weitaus Schlimmeres aus als einen Parsing-Fehler. Innerhalb von Sekunden stürzten die Monitor-Dienste (ceph-mon) im gesamten Cluster ab.
Jede VM, die am System hing, fror ein, und das Proxmox-Dashboard färbte sich rot. Der Cluster, das Herzstück einer selbstgehosteten Infrastruktur, war tot, und zwar wegen einer einzigen fehlerhaften API-Anfrage.
Der Tag, an dem die Monitore starben
Zunächst sah es nach einem kleinen Ausrutscher aus. Der Admin, der unter dem Namen packetsar auftritt, bemerkte, dass Cephs Monitore Fehler warfen. Statt sich zu erholen, stürzten sie aber ab, und zwar immer wieder. Die Logs füllten sich mit einer unheimlich präzisen Meldung:
ceph-mon[278661]: terminate called after throwing an instance of 'ceph::common::bad_cmd_get'
ceph-mon[278661]: what(): bad or missing field 'detail'
Wer schon mal mit Ceph gerungen hat, weiß, dass ausgefallene Monitore (MONs) kein kleines Problem sind. Die MONs führen die Cluster-Map: Sie wissen, welche OSDs welche Daten halten, wo Pools liegen und wer im Quorum ist. Sind sie offline, verliert der Cluster praktisch sein Gedächtnis.
Hier stürzte auch nicht bloß ein einzelner Node ab. Der Fehler zog sich durch alle Monitore, weil jeder sich die vergiftete Anfrage aus einer gemeinsamen Datenbank holte und damit geradewegs die Klippe hinunterstürzte. Jeder Neustartversuch wiederholte nur den Fehler.
„Reboots, Dienst-Neustarts: nichts hat funktioniert", schrieb packetsar. „Ceph- und Proxmox-Cluster sind komplett down, und die VMs sind an diesem Punkt gestoppt."
Die selbstverschuldete Giftpille
Seltsam ist vor allem, dass der Befehl gar nicht so viel Schaden hätte anrichten dürfen. Cephs API soll Eingaben eigentlich validieren und fehlerhaftes JSON oder unbekannte Felder sauber abfangen. Stattdessen wurde der Parameter "detail": 1 so interpretiert, dass er im MON-Prozess eine fatale Exception auslöste.
Ceph nahm die fehlerhafte Anfrage also auf, verschluckte sich daran und speicherte sie dann auch noch ab, sodass die Monitore denselben ungültigen Befehl bei jedem Neustart erneut abspielten. Das Ergebnis war ein Crash-Loop, in dem sich der Cluster an den fehlerhaften Befehl erinnerte und sich immer wieder selbst damit fütterte.
„Sieht so aus, als wäre die Anfrage in einer gemeinsamen ceph-mon-Datenbank gelandet und hätte alle Monitor-Dienste zum Absturz gebracht", schrieb der Admin.
Aus dem fehlerhaften Befehl wurde so eine dauerhafte Korruption. Der vergiftete Zustand steckte im Monitor-Store selbst, und nicht einmal saubere Neustarts wurden ihn wieder los.
Ein Kommentar brachte es gut auf den Punkt:
„Noch ein Beispiel für schlechte Eingabevalidierung? Nicht vergessen, das als Bug an Ceph zu melden."
Wer verteilte Systeme baut, muss Eingaben validieren, denn ein einziges ungeprüftes Feld kann alles zum Einsturz bringen.
„Man kann den ganzen Cluster mit einem einzigen REST-Aufruf vergiften"
So beschrieb es packetsar später im Thread. Das klingt übertrieben, bis man sich an Cephs Architektur erinnert.
Ceph ist um Konsens herum gebaut. Die Monitore replizieren Daten, um das Quorum zu halten, und wenn einer schlechte Zustandsdaten bekommt, gibt er sie in der Annahme, sie seien gültig, an die anderen weiter. Landet ein fehlerhafter Befehl in der Monitor-Datenbank, wird er deshalb getreulich auf alle Nodes kopiert. Dass das System seinen Peers vertraut, ist normalerweise seine Stärke und war in diesem Fall seine Schwäche.
Auf die Frage, ob derselbe Befehl über die CLI problemlos lief, bestätigte der Admin, dass ceph df detail auf der Kommandozeile einwandfrei funktionierte. Die fehlende Validierung saß in der REST-API-Schicht. Das Problem lag also in Cephs API-Wrapper und nicht in der Logik dahinter, ausgerechnet in einer Schicht, die Automatisierung sicherer und einfacher machen sollte und hier zum Single Point of Failure wurde.
Wiederaufbau aus der Asche
Als das Ausmaß des Ausfalls klar war, blieb die Frage, wie man einen toten Ceph-Cluster zurückholt, wenn nicht einmal die Monitore starten.
Einen magischen „Rückgängig"-Knopf gibt es für Cephs Monitor-Datenbank nicht. Packetsar musste also old-school vorgehen und die Datenbank manuell aus den OSDs (Object Storage Daemons) neu aufbauen. Diese Methode ist tief in der Ceph-Dokumentation vergraben und normalerweise extremen Korruptionsszenarien vorbehalten.
Vereinfacht lief die Wiederherstellung so ab:
- Alle OSDs auf jedem Host herunterfahren, um weitere Schreibvorgänge zu stoppen.
- Einen Host als Ausgangspunkt wählen und mit den Daten seiner lokalen OSDs eine frische Monitor-Datenbank aufbauen.
- Dieses neue store.db per Rsync auf die anderen Hosts übertragen, einen nach dem anderen, dabei laufend neu aufbauen und zusammenführen.
- Sobald die Datenbank vollständig ist, das Produktions-store.db auf allen Monitoren durch das neue ersetzen.
- Die MONs wieder hochfahren und Quorum erreichen lassen.
- Zuletzt die Manager-Daemons (mgr) einzeln neu aufbauen und Einstellungen wie das REST-API-Modul neu konfigurieren.
Das macht man nicht leichtfertig. Es ist langsame, nervenaufreibende Arbeit, besonders wenn der Storage-Cluster das Fundament der gesamten Virtualisierungsumgebung ist. Es hat aber funktioniert.
„Etwa eine Stunde, nachdem ich mich langsam durch den Wiederaufbauprozess gearbeitet hatte, konnte ich die VMs wieder online bringen", schrieb er.
Das ist bemerkenswert und zeigt, wie tief man Open-Source-Systeme verstehen und reparieren kann, wenn man volle Kontrolle und genug Geduld hat.
Lehren aus dem Meltdown
Die Moral dieser Geschichte lautet nicht, dass man seinen Cluster nicht anfassen soll, denn durch Herumbasteln lernt man. Verteilte Systeme, besonders solche wie Ceph, verlangen aber besonderen Respekt. Aus diesem Debakel stechen ein paar Erkenntnisse hervor.
1. APIs sind nicht immer sicherer
Wir nehmen gern an, dass APIs Risiko abstrahieren und strukturierte Aufrufe Automatisierung sicherer machen als rohe Befehle. Dieser Vorfall zeigt, dass das Gegenteil eintreten kann, wenn die API Eingaben nicht richtig validiert.
Fehlerhafte Eingaben über eine API sollten nie den Dienst lahmlegen, den die API zugänglich machen soll. Das ist Entwicklung 101.
2. Persistenz ist ein zweischneidiges Schwert
Cephs Design macht das System resilient, weil es Daten über Nodes hinweg konsistent hält, selbst durch Abstürze hindurch. Dieselbe Persistenz macht es aber auch unnachgiebig. Speichert Ceph einen fehlerhaften Zustand, gilt dieser Zustand, bis ihn jemand manuell entfernt.
3. Testen in Produktion ist kein Testen
Die Versuchung ist groß, „nur eine Kleinigkeit" im Live-Cluster auszuprobieren, gerade wenn man es schon hundertmal getan hat. Ein selbstgehostetes Lab ist aber keine Sandbox, und ein fehlerhafter Befehl kann aus einem Abendexperiment eine Wiederherstellungssitzung um 4 Uhr morgens machen.
4. Dokumentation ist Überlebenssicherung
Gerettet hat diesen Cluster die Dokumentation und kein Glück. Wie man einen Monitor-Store aus OSDs neu aufbaut, weiß kaum jemand aus dem Kopf. Der Prozess steht tief in Cephs Low-Level-Dokumentation, in dem Teil, den am Ende nur verzweifelte Admins lesen, und genau der brachte den Cluster zurück.
Wenn Ceph nicht mehr hochkommt
Es war nicht die erste Ceph-Katastrophengeschichte und wird nicht die letzte sein. Im Thread meldeten sich andere mit unheimlich ähnlichen Erfahrungen: Cluster, die nach Stromausfällen nicht wieder hochkamen, irreparabel korrumpierte Monitore oder Phantom-Konfigurationen, die einfach nicht sterben wollten.
Ein Nutzer schrieb:
„Habe es geschafft, Ceph durch einen unerwarteten Stromausfall zu zerschießen … es kam nie wieder hoch, und nichts, was ich versuchte, funktionierte. Selbst ein Neuanfang von null holte immer wieder alte Überreste zurück. Ich habe Ceph an den Nagel gehängt und bin zu ZFS mit Replikation gewechselt."
ZFS ist kein verteilter Storage und tauscht Skalierbarkeit gegen Einfachheit und Zuverlässigkeit. Dass jemand diesen Tausch macht, sagt einiges. Wenn die Wiederherstellung eines Systems schwerer ist als eine komplette Migration, ist das ein Warnsignal.
Ceph ist mächtig, aber nicht nachsichtig. Es bietet enorme Flexibilität mit Object-, Block- und File-Storage auf einer Plattform, setzt aber voraus, dass Sie mit dieser Macht verantwortungsvoll umgehen.
„Öffentliche Bloßstellung ist vielleicht die beste Medizin"
Ein Kommentator meinte halb im Scherz, dass sich „die Ceph-Entwickler schämen sollten", falls der Bug reproduzierbar sei. Ganz falsch liegt er damit nicht.
Das ist kein obskurer Randfall. Ein authentifizierter REST-Aufruf sollte nie Kernservices zum Absturz bringen können. Ob Sie ein Homelab oder ein Rechenzentrum betreiben, solche Zerbrechlichkeit untergräbt das Vertrauen in den Stack.
Open-Source-Software lebt von Transparenz, und Bugs passieren. Fälle wie dieser zeigen aber, wie dringend die API-Eingabevalidierung besser getestet werden muss, besonders bei Befehlen auf Admin-Ebene.
Nachwirkungen und Reflexion
Die Geschichte ging gut aus. Der Cluster wurde wiederbelebt, die VMs kamen wieder online, und der Admin lernte in wenigen Stunden mehr über Cephs Interna als die meisten in Monaten.
Spuren hat der Vorfall trotzdem hinterlassen. „Es erscheint verrückt, dass man den ganzen Cluster mit einem einzigen REST-Aufruf vergiften kann", sagte er, und da hat er recht.
Verteilte Systeme sollen resilient sein, unbesiegbar sind sie deshalb nicht. Manchmal heißt Resilienz einfach, dass man das System wiederherstellen kann. Dieser Fall zeigt genau das: Perfekt war nichts, aber als alles schiefging, ließ sich der Cluster zurückholen.
Das große Ganze
Dahinter steht ein größeres Thema, nämlich wie zerbrechlich Automatisierung in moderner Infrastruktur ist. Wir bauen Schicht um Schicht, APIs auf Daemons und Daemons auf Datenbanken, damit die Verwaltung einfacher wird. Jede Schicht bringt aber neue Komplexität und neue Wege zum Scheitern mit.
In Cloud-nativen Umgebungen vervielfacht sich dieses Risiko, weil jeder Dienst über APIs mit anderen spricht. Jeder Befehl, jedes Deployment-Skript und jeder Automatisierungsjob kann eine Kaskade auslösen.
Wenn selbst Ceph, eines der angesehensten Open-Source-Storage-Systeme der Welt, an einem einzigen fehlerhaften JSON-Feld scheitern kann, erinnert das daran, dass Komplexität immer ihren Preis hat.
Epilog: eine Zeile, sie zu knechten
Irgendwo in einer Terminal-History liegt dieser schicksalhafte Befehl, eine kleine, unscheinbare Textzeile, die in einen Tweet passt.
Dahinter steckt eine Geschichte über Vertrauen, Zerbrechlichkeit und Resilienz in verteilten Systemen. Sie zeigt, wie selbst ausgefeilte Software an einem winzigen Fehler zerbrechen kann und wie man sie mit dem richtigen Wissen, Ausdauer und Dokumentation wieder zum Leben erweckt. Manchmal hängt der Unterschied zwischen totalem Datenverlust und Wiederherstellung einfach daran, ob man weiß, welche Datei als Nächstes per Rsync übertragen werden muss.