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

  1. Check the wrapped error — it indicates the specific x509 failure (e.g. x509: certificate signed by unknown authority, certificate has expired).
  2. Refresh the spiffe_trust_bundle_map_file so it includes the server's current trust domain and root CA.
  3. Correct any clock skew on the client (VerifyOptions uses time.Now()).
  4. 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

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

Related errors


AI-assisted analysis of grpc/grpc-go@03255a9237 (2026-08-07). Data as JSON: /api/errors/98d5ce9976a14ade. Report an issue: GitHub.