Ein Boot-Fehler, fünf Ursachen

SLES 15 · HPE DL380 Gen9 · SAP HANA

Ein Boot-Fehler, fünf Ursachen

Der SUSE-Server eines Kunden wollte nicht mehr booten — und die Rettung wurde zur Ausgrabung in fünf Schichten: ein vergessener USB-Eintrag, eine kaputte Zertifikatskette, eine pip-Überraschung, ein Ein-Buchstaben-Tippfehler und eine Firmware-Falle. Jede behobene Schicht legte die nächste frei.

Der Auftrag klang harmlos: Ein HPE ProLiant DL380 Gen9 mit SUSE Linux Enterprise Server 15 — die Maschine, auf der die SAP-HANA-Datenbank eines Kunden läuft — kam nach einem Shutdown nicht mehr hoch. Statt eines Logins zeigte die Konsole eine Notfall-Shell. Bis die Kiste wirklich wieder gesund war, hatte ich fünf voneinander unabhängige Probleme gefunden und behoben, die nichts miteinander zu tun hatten. Hier die ganze Geschichte, inklusive der Irrwege — denn genau dort stecken die Lektionen.

Akt 1 · Das Boot-Problem

Gruselige Meldungen ohne Bedeutung — und eine leise mit Bedeutung

Die Konsole begrüßte mich mit ehrlich beunruhigendem Text: [Firmware Bug]: the BIOS has corrupted hw-PMU resources (MSR 38d is 330), dazu eine Wand aus CPU-Sicherheitshinweisen zu MDS und MMIO Stale Data. Wenn ein Server nicht bootet und auf dem Bildschirm „Firmware Bug" steht, braucht es Disziplin, dem nicht zuerst hinterherzujagen. Ich habe es notiert (es wird später wichtig, in Akt 3) und weitergemacht — keine dieser Meldungen war der Grund für den Boot-Stopp. Sie erscheinen bei jedem Start dieser Maschine, gesund oder nicht.

Meine erste echte Hypothese war ein Klassiker auf dieser Hardware: dass in der initrd — dem kleinen Start-Dateisystem, das der Kernel benutzt, bevor die echten Platten verfügbar sind — der Treiber für den HPE-Smart-Array-P440ar-RAID-Controller fehlt. Auf ProLiant-Kisten ein vertrautes Ausfallbild. Aber es hielt nicht stand: Die Platten waren aus der Notfall-Shell sichtbar, und die UUID des Root-Dateisystems passte zu dem, was die Kernel-Kommandozeile erwartete. Irrweg Nummer eins, in wenigen Minuten ausgeschlossen — weil ich geprüft statt vermutet habe.

Der eigentliche Hinweis war fast unsichtbar: eine Lücke in den Zeitstempeln. Beim Scrollen durch journalctl -xb stand das Log einfach… rund 89 Sekunden still. Nichts stürzte ab, nichts warf Fehler — das System stand. Und 90 Sekunden sind zufällig genau systemds Standard-Timeout beim Warten auf ein Gerät.

Notfall-Shell — Diagnose
# Was ist fehlgeschlagen, und warum?
journalctl -xb          # komplettes Log dieses Boots — auf Zeitlücken achten
systemctl --failed      # welche Units haben aufgegeben
ls /dev/disk/by-uuid    # welche Platten existieren gerade wirklich
cat /proc/cmdline       # welches Root-Device dem Kernel genannt wurde

systemctl --failed sagte es dann in Klartext: Timed out waiting for device — gefolgt von einer UUID im kurzen FAT-Format, wie USB-Sticks es benutzen — und Dependency failed for /mnt/usb. Irgendwer hatte irgendwann einen USB-Stick eingesteckt, ihn in /etc/fstab eingetragen (die Datei, die auflistet, was beim Boot gemountet wird) — und ist später mit dem Stick davongegangen. Ohne die Option nofail behandelt systemd jede fstab-Zeile als Versprechen: Erscheint das Gerät nicht, gilt der Boot als kaputt, und man landet in der Notfall-Shell. URSACHE 1

/etc/fstab — der Fix
# Vorher: Boot hängt 90 s und scheitert, wenn der Stick fehlt
UUID=XXXX-XXXX  /mnt/usb  vfat  defaults                            0  0
# Nachher: Boot läuft ohne ihn weiter und wartet nur 5 Sekunden
UUID=XXXX-XXXX  /mnt/usb  vfat  nofail,x-systemd.device-timeout=5s  0  0

