Das Symptom
npm install läuft nicht. Ein fetch gegen eine interne API läuft nicht. Node
bricht mit UNABLE_TO_VERIFY_LEAF_SIGNATURE ab, manchmal auch mit
DEPTH_ZERO_SELF_SIGNED_CERT oder UNABLE_TO_GET_ISSUER_CERT. Der Browser auf
demselben Rechner, im selben Netz, mit derselben URL: völlig zufrieden, grünes
Schloss, keine Warnung.
Die IT sagt, das Wurzelzertifikat der Firma sei ausgerollt und liege im Zertifikatsspeicher des Systems. Sie hat recht. Node interessiert das trotzdem nicht.
Die „Layer 8“-Wahrheit
Das ist kein Fehler in deinem Netz und kein Fehler in deinem Code, sondern eine Differenz darüber, wer eigentlich festlegt, wem zu trauen ist. Der Browser fragt den Vertrauensspeicher des Betriebssystems – und findet dort das Zertifikat, das eure IT ausgerollt hat. Node fragt ihn nicht automatisch. Deshalb sieht Node eine Kette, die bei einem unbekannten Aussteller endet, und tut das einzig Richtige: Es bricht ab.
Bemerkenswert ist, wie offen die Node-Doku diesen Stolperstein inzwischen
behandelt. Bei Fehlern wie UNABLE_TO_VERIFY_LEAF_SIGNATURE,
DEPTH_ZERO_SELF_SIGNED_CERT oder UNABLE_TO_GET_ISSUER_CERT hängt Node von
sich aus einen Hinweis an, „suggesting that if the root CA is installed locally,
try running with the --use-system-ca flag“. Und die Begründung dafür steht
gleich dahinter: „to direct developers towards a secure solution, to prevent
unsafe workarounds“. Das ist eine ungewöhnlich ehrliche Zeile in einer
API-Doku – sie sagt im Klartext, dass hier reihenweise Leute die
Zertifikatsprüfung abschalten, und versucht, sie vorher abzufangen.
Denn genau das ist der Layer-8-Anteil: Die erste Suchanfrage zu diesem Fehler führt zuverlässig zu einer Umgebungsvariable, die die Prüfung komplett ausknipst. Sie funktioniert sofort, sie ist eine Zeile, und sie verwandelt eine TLS-Verbindung in ein verschlüsseltes Gespräch mit einem beliebigen Unbekannten. Der Unterschied zwischen „Node kennt diese CA nicht“ und „Node prüft nicht mehr“ ist derselbe wie zwischen einem verschlossenen Türschloss und einem abmontierten. Die Ursache hier ist harmlos und die richtige Antwort ist genauso kurz wie die falsche.