Eine erfolgreiche Anfrage über eine bestehende TLS-Verbindung beweist nicht, dass eine neue Verbindung das gewechselte Gateway-Zertifikat akzeptiert. Im isolierten Test unten übertrug die bestehende Verbindung nach dem Zertifikatswechsel weiter Daten. Eine neue Verbindung mit dem alten Truststore scheiterte dagegen. Auch der Austausch der CA-Bundle-Datei aktualisierte den bereits erzeugten Python-SSL-Kontext nicht. Erst ein neu aufgebauter Kontext mit dem vorgesehenen Truststore akzeptierte neue Verbindungen – ohne die Verifikation abzuschalten.
Für ein Inferenz-Gateway trennt dieser Unterschied einen beruhigenden Healthcheck von einem belastbaren Abnahmetest. Prüfen Sie Zertifikatskette, Dienstidentität und wirksames Client-Vertrauen getrennt. Weisen Sie anschließend nach, dass der Client damit eine neue Verbindung aufbauen kann. Dieser Beitrag beschreibt ein synthetisches Loopback-Experiment, keinen Kundenvorfall und keinen Benchmark eines KI-Anbieters.
Definieren Sie die Grenze des Zertifikatswechsels
Eine Zertifikatserneuerung unter einer bereits vertrauten CA ist nicht derselbe Eingriff wie der Wechsel zu einer anderen Root-CA. Ein neues Zwischenzertifikat, ein anderer Subject Alternative Name (SAN), eine unvollständig ausgelieferte Kette oder ein verändertes Gültigkeitsfenster können die Annahme unabhängig voneinander verhindern. Erfassen Sie Leaf-Zertifikat, Zwischenzertifikate, vorgesehene Vertrauensanker, DNS-Referenzidentität und wirksame Trust-Konfiguration je Client-Gruppe. Der Test wechselt bewusst von Root A zu Root B, damit diese Vertrauensgrenze sichtbar wird.
Die Python-Dokumentation zu ssl unterscheidet SSL-Kontexte von den damit erzeugten Sockets. Ein Kontext enthält Prüfkonfiguration und geladenes Vertrauensmaterial. Eine Bundle-Datei auf dem Datenträger, ein laufender Kontext und eine bestehende Transportverbindung sind unterschiedliche Objekte. Ein geändertes eingebundenes Secret beweist deshalb nicht, dass SDK, Prozess oder Verbindungspool es neu geladen haben.
RFC 9525 trennt die Prüfung der Dienstidentität von der Validierung des Zertifizierungspfads. Auch eine Kette einer vertrauten CA kann den falschen Dienst identifizieren. Im Test blieb die Referenzidentität model.test, obwohl das TCP-Ziel 127.0.0.1 war. Der Client übergab model.test als server_hostname und deaktivierte den Common-Name-Fallback; die erwartete Identität stand im DNS-SAN. Ersetzen Sie den Referenzhostnamen nicht durch die Ziel-IP, nur damit ein Diagnosetest verbindet.
Ausgeführter Test und bereinigtes Kettenmanifest
Der Lauf verwendete Python 3.14.9, dessen eingebundene OpenSSL-Bibliothek 3.5.9 und cryptography 50.0.1. Das separate openssl-Kommando meldete Version 3.5.5. Erfassen Sie beide OpenSSL-Versionen: CLI und Python-Bibliothek müssen nicht übereinstimmen. Die Gültigkeitsprüfungen unten liefen über die CLI; die Netzwerk-Handshakes über Pythons Bibliothek.
Der Test erzeugte temporäre RSA-2048-Schlüssel und mit SHA-256 signierte Testzertifikate. Das alte Leaf mit DNS-SAN model.test war direkt von Test-Root A signiert. Das neue Leaf, ebenfalls model.test, war von Test-Zwischenzertifikat B signiert, das zu Test-Root B führte. Ein zusätzliches Zertifikat mit falscher Identität verwendete DNS-SAN other.test unter derselben B-Kette. CA-Zertifikate enthielten CA- und Signaturberechtigungen; Leafs die Server-Auth-Verwendung. Der Server lieferte Leaf und erforderliches Zwischenzertifikat aus, nicht einen Ersatz für den Vertrauensanker des Clients.
Ein bereinigtes Manifest bewahrte Aussteller, SANs, Gültigkeitsfenster und SHA-256-Fingerprints auf. Temporäre private Schlüssel wurden beim Testende gelöscht. Produktionszertifikate, DNS-Einträge und produktive Truststores blieben unverändert. Der Loopback-Listener verwendete einen vom Betriebssystem zugewiesenen Port und ein kleines Echo-Protokoll, weder HTTP noch eine Inferenz-API. Damit bleibt TLS-Verhalten von Anwendungs-Retries und Modellausführung getrennt.
Beide Seiten waren auf TLS 1.3 beschränkt. Der Server gab keine Session-Tickets aus; erfolgreiche neue Verbindungen meldeten session_reused=false. Der Client nutzte create_default_context(cafile=...) mit aktivierter Zertifikats- und Hostnamenprüfung, deaktiviertem Common-Name-Fallback und protokollierten verify_flags=557088. Das sind beobachtete Einstellungen dieser Laufzeit, keine Zusage über jede Python-Version oder jeden SDK-Standard.
Beobachten Sie alte und neue Verbindung getrennt
Der Server wählte seinen aktuellen SSL-Kontext beim Annehmen jeder TCP-Verbindung. Der Wechsel vom alten Zertifikat zur neuen Kette betraf spätere Annahmen, nicht den bereits umhüllten Socket. Der gehaltene Socket übertrug nach dem Wechsel eine weitere Nachricht und behielt denselben Peer-Zertifikatsfingerprint. Das bedeutet nicht, dass er das neue Zertifikat authentifiziert hätte: Es fand kein neuer Handshake statt.
Verbindungsablauf – vor dem Wechsel: Client-Kontext A → vollständiger Handshake mit altem Leaf → bestehender Socket. Nach dem Listener-Wechsel: bestehender Socket → weiterer erfolgreicher Austausch, weiterhin dem alten Peer-Zertifikat zugeordnet. Getrennter Pfad: neuer Socket + Kontext A → neue B-Kette → Ablehnung. Nach explizitem Kontext-Neuaufbau: neuer Socket + Kontext B → neue B-Kette → Annahme. Erfassen Sie diese Beobachtungen getrennt statt als globales Signal „Gateway gesund“.
Das Experiment zu DNS und Verbindungspools zeigte bereits, warum eine neue DNS-Antwort bestehende Verbindungen nicht verschiebt. Dieser Test ergänzt die kryptografische Grenze, die der frühere Klartext-Test ausdrücklich nicht untersuchte. Er wiederholt keine Messung zu DNS-Zeiten, Pool-Implementierung oder Backend-Erkennung.
Handshake-Matrix: beobachtete Ergebnisse
| Verbindung / Fehler | Beobachtetes Ergebnis | Einordnung |
|---|---|---|
| Neuer Socket zum alten Server; A | Akzeptiert; nicht wiederaufgenommen | Ausgangskontrolle |
| Gehaltener Socket nach Wechsel | Austausch gelingt; gleiches Zertifikat | Kein neuer Handshake |
| Neuer Socket zum neuen Server; A | Abgelehnt: Code 20 | B-Kette nicht vertraut |
| Bundle-Datei B; bestehender Kontext A | Abgelehnt: Code 20 | Dateiwechsel ist kein Kontext-Reload |
| Neuer Server; neuer Kontext B | Akzeptiert; nicht wiederaufgenommen | Vorgesehenes B-Vertrauen geladen |
| Zwischenzertifikat fehlt; B | Abgelehnt: Code 20 | Ausgelieferte Kette unvollständig |
| Falscher SAN; B | Abgelehnt: Code 62 | Vertraute Kette, falsche Identität |
| Alter Server; neuer Kontext B | Abgelehnt: Code 20 | A nicht mehr akzeptiert |
| Alter und neuer Server; A+B | Beide akzeptiert; nicht wiederaufgenommen | Temporäre Überlappung gezeigt |
Die ausstellerbezogenen Fehler lieferten Verifikationscode 20, „unable to get local issuer certificate“; der falsche SAN lieferte Code 62, Hostname mismatch. Diese Codes beschreiben diesen Lauf. Derselbe Code kann unterschiedliche Probleme beim Kettenaufbau anzeigen. Leiten Sie aus Code 20 deshalb nicht automatisch „Root fehlt“ ab. Prüfen Sie ausgelieferte Zwischenzertifikate und vorgesehene Vertrauensanker gemeinsam.
Für den Datei-Test überschrieb der Test active.pem von ausschließlich A auf ausschließlich B. Anschließend versuchte er mit dem bestehenden Kontext eine neue Verbindung. Diese scheiterte weiterhin. Ein neu erzeugter Kontext las dieselbe Datei, akzeptierte die B-Kette und lehnte den A-Server ab. Deshalb verwendet der Test einen Kontextaustausch, statt zu behaupten, ein weiterer Ladevorgang entferne altes Vertrauen. Ein temporärer A+B-Kontext akzeptierte beide Server. Das demonstriert eine Überlappungsoption, keine Empfehlung, ausgemusterte CAs unbegrenzt zu behalten.
Prüfen Sie Hostnamen und Gültigkeit unabhängig
Die Offline-Kontrolle verwendete openssl verify mit expliziter Root-Datei, einer Datei nicht vertrauenswürdiger Zwischenzertifikate, dem Zweck sslserver und strikter X.509-Prüfung. Standard-CA-Verzeichnis und Standard-CA-Store wurden als zusätzliche Quellen deaktiviert. Die korrekte B-Kette bestand mit -verify_hostname model.test. Das other.test-Leaf bestand die Kettenprüfung ohne Hostnamenoption und scheiterte, sobald die Prüfung gegen model.test hinzukam. Eine gültige Kette allein belegte die Dienstidentität somit nicht.
Die OpenSSL-Referenz zu verify dokumentiert Ketteneingaben, Hostnamenprüfung und -attime. Der Test bewertete dasselbe neue Leaf zu zwei kontrollierten Prüfzeitpunkten: zwei Tage vor und zwei Tage nach dem Referenzzeitpunkt des Laufs. Die Leaf-Gültigkeit reichte jeweils nur einen Tag in beide Richtungen, die CA-Gültigkeit dreißig Tage. Die erste Prüfung scheiterte auf Leaf-Ebene mit Code 9, „certificate is not yet valid“; die zweite mit Code 10, „certificate has expired“. Die Systemuhr blieb unverändert.
Das waren Offline-Pfadprüfungen, keine Netzwerk-Handshakes mit simulierter Zeit. Sie isolieren die Gültigkeit, ohne die Maschinenzeit zu ändern oder eine Zeitinjektion im produktiven SDK zu behaupten. Der Test rief auch keine OCSP-Antworten oder CRLs ab und prüfte sie nicht. Vertrauter Aussteller, passender SAN und gültiger Zeitraum belegen keine getestete Widerrufsstrategie.
Entscheidungstabelle für den Betrieb
| Beobachtung | Nächste unterscheidende Prüfung | Release-Entscheidung |
|---|---|---|
| Alter Stream funktioniert; neuer Handshake scheitert | Neue Peer-Kette und geladenes Vertrauen | Nicht allein wegen Stream-Erfolg freigeben |
| Neue Root-Datei; Fehler bleiben | Kontextgeneration und Reload-Grenze | Neu aufbauen und prüfen, nicht umgehen |
| Ausstellerfehler trotz erwartetem Root | Ausgeliefertes Zwischenzertifikat und Kettenaufbau | Kette vor Rollout reparieren |
| Vertraute Kette; Hostname falsch | Referenzidentität gegen DNS-SAN | Falsche Dienstidentität ablehnen |
| Offline-Gültigkeitsfehler | Leaf-Zeitraum und vorgesehene Prüfzeit | Ausstellung oder Zeitplanung korrigieren |
| Alte CA muss entfernt werden | Neuer Kontext lehnt ausschließlich alte Kette ab | Überlappung begrenzen und Vertrauen entfernen |
Ein produktiver Abnahmenachweis sollte Client-Laufzeit und SDK, Proxy oder Service-Mesh, Bundle-Digest, Kontextgeneration, Verbindungsaufbauzeit, Referenzidentität, Peer-Fingerprint, Prüfergebnis und Session-Wiederaufnahme erfassen. Halten Sie Prompts, API-Zugangsdaten und private Schlüssel aus diesem Nachweis heraus. Verwenden Sie begrenzte Fehlerklassen in Metriken; detaillierte Zertifikatsnachweise gehören in kontrollierte Logs oder Release-Artefakte.
Verknüpfen Sie die Prüfung mit nutzerseitigen Inferenz-SLOs: Erfolgreiche alte Streams dürfen nicht den Nenner für die Gesundheit neuer Verbindungen bilden. Beobachten Sie beide Gruppen während des Wechsels. Zertifikatsfehler rechtfertigen keine unbegrenzten Verbindungsversuche; das Betriebsmodell für Retry-Budgets setzt hierfür eine eigene Begrenzung. Eine unverändert ungültige Identität wird durch Wiederholung nicht gültig.
Rollout-Checkliste mit ausdrücklichen Grenzen
1. Inventarisieren Sie die tatsächliche Vertrauensquelle des Clients und den Neulademechanismus. System-Bundle, eingebautes SDK-Bundle und explizites Anwendungs-Bundle können abweichen. Reproduzieren Sie den wirksamen Bereitstellungspfad statt nur die Shell eines Administrators.
2. Stellen Sie vorgesehene Kette und Referenzidentität isoliert bereit. Verlangen Sie Positivkontrollen sowie die Ablehnung nicht vertrauter Aussteller, fehlender Zwischenzertifikate und falscher SANs. Lassen Sie die Zertifikatsprüfung durchgehend aktiviert.
3. Wenn Ihre Richtlinie temporäres A+B-Vertrauen erlaubt, definieren Sie Verantwortliche und Entfernungskriterium. Eine zusätzliche CA erweitert den Kreis akzeptierter Aussteller. Das ist kein neutraler Verfügbarkeitsschalter und ungeeignet, wenn A sofort das Vertrauen entzogen werden muss.
4. Erzeugen und prüfen Sie einen neuen Client-Kontext oder verwenden Sie den dokumentierten Neulademechanismus. Weisen Sie vor neuer Arbeitszuweisung nach, dass neue Verbindungen ihn verwenden. Ein veränderter Dateihash allein belegt das nicht.
5. Weisen Sie auslaufenden Pools keine neue Arbeit zu und lassen Sie aktive Streams innerhalb definierter Fristen auslaufen. Erzwungener Verbindungswechsel kostet Handshakes und kann Teilgenerierungen unterbrechen. Ein dringender Vertrauensentzug kann das Beenden bestehender Sitzungen erfordern. Das ist eine separate Risikoentscheidung, deren Sicherheit dieser verfügbarkeitsorientierte Test nicht nachweist.
6. Prüfen Sie Wiederaufnahme, mTLS, Widerruf, Proxy-Hops und das tatsächliche SDK bei Bedarf separat. Ein vollständiger Handshake mit deaktivierten Tickets belegt nicht das Verhalten wiederaufgenommener Sitzungen während eines Wechsels. HTTP/2-Multiplexing, Auswahl kreuzsignierter Ketten und produktive Reload-Rennen wurden ebenfalls nicht gemessen.
7. Entfernen Sie altes Vertrauen über eine ersetzende Konfiguration und weisen Sie nach, dass die ausschließlich alte Kette auf einer neuen Verbindung abgelehnt wird. Erhalten Sie eine freigegebene Rollback-Grenze, ohne stillschweigend einer sicherheitspolitisch ausgeschlossenen CA wieder zu vertrauen.
Der Zielkonflikt ist klar: Langlebige Verbindungen reduzieren Aufbaukosten, können aber Fehler neuer Handshakes verdecken. Aggressives Ausmustern macht die neue Konfiguration früher sichtbar, erzeugt jedoch zusätzliche Verbindungswechsel und kann nützliche Arbeit unterbrechen. Das Experiment belegt Annahmeentscheidungen, keinen Latenzgewinn und keine allgemeingültige Drain-Frist.
Machen Sie den nächsten Wechsel zu einem belegbaren Release
Bringen Sie vor dem nächsten Zertifikatswechsel am Inferenz-Gateway eine Client-/Pool-Konfiguration, das geplante Zertifikatskettenmanifest und die vorgesehene Richtlinie zum Vertrauensentzug in ein Implementierungsreview mit Ade Christanto ein. Das praktische Ergebnis sollte eine reproduzierbare positive und negative Handshake-Matrix, eine dokumentierte Grenze des Kontext-Neuladens und ein Plan zum sicheren Auslaufen aktiver Streams sein. Eine grüne Anfrage über die gestrige Verbindung ist keine Release-Abnahme.


