grpc/grpc-go · error

spiffe: could not get spiffe ID from peer leaf cert but…

Error message

spiffe: could not get spiffe ID from peer leaf cert but verification with spiffe trust map was configured: %v

What it means

Raised by GetRootsFromSPIFFEBundleMap when idFromCert fails on the peer's leaf certificate. A SPIFFE trust map was configured (so SPIFFE verification is expected), but the peer cert is not a valid SPIFFE leaf: it is nil, has a URI SAN count other than 1, or its URI is not a parseable SPIFFE ID. The underlying idFromCert error is appended.

Solutions

  1. Ensure the peer workload's certificate is minted by a SPIFFE-compatible CA (SPIRE, Istio CA, etc.) and carries exactly one spiffe:// URI SAN.
  2. If non-SPIFFE clients must connect, separate them onto a listener that does not use a SPIFFE trust map.
  3. Inspect the peer cert with openssl x509 -text and check the URI SAN section.
  4. Confirm the certificate chain is assembled correctly so the leaf reaches idFromCert non-nil.

Example fix

// before: peer cert has DNS SANs only, verified via SPIFFE map -> error
// after: mint peer cert with one spiffe://example.org/workload URI SAN
Defensive patterns

Strategy: type-guard

Validate before calling

func peerCertIsSpiffe(c *x509.Certificate) bool {
    return c != nil && len(c.URIs) == 1 && strings.HasPrefix(c.URIs[0].String(), "spiffe://")
}
// gate GetRootsFromSPIFFEBundleMap on this

Type guard

func isSPIFFELeaf(c *x509.Certificate) bool {
    if c == nil || len(c.URIs) != 1 { return false }
    if _, err := spiffeid.FromURI(c.URIs[0]); err != nil { return false }
    return true
}

Try / catch

In a custom VerifyPeerCertificate callback, check isSPIFFELeaf on the parsed leaf first; if false, return a clear non-SPIFFE error rather than calling GetRootsFromSPIFFEBundleMap.

Prevention

When it happens

Trigger: A client connects with mTLS but presents a certificate without a SPIFFE URI SAN (a traditional DNS-SAN cert), with multiple URIs, with a non-spiffe:// URI, or the cert chain arrived as nil during verification.

Common situations: Mixing SPIFFE-based mTLS verification with non-SPIFFE workloads on the same listener; a workload cert generated by a non-SPIFFE CA; cert rotation producing a cert with zero URIs; misconfigured cert chain assembly delivering nil.

Related errors


AI-assisted analysis of grpc/grpc-go@0c51461d27 (2026-08-11). Data as JSON: /api/errors/759b5fbd856242a1. Report an issue: GitHub.

Appendix: source

Thrown at internal/credentials/spiffe/spiffe.go:74

		}
		bundle, err := spiffebundle.Parse(trustDomain, jsonBundle)
		if err != nil {
			return nil, fmt.Errorf("spiffe: BundleMapFromBytes() failed to parse bundle for trust domain %q: %v", td, err)
		}
		bundleMap[td] = bundle
	}
	return bundleMap, nil
}

// GetRootsFromSPIFFEBundleMap returns the root trust certificates from the
// SPIFFE bundle map for the given trust domain from the leaf certificate.
func GetRootsFromSPIFFEBundleMap(bundleMap map[string]*spiffebundle.Bundle, leafCert *x509.Certificate) (*x509.CertPool, error) {
	// 1. Upon receiving a peer certificate, verify that it is a well-formed SPIFFE
	//    leaf certificate.  In particular, it must have a single URI SAN containing
	//    a well-formed SPIFFE ID ([SPIFFE ID format]).
	spiffeID, err := idFromCert(leafCert)
	if err != nil {
		return nil, fmt.Errorf("spiffe: could not get spiffe ID from peer leaf cert but verification with spiffe trust map was configured: %v", err)
	}

	// 2. Use the trust domain in the peer certificate's SPIFFE ID to lookup
	//    the SPIFFE trust bundle. If the trust domain is not contained in the
	//    configured trust map, reject the certificate.
	spiffeBundle, ok := bundleMap[spiffeID.TrustDomain().Name()]
	if !ok {
		return nil, fmt.Errorf("spiffe: no bundle found for peer certificates trust domain %q but verification with a SPIFFE trust map was configured", spiffeID.TrustDomain().Name())
	}
	roots := spiffeBundle.X509Authorities()
	rootPool := x509.NewCertPool()
	for _, root := range roots {
		rootPool.AddCert(root)
	}
	return rootPool, nil
}

// idFromCert parses the SPIFFE ID from the x509.Certificate. If the certificate

View on GitHub (pinned to 0c51461d27)