Mensaje de error
tls: failed to verify certificate: x509: certificate signed by unknown authority
Go crypto/tls (Go ≥ 1.20) — wrapping x509 verification errors
Qué significa
Desde Go 1.20, los fallos del handshake TLS envuelven el error x509 subyacente con el prefijo «tls: failed to verify certificate:», de modo que los registros muestran tanto la capa (el handshake TLS) como la causa raíz (falló la construcción de la cadena). El sufijo varía —autoridad desconocida, certificado caducado, nombre de host que no coincide— y es la parte sobre la que hay que actuar. El prefijo también sirve como filtro práctico de registros: buscarlo con grep separa los fallos de confianza TLS de los errores de la aplicación, y precisamente por eso se añadió el envoltorio.
Por qué ocurre
Cualquiera de las causas de autoridad desconocida
frecuenteIntermedios que faltan, CA privadas y contenedores sin CA: todo lo que produce «x509: certificate signed by unknown authority» aparece ahora con este prefijo cuando ocurre al establecer una conexión TLS y no en una llamada explícita a Verify.
Endpoints de desarrollo o autofirmados consultados con clientes por defecto
frecuentehttp.Get contra un servidor local con un certificado autofirmado (httptest.NewTLSServer desde otro proceso, el ingress de minikube, un proxy de desarrollo) falla aquí, a menos que se le dé al cliente la CA del servidor.
El sufijo es distinto: léelo
ocasional«...: x509: certificate has expired» o «...: x509: certificate is valid for X, not Y» son problemas distintos con el mismo prefijo; la solución depende del sufijo, no de la capa TLS.
Cómo solucionarlo
- 1.
Dar al cliente las anclas de confianza correctas
El mismo remedio que para el error x509 sin prefijo: un pool de raíces que contenga la CA emisora, configurado en el transporte que realmente se usa para la conexión.
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.
Inspeccionar lo que presenta el servidor
Revisa la cadena que envía el servidor, sus emisores y su validez antes de tocar el código del cliente: la mayoría de las soluciones acaban siendo de configuración de la cadena en el servidor.
bash openssl s_client -connect internal.example:8443 -servername internal.example \ </dev/null 2>/dev/null | openssl x509 -noout -subject -issuer -dates - 3.
Mantener la verificación activada, incluso en las pruebas
Los servidores de httptest te dan un cliente ya configurado; úsalo en lugar de desactivar la verificación de forma global.
go srv := httptest.NewTLSServer(handler) defer srv.Close() resp, err := srv.Client().Get(srv.URL) // trusts srv's cert, nothing else