Fehlermeldung
tls: failed to verify certificate: x509: certificate signed by unknown authority
Go crypto/tls (Go ≥ 1.20) — wrapping x509 verification errors
Was der Fehler bedeutet
Seit Go 1.20 verpacken fehlgeschlagene TLS-Handshakes den zugrunde liegenden x509-Fehler mit dem Präfix „tls: failed to verify certificate:“, sodass Logs sowohl die Ebene (TLS-Handshake) als auch die eigentliche Ursache zeigen (der Aufbau der Kette ist fehlgeschlagen). Das Suffix variiert – unbekannte Zertifizierungsstelle, abgelaufen, nicht passender Hostname – und ist der Teil, an dem du ansetzen musst. Das Präfix taugt außerdem als Log-Filter: Ein grep danach trennt TLS-Vertrauensfehler von Fehlern auf Anwendungsebene – genau dafür wurde das Verpacken eingeführt.
Warum der Fehler auftritt
Jede Ursache von „unknown authority“
häufigFehlende Zwischenzertifikate, private CAs und Container ohne CA-Bundle – alles, was „x509: certificate signed by unknown authority“ auslöst, erscheint jetzt mit diesem Präfix, wenn es beim TLS-Verbindungsaufbau (Dial) passiert statt in einem expliziten Aufruf von Verify.
Standard-Clients rufen Entwicklungs- oder selbstsignierte Endpunkte auf
häufighttp.Get gegen einen lokalen Server mit selbstsigniertem Zertifikat (httptest.NewTLSServer aus einem anderen Prozess, ein Ingress in minikube, ein Entwicklungs-Proxy) scheitert hier, sofern der Client nicht die CA des Servers erhält.
Das Suffix unterscheidet sich – lies es
gelegentlich„...: x509: certificate has expired“ oder „...: x509: certificate is valid for X, not Y“ sind verschiedene Probleme mit demselben Präfix; die Lösung richtet sich nach dem Suffix, nicht nach der TLS-Ebene.
So behebst du den Fehler
- 1.
Dem Client die richtigen Vertrauensanker geben
Dieselbe Abhilfe wie beim x509-Fehler ohne Präfix: ein Root-Pool mit der ausstellenden CA, gesetzt auf dem Transport, der für den Verbindungsaufbau tatsächlich verwendet wird.
go pool := x509.NewCertPool() caPEM, _ := os.ReadFile("ca.pem") pool.AppendCertsFromPEM(caPEM) client := &http.Client{Transport: &http.Transport{ TLSClientConfig: &tls.Config{RootCAs: pool}, }} resp, err := client.Get("https://internal.example:8443/healthz") - 2.
Untersuchen, was der Server vorlegt
Sieh dir die ausgelieferte Kette, ihre Aussteller und ihre Gültigkeit an, bevor du Client-Code anfasst – die meisten Korrekturen stellen sich als serverseitige Konfiguration der Kette heraus.
bash openssl s_client -connect internal.example:8443 -servername internal.example \ </dev/null 2>/dev/null | openssl x509 -noout -subject -issuer -dates - 3.
Prüfung eingeschaltet lassen, auch in Tests
httptest-Server liefern dir einen vorkonfigurierten Client; verwende ihn, statt die Prüfung global abzuschalten.
go srv := httptest.NewTLSServer(handler) defer srv.Close() resp, err := srv.Client().Get(srv.URL) // trusts srv's cert, nothing else