Der demütigende Teil: Die allerersten Meldungen auf dem Bildschirm hatten den Schuldigen exakt benannt. „Timed out waiting for device… Dependency failed for /mnt/usb" ist kein Rätsel. Die Lektion, die ich immer wieder neu lerne: systemds Worte wörtlich lesen, bevor man Theorien baut. Nebenbei zeigte das Journal noch FAT-fs (sda1): Volume was not properly unmounted auf der EFI-Boot-Partition — Narbengewebe früherer harter Shutdowns — also gab es dort noch eine fsck.vfat-Bereinigung. Ein Reboot später lief der Server. Die Geschichte hätte hier enden können. Tat sie nicht.


Akt 2 · Das TLS-Kaninchenloch

„Certificate verify failed" — überall

Kaum bootete die Kiste wieder, brauchte die Anwendung des Kunden ein Python-Paket-Update. pip verweigerte: CERTIFICATE_VERIFY_FAILED. Ärgerlich, aber gewöhnlich — meist ein Problem der Anwendung. Nur: curl scheiterte gegen denselben Host ebenfalls (Fehler 60, der Zertifikatsfehler). Dann scheiterte zypper ref auf jedem einzelnen Repository. Diese Eskalation drehte die Diagnose komplett: Das war kein App-Problem — das gesamte Betriebssystem hatte aufgehört, dem Internet zu vertrauen.

Es gab sogar eine Henne-Ei-Pointe: Die naheliegende Reparatur „ca-certificates-Paket neu installieren" funktioniert nicht, wenn schon der Download des Pakets genau das TLS braucht, das kaputt ist. (Falls man je völlig in der Ecke steht: Einmalig ein RPM mit abgeschalteter Verifikation zu holen ist ein vertretbarer letzter Ausweg, denn RPM-Pakete tragen eigene GPG-Signaturen, die bei der Installation geprüft werden. Besser ist, die eigentliche Ursache zu beheben.)

Bei systemweiten TLS-Ausfällen gehe ich eine feste Leiter ab, billigste Prüfung zuerst:

  • Die Uhr. Zertifikate gelten von–bis; ein falsches Systemdatum bricht alle gleichzeitig. (Hier in Ordnung.)
  • Der Zertifikatsspeicher. Existiert /etc/ssl/ca-bundle.pem und enthält gesunde ~140+ Zertifikate? (Hier in Ordnung.)
  • Was der Server tatsächlich schickt. openssl s_client zeigt die Zertifikatskette exakt so, wie sie präsentiert wird — und die Nummer des Verify-Fehlers ist der schnellste Weg zur Ursache.
die Leiter, Stufe 3
echo | openssl s_client -connect pypi.org:443 -servername pypi.org 2>&1 | grep -E "s:|i:|verify"
 0 s:CN = pypi.org          ← Leaf, signiert von…
   i:CN = corp-SubCA        ← …einem Intermediate, das nirgends in der Kette steckt
verify error:num=2:unable to get issuer certificate

Zwei Dinge sprangen ins Auge. Erstens: pypi.org präsentierte ein Zertifikat, ausgestellt von corp-SubCA — der internen CA des Kunden, nichts, was PyPI je benutzen würde. Zweitens: verify error num=2 heißt „ich sehe, wer das signiert hat, aber ich finde das Zertifikat des Signierers nicht". Zusammen erzählten sie die ganze Geschichte.

Was ein TLS-Inspektions-Proxy wirklich tut

Dieses Netz betreibt, wie viele Firmennetze, eine Security-Appliance, die verschlüsselten Verkehr inspiziert. Man stellt sich vor, die eigene Verbindung erreiche die Website mit einem Kontrollpunkt in der Mitte. In Wirklichkeit gibt es gar keine einzelne Verbindung — es gibt zwei:

Deine Maschine sieht das echte Zertifikat der Website nie. Sie sieht eine Imitation, die der Proxy prägt, signiert von der privaten Zertifizierungsstelle der Firma. Das ist keine Malware — die Appliance tut ihren erklärten Job — aber es funktioniert nur, wenn jede Maschine dieser privaten CA vertraut und der Proxy die vollständigen Papiere übergibt. Womit wir bei der Frage wären, was „vollständig" heißt. Eine Zertifikatskette hat drei Glieder: eine Root-CA (auf deiner Maschine installiert, der Vertrauensanker), ein Intermediate (von der Root signiert, erledigt das Tagesgeschäft) und das Leaf (das Zertifikat der eigentlichen Website). Der Server soll Leaf plus Intermediate schicken; die Root steuert deine Maschine bei.

