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.
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/nullInterpretation
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.crtInterpretation
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.