{"record":{"id":"759b5fbd856242a1","repo":"grpc/grpc-go","slug":"spiffe-could-not-get-spiffe-id-from-peer-leaf-cer","errorCode":null,"errorMessage":"spiffe: could not get spiffe ID from peer leaf cert but verification with spiffe trust map was configured: %v","messagePattern":"spiffe: could not get spiffe ID from peer leaf cert but verification with spiffe trust map was configured: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/credentials/spiffe/spiffe.go","lineNumber":74,"sourceCode":"\t\t}\n\t\tbundle, err := spiffebundle.Parse(trustDomain, jsonBundle)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"spiffe: BundleMapFromBytes() failed to parse bundle for trust domain %q: %v\", td, err)\n\t\t}\n\t\tbundleMap[td] = bundle\n\t}\n\treturn bundleMap, nil\n}\n\n// GetRootsFromSPIFFEBundleMap returns the root trust certificates from the\n// SPIFFE bundle map for the given trust domain from the leaf certificate.\nfunc GetRootsFromSPIFFEBundleMap(bundleMap map[string]*spiffebundle.Bundle, leafCert *x509.Certificate) (*x509.CertPool, error) {\n\t// 1. Upon receiving a peer certificate, verify that it is a well-formed SPIFFE\n\t//    leaf certificate.  In particular, it must have a single URI SAN containing\n\t//    a well-formed SPIFFE ID ([SPIFFE ID format]).\n\tspiffeID, err := idFromCert(leafCert)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"spiffe: could not get spiffe ID from peer leaf cert but verification with spiffe trust map was configured: %v\", err)\n\t}\n\n\t// 2. Use the trust domain in the peer certificate's SPIFFE ID to lookup\n\t//    the SPIFFE trust bundle. If the trust domain is not contained in the\n\t//    configured trust map, reject the certificate.\n\tspiffeBundle, ok := bundleMap[spiffeID.TrustDomain().Name()]\n\tif !ok {\n\t\treturn 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())\n\t}\n\troots := spiffeBundle.X509Authorities()\n\trootPool := x509.NewCertPool()\n\tfor _, root := range roots {\n\t\trootPool.AddCert(root)\n\t}\n\treturn rootPool, nil\n}\n\n// idFromCert parses the SPIFFE ID from the x509.Certificate. If the certificate","sourceCodeStart":56,"sourceCodeEnd":92,"githubUrl":"https://github.com/grpc/grpc-go/blob/03255a9237b6eb32710f6bc4f2de9a675b99fe36/internal/credentials/spiffe/spiffe.go#L56-L92","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Ensure the peer workload is enrolled in SPIRE and its cert carries exactly one spiffe:// URI SAN.","If legacy certs must coexist, do not configure SPIFFEBundleMap globally; segment traffic so only SPIFFE-issuing clusters use it.","Inspect the peer leaf cert with openssl x509 -text and confirm the URI SAN is present and well-formed.","Re-issue the peer's cert through its SPIRE workload agent."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"func leafHasValidSVID(c *x509.Certificate) error {\n    if c == nil { return errors.New(\"nil cert\") }\n    if len(c.URIs) != 1 { return fmt.Errorf(\"expected 1 URI SAN, got %d\", len(c.URIs)) }\n    if _, err := spiffeid.FromURI(c.URIs[0]); err != nil { return err }\n    return nil\n}","typeGuard":"func isSPIFFESVID(c *x509.Certificate) bool {\n    if c == nil || len(c.URIs) != 1 { return false }\n    _, err := spiffeid.FromURI(c.URIs[0])\n    return err == nil\n}","tryCatchPattern":"roots, err := spiffe.GetRootsFromSPIFFEBundleMap(bm, leaf)\nif err != nil && strings.Contains(err.Error(), \"could not get spiffe ID\") {\n    // peer is not a SPIFFE workload; fail closed and audit the cert\n}","preventionTips":["Do not enable SPIFFE bundle map verification on endpoints that serve non-SPIFFE certs.","Gate SPIFFE mTLS per cluster/listener to avoid mixed-identity failures.","Audit peer certs in staging to confirm URI SANs before enforcing in production."],"tags":["grpc","spiffe","mtls","x509","handshake"],"analyzedSha":"03255a9237b6eb32710f6bc4f2de9a675b99fe36","analyzedAt":"2026-08-07T00:29:34.215Z","schemaVersion":2},"datasetVersion":"2026-08-07T03:17:09.362Z"}