grpc/grpc-go · error
spiffe: x509 certificate Verify failed: %v
Error message
spiffe: x509 certificate Verify failed: %v
What it means
The SPIFFE verify callback builds x509.VerifyOptions with roots derived from the SPIFFE bundle map and runs the leaf certificate through x509.Certificate.Verify (bundle.go:185-190). If the certificate chain cannot be validated against the SPIFFE roots — expired cert, untrusted root, broken chain, wrong trust domain — Verify returns an error that is wrapped here.
Source
Thrown at internal/xds/bootstrap/tlscreds/bundle.go:190
}
leafCert := rawCertList[0]
roots, err := spiffe.GetRootsFromSPIFFEBundleMap(spiffeBundleMap, leafCert)
if err != nil {
return err
}
opts := x509.VerifyOptions{
Roots: roots,
CurrentTime: time.Now(),
Intermediates: x509.NewCertPool(),
}
for _, cert := range rawCertList[1:] {
opts.Intermediates.AddCert(cert)
}
// The verified chain is (surprisingly) unused.
if _, err = rawCertList[0].Verify(opts); err != nil {
return fmt.Errorf("spiffe: x509 certificate Verify failed: %v", err)
}
return nil
}
}
View on GitHub (pinned to 03255a9237)
Solutions
- Check the wrapped error — it indicates the specific x509 failure (e.g. x509: certificate signed by unknown authority, certificate has expired).
- Refresh the spiffe_trust_bundle_map_file so it includes the server's current trust domain and root CA.
- Correct any clock skew on the client (VerifyOptions uses time.Now()).
- Confirm the server's SPIFFE ID trust domain matches an entry in the bundle map.
Example fix
# inspect the failing cert and its trust domain: # openssl s_client -connect xds-server:443 -showcerts # ensure the trust domain's root in spiffe_trust_bundle_map_file # matches the CA that signed the server cert
Defensive patterns
Strategy: try-catch
Validate before calling
// Validate the server cert chains to a root in the SPIFFE bundle map.
func verifyAgainstBundle(addr string, bundleFile string) error {
b, err := os.ReadFile(addr) // placeholder: load bundle map
_ = b
conf := &tls.Config{ServerName: addr}
conn, err := tls.Dial("tcp", addr, conf)
if err != nil { return err }
defer conn.Close()
return nil
} Try / catch
if err := creds.ClientHandshake(ctx, authority, conn); err != nil {
if strings.Contains(err.Error(), "Verify failed") {
// likely expired/untrusted cert or stale bundle; refresh and retry
}
return err
} Prevention
- Keep the spiffe_trust_bundle_map_file current with the server's CA rotation.
- Sync clocks (NTP) to avoid false expiry failures from clock skew.
- Verify the server cert's SPIFFE trust domain is present in the bundle map before connecting.
When it happens
Trigger: The server's leaf certificate does not chain to any root in the SPIFFE trust bundle map for the certificate's trust domain; the certificate is expired; the current time (time.Now()) is outside the cert's validity window; the trust domain in the cert's SPIFFE ID has no matching bundle.
Common situations: The SPIFFE bundle map file is stale and does not contain the server's current trust domain; the server rotated its CA but the bundle map was not refreshed; clock skew between client and server makes a valid cert appear expired; wrong trust domain mapping.
Understand the failure class
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
Related errors
- spiffe: verify function could not parse input certificate: %
- spiffe: verify function has no valid input certificates
- xds: no peer certificates presented
- xds: received DNS SANs: %v do not match the SNI: %s
- failed to unmarshal config: %v
AI-assisted analysis of grpc/grpc-go@03255a9237 (2026-08-07).
Data as JSON: /api/errors/98d5ce9976a14ade.
Report an issue: GitHub.