Der Proxy hier lieferte das gefälschte Leaf und, kurioserweise, die Root — aber nicht das Intermediate corp-SubCA. Kette kaputt, keine Verifikation, kein TLS, nirgends. URSACHE 2

Und warum funktionierte jeder Windows-Laptop im Haus problemlos gegen denselben Proxy? Zwei Gründe. Windows-Maschinen bekommen die Firmen-CAs automatisch per Gruppenrichtlinie verteilt, und Windows betreibt „AIA Chasing" — fehlt ein Intermediate, folgt es einer im Zertifikat hinterlegten URL und lädt das fehlende Glied selbst herunter. OpenSSL, das unter Linux fast alles benutzt, verweigert das mit Absicht. „Läuft unter Windows, scheitert unter Linux" ist bei TLS deshalb praktisch die Signatur für genau diesen Zustand: unvollständige Kette.

der Fix — beide CAs systemweit vertrauen
cp corp-RootCA.crt corp-SubCA.crt /etc/pki/trust/anchors/
update-ca-certificates
trust list | grep -c corp   # prüfen, dass beide im Speicher gelandet sind

Mit der Root und dem fehlenden Intermediate im System-Zertifikatsspeicher kann OpenSSL die Kette lokal vervollständigen. curl lief. zypper aktualisierte alle Repositories. (Der wirklich korrekte Fix ist, den Proxy so zu konfigurieren, dass er seine volle Kette ausliefert — das ist ein Ticket fürs Netzwerk-Team; der serverseitige Fix entsperrt dich heute.)

Das Problem, das zwanzig Minuten später zurückkam

pip funktionierte — also passierte als Erstes natürlich pip install --upgrade pip. Und die TLS-Fehler kamen sofort zurück, nur im venv. Am System hatte sich nichts geändert; an pip selbst schon. SUSE liefert ein gepatchtes pip aus, das den System-Zertifikatsspeicher liest — genau den, den ich gerade repariert hatte. Das Upgrade ersetzte es durch die Upstream-Version von PyPI, die den Systemspeicher komplett ignoriert und ihre eigene mitgelieferte Zertifikatssammlung benutzt (ein Paket namens certifi), die von corp-RootCA noch nie gehört hat. URSACHE 3 Eine Zeile macht pip tippfehlersicher und dauerhaft:

pip — auf den Systemspeicher zeigen
pip config set global.cert /etc/ssl/ca-bundle.pem

Die Anwendung selbst — ein Python-basierter Security-Feed-Aggregator, im Kern ein RSS-Reader für Schwachstellenmeldungen — scheiterte zur Laufzeit auf dieselbe Art, aus demselben certifi-Grund. Aber ihr Fehlermuster war diagnostisches Gold: Nur die Microsoft- und Google/Feedburner-Feeds funktionierten, alles andere schlug fehl. Das waren exakt die Domains auf der SSL-Inspektions-Ausnahmeliste des Proxys — Verkehr dorthin lief unangetastet durch, mit echten, öffentlich vertrauten Zertifikaten, während jede inspizierte Domain die Firmen-Fälschung bekam, die certifi ablehnt. Wenn manche TLS-Ziele gehen und andere nicht: fragen, was die funktionierenden im Netz gemeinsam haben, nicht im Code. URSACHE 4

Der Fünf-Minuten-Fix, der eine Stunde dauerte

Der Standard-Fix für Pythons requests-Bibliothek ist eine Umgebungsvariable, die aufs System-Bundle zeigt. Ich setzte sie. Nichts änderte sich. Ich prüfte den Service, das Shell-Profil, die Neustart-Reihenfolge — nichts. Das eigentliche Problem, beschämend spät entdeckt:

finde den Unterschied
REQUEST_CA_BUNDLE=/etc/ssl/ca-bundle.pem    # was ich tippte — lautlos ignoriert
REQUESTS_CA_BUNDLE=/etc/ssl/ca-bundle.pem   # was die Bibliothek liest — man beachte das S

Ein fehlender Buchstabe. URSACHE 5 Und genau das ist die leise Bösartigkeit von Umgebungsvariablen: Eine falsch geschriebene ist kein Fehler, sondern nur eine Variable, die niemand liest. Keine Warnung, keine Log-Zeile, nichts. Seither bevorzuge ich Mechanismen, die sich nicht lautlos vertippen lassen — pip config wie oben, oder den Default direkt im Code der Anwendung mit os.environ.setdefault("REQUESTS_CA_BUNDLE", "/etc/ssl/ca-bundle.pem"), wo ein Tippfehler wenigstens an einer reviewbaren Stelle wohnt.

