{"record":{"id":"5a49c9f92e7955f9","repo":"kubernetes/kops","slug":"validating-pkcs7-signer-san-w","errorCode":null,"errorMessage":"validating PKCS7 signer SAN: %w","messagePattern":"validating PKCS7 signer SAN: %w","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"upup/pkg/fi/cloudup/azure/attest.go","lineNumber":262,"sourceCode":"\tp7, err := pkcs7.Parse(sigBytes)\n\tif err != nil {\n\t\treturn nil, nil, fmt.Errorf(\"parsing PKCS7 signature: %w\", err)\n\t}\n\tklog.V(8).Infof(\"Parsed PKCS7 structure with %d embedded certificate(s)\", len(p7.Certificates))\n\n\t// Verify the PKCS7 signature against the embedded leaf certificate.\n\tif err := p7.Verify(); err != nil {\n\t\treturn nil, nil, fmt.Errorf(\"verifying PKCS7 signature: %w\", err)\n\t}\n\tklog.V(4).Infof(\"PKCS7 self-signature verified\")\n\n\tsigner := p7.GetOnlySigner()\n\tif signer == nil {\n\t\treturn nil, nil, fmt.Errorf(\"PKCS7 signer certificate not found\")\n\t}\n\tklog.V(8).Infof(\"PKCS7 signer certificate: subject=%q issuer=%q SANs=%v\", signer.Subject, signer.Issuer, signer.DNSNames)\n\tif err := validateAzureMetadataSignerSAN(signer); err != nil {\n\t\treturn nil, nil, fmt.Errorf(\"validating PKCS7 signer SAN: %w\", err)\n\t}\n\tklog.V(4).Infof(\"PKCS7 signer SAN validated as Azure metadata endpoint\")\n\n\treturn p7, signer, nil\n}\n\n// nonceForBody derives the IMDS attestation nonce from the request body; the shared\n// azuremetadata implementation keeps the authenticator and verifier sides identical.\nfunc nonceForBody(body []byte) string {\n\treturn azuremetadata.NonceForBody(body)\n}\n\n// parseAndValidateAttestedDocumentContent unmarshals the signed attestation payload and validates\n// its nonce and freshness timestamps.\nfunc parseAndValidateAttestedDocumentContent(content []byte, body []byte) (*attestedData, error) {\n\tvar data attestedData\n\tif err := json.Unmarshal(content, &data); err != nil {\n\t\treturn nil, fmt.Errorf(\"unmarshalling attested data: %w\", err)","sourceCodeStart":244,"sourceCodeEnd":280,"githubUrl":"https://github.com/kubernetes/kops/blob/4c8573c808a73d578c5eadc86d410646ea0b0d73/upup/pkg/fi/cloudup/azure/attest.go#L244-L280","documentation":"This wraps a failure from validateAzureMetadataSignerSAN, which checks that the PKCS7 signer certificate's Subject Alternative Name corresponds to the Azure metadata endpoint (e.g. the certificate covering 'management.azure.com' / IMDS). Even a cryptographically valid signature is rejected here if the signer cert is not the expected Azure metadata certificate, guarding against a validly-signed but untrusted document.","triggerScenarios":"validateAzureMetadataSignerSAN(signer) inspects signer.DNSNames (logged at klog.V(8) just before the call); it errors when the signer certificate has no DNS SANs, has SANs other than the expected Azure metadata hostnames, or omits SANs entirely in favor of a subject CN.","commonSituations":"Azure rotating the IMDS signing certificate to one with different SANs while the local allowlist is outdated; using the wrong certificate in test fixtures (a generic code-signing cert without the expected SAN); a genuine security event where the document was signed by a different Azure service's certificate.","solutions":["Enable klog V(8) to log the signer's subject, issuer, and DNSNames and compare against the SAN allowlist in validateAzureMetadataSignerSAN","Update the expected SAN allowlist if Microsoft rotated the IMDS signing certificate to new hostnames (check Azure IMDS docs for the current certificate)","Ensure the code is validating the IMDS/attestation document signer, not a different Azure service's certificate; use the correct root/fetcher pairing","If this occurs unexpectedly in production, treat as a potential security signal and verify the attested document was fetched from 169.254.169.254 inside the VM"],"exampleFix":"// before\n// allowlist stale after Azure cert rotation\nif !contains(allowedSANs, signer.DNSNames...) {\n    return fmt.Errorf(\"unexpected SAN\")\n}\n// after\nallowedSANs := []string{\"metadata.azure.com\", \"management.azure.com\"} // refreshed per current Azure IMDS signing cert\nfor _, dns := range signer.DNSNames {\n    if slices.Contains(allowedSANs, strings.ToLower(dns)) {\n        return nil\n    }\n}\nreturn fmt.Errorf(\"signer SAN %v not Azure metadata endpoint\", signer.DNSNames)","handlingStrategy":"validation","validationCode":"func validateAzureMetadataSignerSAN(signer *x509.Certificate) error {\n    expected := \"management.azure.com\"\n    for _, dns := range signer.DNSNames {\n        if strings.EqualFold(dns, expected) {\n            return nil\n        }\n    }\n    return fmt.Errorf(\"signer SAN %v does not include %q\", signer.DNSNames, expected)\n}","typeGuard":"func hasAzureMetadataSAN(cert *x509.Certificate) bool {\n    for _, dns := range cert.DNSNames {\n        if strings.EqualFold(dns, \"management.azure.com\") {\n            return true\n        }\n    }\n    return false\n}","tryCatchPattern":"if err := validateAzureMetadataSignerSAN(signer); err != nil {\n    klog.V(4).Infof(\"rejecting signer: subject=%q issuer=%q SANs=%v\", signer.Subject, signer.Issuer, signer.DNSNames)\n    return nil, nil, fmt.Errorf(\"validating PKCS7 signer SAN: %w\", err)\n}","preventionTips":["Log signer SANs at V(8) so SAN mismatches are immediately diagnosable","Track Azure IMDS signing certificate rotations and refresh the SAN allowlist on upgrade","Keep the SAN validator strict — never fall back to Subject CN when SANs are missing","Treat SAN failures on real IMDS documents as a potential security incident, not just a config bug"],"tags":["azure","x509","san","attestation","security"],"backgroundTag":"certificate-san-mismatch","analyzedSha":"4c8573c808a73d578c5eadc86d410646ea0b0d73","analyzedAt":"2026-09-05T04:13:19.212Z","contentChangedAt":"2026-09-05T04:13:19.212Z","schemaVersion":2},"datasetVersion":"2026-09-12T12:17:11.808Z"}