← Debugging Guides

阅读中文版本

Go: x509: certificate signed by unknown authority

Fix the Go TLS error "x509: certificate signed by unknown authority" by trusting a private CA, correcting SNI, and avoiding blanket InsecureSkipVerify.

intermediatedebugginggotlssecurity

Symptoms

  • x509: certificate signed by unknown authority
  • HTTPS calls fail in containers but succeed on the developer machine
  • The error mentions a self-signed or internal certificate

Possible causes

  • The server presents a certificate from a private CA not in the system trust store
  • The trust store is missing inside a minimal container image
  • A custom http.Client replaced tls.Config with a partial RootCAs pool
  • The hostname does not match, masking the real cause of the trust error

Diagnosis steps

Inspect the served chain

openssl s_client -connect host:443 -showcerts </dev/null

Interpretation

The issuer of the leaf tells you which CA must be trusted; a self-signed leaf has no chain.

Check the client trust store

ls /etc/ssl/certs/ca-certificates.crt

Interpretation

A missing or empty bundle in a slim image explains failures that only occur in containers.

Verify the server name sent in SNI

Interpretation

Connecting by IP or wrong host can make the server present a different cert, confusing the diagnosis.

Root cause

Go verifies the server certificate against the system trust store plus any RootCAs you configure. A certificate issued by a private or internal CA is not in that store, so verification fails with an unknown-authority error even though the connection is cryptographically valid. Slim containers often omit the CA bundle entirely.

Fix

Add the issuing CA to the system store (install ca-certificates, copy the PEM), or supply it via tls.Config.RootCAs. Never reach for InsecureSkipVerify in production; scope trust to the specific CA and keep the hostname check enabled. For mutual TLS, load client certs explicitly.

Verify the fix

Re-run the request against the same host from the container; the handshake completes and the response is received, while the trust store is confirmed to hold the expected CA.

Symptoms

An HTTPS call returns x509: certificate signed by unknown authority. It often works locally but fails in CI or a container, which points at the trust store rather than the server.

Diagnosis

Inspect the served chain and the client trust store:

openssl s_client -connect api.internal:443 -showcerts </dev/null
ls /etc/ssl/certs/ca-certificates.crt

If the issuer is an internal CA, that CA must be trusted by the client.

Fix

Trust the specific CA in code, or install it system-wide:

pool := x509.NewCertPool()
pem, _ := os.ReadFile("/etc/ssl/internal-ca.pem")
pool.AppendCertsFromPEM(pem)
client := &http.Client{Transport: &http.Transport{
    TLSClientConfig: &tls.Config{RootCAs: pool},
}}

In a slim image, install ca-certificates and add the PEM.

Verification

Re-run the request inside the container; the TLS handshake succeeds and the response arrives, with the expected CA present in the trust store.