Behebe eine Schicht, und die nächste zeigt sich. Das ist kein Pech — so verhalten sich geschichtete Systeme.

Akt 3 · Der Firmware-Epilog

Den Kreis schließen — und einem Downgrade ausweichen

Erinnerst du dich an die [Firmware Bug]-Meldung vom allerersten Bildschirm? Als alles andere gesund war, kam ich darauf zurück und spielte HPEs letztes Service Pack für ProLiant Gen9 ein — das SPP 2022.08, das letzte Firmware-Bundle, das diese Generation je bekommen wird — per SUM im Online-Modus, direkt aus dem laufenden OS.

Und da saß die Falle. SUM zeigte mehrere Komponenten mit einem „Forced"-Schalter — das klingt nach „besonders gründlich" und bedeutet tatsächlich „die Version, die ich anbiete, ist nicht neuer als die installierte". BIOS (P89 v3.30, von 2023) und iLO (2.82) des Servers waren bereits neuer als das, was das 2022er-SPP mitbrachte (P89 v2.92, iLO 2.81), weil diese Komponenten nach dem letzten Bundle weiterhin einzelne Sicherheitsupdates erhielten. Ein „Alles deployen"-Klick hätte die Systemboard-Firmware eines produktiven HANA-Hosts heruntergestuft. Auf End-of-Life-Hardware kann das neueste offizielle Bundle älter sein als deine Maschine — immer die Spalten „Installed" und „Available" lesen, bevor man deployt.

Also wurde selektiv deployt: NIC-Firmware, Platten-Firmware (HPD4 → HPD6) und das Management-Tooling (ssacli und Co.) — die Teile, die wirklich neuer waren. Danach die Verifikationsrunde:

Verifikation
sut -status                     # HPE-Agent zufrieden, nichts ausstehend
ssacli ctrl all show status     # RAID-Controller / Cache / Batterie: OK
journalctl -b -p err            # aktueller Boot, nur Fehler: still

Eine Notiz für alle, die ebenfalls Gen9-Maschinen am Leben halten: Es wird nie wieder ein SPP geben. Künftige Fixes kommen als einzelne Komponenten-Updates — hochgeladen über die iLO-Weboberfläche oder installiert als Linux-.scexe/.rpm-Pakete. Die Ära des einen großen Bundles ist für diese Hardware vorbei.

Was ich mitnehme

  • Ein Symptom, viele Ursachen. Ein einziger sichtbarer Ausfall kann auf mehreren unabhängigen Problemen sitzen. Eine Schicht zu beheben und einen neuen Fehler zu sehen ist kein Scheitern — es ist Fortschritt.
  • systemd wörtlich lesen. „Timed out waiting for device X" benennt den Schuldigen. Erst glauben, dann Theorien bauen.
  • ~90 Sekunden sind eine Signatur. Eine Lücke oder ein Hänger von anderthalb Minuten heißt fast immer: systemd wartet auf ein Gerät oder einen Mount. fstab prüfen.
  • Immer nofail an Wechseldatenträger- und Netzwerk-Mounts. Ein fehlender USB-Stick darf nie einen Boot kosten.
  • Bei TLS-Fehlern die Verify-Fehlernummer holen. openssl s_client mit num=2 zeigte direkt aufs fehlende Intermediate. Schnellstes Werkzeug im Kasten.
  • „Läuft unter Windows, scheitert unter Linux" heißt bei TLS fast immer: unvollständige Kette, von Windows' AIA Chasing übertüncht.
  • Distro-gepatchte Tools sind keine Upstream-Tools. SUSEs pip vertraute dem Systemspeicher; das Upgrade tat es stillschweigend nicht mehr.
  • Umgebungsvariablen scheitern lautlos. Für alles Wichtige Config-Dateien oder In-Code-Defaults bevorzugen.
  • Nie blind „Forced"-Firmware deployen. Auf EOL-Hardware kann das letzte offizielle Bundle älter sein als die installierten Versionen.
FAZIT

Gesamtschaden: eine veraltete fstab-Zeile, ein fauler Proxy, ein übereifriges pip-Upgrade, ein mitgebrachter Zertifikatsspeicher, ein fehlender Buchstabe — und ein Firmware-Bundle, das rückwärts wollte. Nichts davon exotisch. Alles auf einer einzigen Maschine gestapelt, hinter einem einzigen Symptom.

Der Server ist seither langweilig. In diesem Beruf ist langweilig der Pokal.

Kommentare (0)

Noch keine Kommentare. Sei der Erste!

Kommentar schreiben