grpc/grpc-go · error

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

Error message

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

What it means

Returned by GetRootsFromSPIFFEBundleMap when the peer's leaf certificate cannot yield a SPIFFE ID via idFromCert, even though the caller configured SPIFFE Bundle Map verification. The wrapped error is whatever idFromCert produced (nil cert, wrong URI count, or an unparseable URI). This is a handshake-time failure: verification was requested but the presented cert is not a conformant SPIFFE certificate.

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 03255a9237)

Solutions

  1. Ensure the peer workload is enrolled in SPIRE and its cert carries exactly one spiffe:// URI SAN.
  2. If legacy certs must coexist, do not configure SPIFFEBundleMap globally; segment traffic so only SPIFFE-issuing clusters use it.
  3. Inspect the peer leaf cert with openssl x509 -text and confirm the URI SAN is present and well-formed.
  4. Re-issue the peer's cert through its SPIRE workload agent.
Defensive patterns

Strategy: validation

Validate before calling

func leafHasValidSVID(c *x509.Certificate) error {
    if c == nil { return errors.New("nil cert") }
    if len(c.URIs) != 1 { return fmt.Errorf("expected 1 URI SAN, got %d", len(c.URIs)) }
    if _, err := spiffeid.FromURI(c.URIs[0]); err != nil { return err }
    return nil
}

Type guard

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

Try / catch

roots, err := spiffe.GetRootsFromSPIFFEBundleMap(bm, leaf)
if err != nil && strings.Contains(err.Error(), "could not get spiffe ID") {
    // peer is not a SPIFFE workload; fail closed and audit the cert
}

Prevention

When it happens

Trigger: A peer presents a non-SPIFFE cert (no URI SAN, multiple URI SANs, or a URI SAN that is not a spiffe:// URI) while the server/client has km.SPIFFEBundleMap set in its key material. Triggered from buildVerifyFunc at handshake_info.go:281.

Common situations: Mixed environment where some workloads use SPIFFE mTLS and others use traditional mTLS; misconfigured SPIRE agent that issued a cert without the URI SAN; a cert rotated by a non-SPIFFE CA; turning on SPIFFE verification against endpoints that still serve legacy certs.

Related errors


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