kubernetes/kops · critical
attested vmId %q does not match %s (API vmId %q)
Error message
attested vmId %q does not match %s (API vmId %q)
What it means
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.
Source
Thrown at upup/pkg/fi/cloudup/azure/verifier.go:250
}
klog.V(2).Infof("Azure verifier for VM %q verified as node %q in instance group %q", vmLogID, nodeName, igName)
return result, nil
}
// extractNodeIdentity cross-verifies the attested vmId against the Azure API vmId for the claimed resource and
// extracts the node name and instance group from the API object. desc is a human-readable resource description
// used in errors and logs.
func extractNodeIdentity(data *attestedData, desc string, apiVMID *string, osProfile *compute.OSProfile, tags map[string]*string) (nodeName, igName string, err error) {
if apiVMID == nil {
return "", "", fmt.Errorf("determining VMID for %s", desc)
}
// Cross-verify: the vmId from the cryptographically signed attested document must match the vmId from the
// Azure API for the claimed resource ID.
klog.V(4).Infof("Azure verifier for %s cross-verifying vmId: attested=%q api=%q", desc, data.VMId, *apiVMID)
if data.VMId != *apiVMID {
return "", "", fmt.Errorf("attested vmId %q does not match %s (API vmId %q)", data.VMId, desc, *apiVMID)
}
if osProfile == nil || osProfile.ComputerName == nil || *osProfile.ComputerName == "" {
return "", "", fmt.Errorf("determining ComputerName for %s", desc)
}
nodeName = strings.ToLower(*osProfile.ComputerName)
igNameTag, ok := tags[InstanceGroupNameTag]
if !ok || igNameTag == nil {
return "", "", fmt.Errorf("determining IG name for %s", desc)
}
klog.V(4).Infof("Azure verifier for %s resolved identity: node=%q instanceGroup=%q", desc, nodeName, *igNameTag)
return nodeName, *igNameTag, nil
}
// privateIPEndpoints collects the private IP addresses and nodeup challenge endpoints from a
// network interface's IP configurations.
func privateIPEndpoints(ni network.Interface, desc string) (addrs, challengeEndpoints []string, err error) {View on GitHub (pinned to 4c8573c808)
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
Defensive patterns
Strategy: validation
Validate before calling
// On the node, before requesting verification, sanity-check local IMDS vs expectation
resp, _ := http.Get("http://169.254.169.254/metadata/instance/compute?api-version=2021-02-01") // with Metadata:true header
// ensure vmId/resourceId are for THIS node and no proxy overrides 169.254.169.254 Type guard
func hasMatchingVMID(attested, api string) bool {
return attested != "" && api != "" && attested == api
} Try / catch
nodeName, ig, err := verifier.VerifyToken(ctx, token)
if err != nil {
if strings.Contains(err.Error(), "does not match") {
// attested identity mismatch: do NOT retry with same token; re-attest a fresh document on the node
}
return err
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- verifying PKCS7 signature: %w
- validating PKCS7 signer SAN: %w
- decoding PKCS7 signature: %w
- parsing PKCS7 signature: %w
- PKCS7 signer certificate not found
AI-assisted analysis of kubernetes/kops@4c8573c808 (2026-09-05).
Data as JSON: /api/errors/fb4e05897f29b4f9.
Report an issue: GitHub.