{"record":{"id":"fb4e05897f29b4f9","repo":"kubernetes/kops","slug":"attested-vmid-q-does-not-match-s-api-vmid-q","errorCode":null,"errorMessage":"attested vmId %q does not match %s (API vmId %q)","messagePattern":"attested vmId %q does not match (.+?) \\(API vmId %q\\)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"upup/pkg/fi/cloudup/azure/verifier.go","lineNumber":250,"sourceCode":"\t}\n\n\tklog.V(2).Infof(\"Azure verifier for VM %q verified as node %q in instance group %q\", vmLogID, nodeName, igName)\n\treturn result, nil\n}\n\n// extractNodeIdentity cross-verifies the attested vmId against the Azure API vmId for the claimed resource and\n// extracts the node name and instance group from the API object. desc is a human-readable resource description\n// used in errors and logs.\nfunc extractNodeIdentity(data *attestedData, desc string, apiVMID *string, osProfile *compute.OSProfile, tags map[string]*string) (nodeName, igName string, err error) {\n\tif apiVMID == nil {\n\t\treturn \"\", \"\", fmt.Errorf(\"determining VMID for %s\", desc)\n\t}\n\n\t// Cross-verify: the vmId from the cryptographically signed attested document must match the vmId from the\n\t// Azure API for the claimed resource ID.\n\tklog.V(4).Infof(\"Azure verifier for %s cross-verifying vmId: attested=%q api=%q\", desc, data.VMId, *apiVMID)\n\tif data.VMId != *apiVMID {\n\t\treturn \"\", \"\", fmt.Errorf(\"attested vmId %q does not match %s (API vmId %q)\", data.VMId, desc, *apiVMID)\n\t}\n\tif osProfile == nil || osProfile.ComputerName == nil || *osProfile.ComputerName == \"\" {\n\t\treturn \"\", \"\", fmt.Errorf(\"determining ComputerName for %s\", desc)\n\t}\n\n\tnodeName = strings.ToLower(*osProfile.ComputerName)\n\tigNameTag, ok := tags[InstanceGroupNameTag]\n\tif !ok || igNameTag == nil {\n\t\treturn \"\", \"\", fmt.Errorf(\"determining IG name for %s\", desc)\n\t}\n\tklog.V(4).Infof(\"Azure verifier for %s resolved identity: node=%q instanceGroup=%q\", desc, nodeName, *igNameTag)\n\n\treturn nodeName, *igNameTag, nil\n}\n\n// privateIPEndpoints collects the private IP addresses and nodeup challenge endpoints from a\n// network interface's IP configurations.\nfunc privateIPEndpoints(ni network.Interface, desc string) (addrs, challengeEndpoints []string, err error) {","sourceCodeStart":232,"sourceCodeEnd":268,"githubUrl":"https://github.com/kubernetes/kops/blob/4c8573c808a73d578c5eadc86d410646ea0b0d73/upup/pkg/fi/cloudup/azure/verifier.go#L232-L268","documentation":"kOps' Azure nodeup token verifier fails closed when the vmId inside the cryptographically signed attested (vTPM) document does not equal the vmId returned by the Azure API for the resource ID the token claims. This prevents a node from replaying a signed document belonging to a different VM, so any mismatch aborts node identity extraction.","triggerScenarios":"extractNodeIdentity fetches the VM via the Azure compute API for the resource ID claimed in the token, then compares attested data.VMId against *apiVMID; any inequality (including case or casing differences in Azure's IDs is unlikely, but a genuinely different VM) triggers it.","commonSituations":"A token/attested document was generated on one VM and replayed on another; a load balancer or stale IMDS cache served metadata from a different instance; tests or proxies intercept IMDS and return mismatched data; cluster rebuilt with recycled hostnames pointing at the wrong resource.","solutions":["Verify the VM making the request is the same VM whose resource ID it claims; check the log line 'cross-verifying vmId: attested=... api=...' for the two IDs","Confirm IMDS (169.254.169.254) is the real Azure endpoint and not proxied/overridden in the node's environment","Check for VM re-creation or disk/identity reuse: if the VM was recreated, old attested documents are invalid; re-run nodeup so a fresh document is attested","Ensure the resource ID in the token resolves in the same subscription/resource group the verifier client is scoped to"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// On the node, before requesting verification, sanity-check local IMDS vs expectation\nresp, _ := http.Get(\"http://169.254.169.254/metadata/instance/compute?api-version=2021-02-01\") // with Metadata:true header\n// ensure vmId/resourceId are for THIS node and no proxy overrides 169.254.169.254","typeGuard":"func hasMatchingVMID(attested, api string) bool {\n\treturn attested != \"\" && api != \"\" && attested == api\n}","tryCatchPattern":"nodeName, ig, err := verifier.VerifyToken(ctx, token)\nif err != nil {\n\tif strings.Contains(err.Error(), \"does not match\") {\n\t\t// attested identity mismatch: do NOT retry with same token; re-attest a fresh document on the node\n\t}\n\treturn err\n}","preventionTips":["Never proxy or cache IMDS responses across VMs","Re-run nodeup to mint a fresh attested document after any VM recreation","Keep kOps-managed resource IDs stable; avoid renaming/moving VMs between resource groups","Monitor verifier logs for 'cross-verifying vmId' anomalies"],"tags":["azure","security","attestation","identity"],"backgroundTag":"attested-vmid-mismatch","analyzedSha":"4c8573c808a73d578c5eadc86d410646ea0b0d73","analyzedAt":"2026-09-05T04:13:19.212Z","contentChangedAt":"2026-09-05T04:13:19.212Z","schemaVersion":2},"datasetVersion":"2026-09-12T07:17:12.445Z"}