Mensagem de erro
tls: failed to verify certificate: x509: certificate signed by unknown authority
Go crypto/tls (Go ≥ 1.20) — wrapping x509 verification errors
O que significa
Desde o Go 1.20, as falhas de handshake TLS encapsulam o erro x509 subjacente com o prefixo “tls: failed to verify certificate:”, de modo que os logs mostram tanto a camada (handshake TLS) quanto a causa raiz (a construção da cadeia falhou). O sufixo varia — autoridade desconhecida, certificado expirado, nome de host divergente — e é ele que diz o que fazer. O prefixo também é um filtro de log prático: um grep por ele separa as falhas de confiança do TLS dos erros da camada de aplicação, e foi exatamente para isso que o encapsulamento foi adicionado.
Por que acontece
Qualquer uma das causas de autoridade desconhecida
comumIntermediários ausentes, CAs privadas e contêineres sem certificados de CA — tudo o que produz “x509: certificate signed by unknown authority” agora aparece com esse prefixo quando acontece durante a abertura de uma conexão TLS (dial), e não em uma chamada explícita a Verify.
Endpoints de desenvolvimento ou autoassinados acessados por clientes com configuração padrão
comumUm http.Get contra um servidor local com certificado autoassinado (um httptest.NewTLSServer acessado de outro processo, o ingress do minikube, um proxy de desenvolvimento) falha aqui, a menos que o cliente receba a CA do servidor.
O sufixo é diferente — leia-o
ocasional“...: x509: certificate has expired” ou “...: x509: certificate is valid for X, not Y” são problemas diferentes com o mesmo prefixo; a correção depende do sufixo, não da camada TLS.
Como corrigir
- 1.
Dar ao cliente as âncoras de confiança certas
A mesma solução do erro x509 sem prefixo: um pool de certificados raiz que contenha a CA emissora, configurado no transporte HTTP que de fato abre a conexão.
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.
Inspecionar o que o servidor apresenta
Veja a cadeia servida, os emissores e a validade dela antes de mexer no código do cliente — a maioria das correções acaba sendo na configuração da cadeia no lado do servidor.
bash openssl s_client -connect internal.example:8443 -servername internal.example \ </dev/null 2>/dev/null | openssl x509 -noout -subject -issuer -dates - 3.
Manter a verificação ativada, mesmo em testes
Os servidores do httptest fornecem um cliente já configurado; use-o em vez de desativar a verificação globalmente.
go srv := httptest.NewTLSServer(handler) defer srv.Close() resp, err := srv.Client().Get(srv.URL) // trusts srv's cert, nothing else