{"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/0c51461d27177d997e14c642fe18c11668fc09a3/internal/credentials/spiffe/spiffe.go#L56-L92","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Ensure the peer workload's certificate is minted by a SPIFFE-compatible CA (SPIRE, Istio CA, etc.) and carries exactly one spiffe:// URI SAN.","If non-SPIFFE clients must connect, separate them onto a listener that does not use a SPIFFE trust map.","Inspect the peer cert with openssl x509 -text and check the URI SAN section.","Confirm the certificate chain is assembled correctly so the leaf reaches idFromCert non-nil."],"exampleFix":"// before: peer cert has DNS SANs only, verified via SPIFFE map -> error\n// after: mint peer cert with one spiffe://example.org/workload URI SAN","handlingStrategy":"type-guard","validationCode":"func peerCertIsSpiffe(c *x509.Certificate) bool {\n    return c != nil && len(c.URIs) == 1 && strings.HasPrefix(c.URIs[0].String(), \"spiffe://\")\n}\n// gate GetRootsFromSPIFFEBundleMap on this","typeGuard":"func isSPIFFELeaf(c *x509.Certificate) bool {\n    if c == nil || len(c.URIs) != 1 { return false }\n    if _, err := spiffeid.FromURI(c.URIs[0]); err != nil { return false }\n    return true\n}","tryCatchPattern":"In a custom VerifyPeerCertificate callback, check isSPIFFELeaf on the parsed leaf first; if false, return a clear non-SPIFFE error rather than calling GetRootsFromSPIFFEBundleMap.","preventionTips":["Only enable SPIFFE trust-map verification on listeners that exclusively receive SPIFFE workloads.","Issue certs from a SPIFFE-aware CA that guarantees one spiffe:// URI SAN.","Unit-test verification with both SPIFFE and non-SPIFFE peer certs."],"tags":["grpc","spiffe","tls","mtls","certificates","security"],"backgroundTag":null,"analyzedSha":"0c51461d27177d997e14c642fe18c11668fc09a3","analyzedAt":"2026-08-11T14:49:15.055Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}