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

  1. 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
  2. Confirm IMDS (169.254.169.254) is the real Azure endpoint and not proxied/overridden in the node's environment
  3. 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
  4. 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

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


AI-assisted analysis of kubernetes/kops@4c8573c808 (2026-09-05). Data as JSON: /api/errors/fb4e05897f29b4f9. Report an issue: GitHub.