{"record":{"id":"822a9eaf0cd963e9","repo":"kubernetes/kops","slug":"missing-resource-id","errorCode":null,"errorMessage":"missing resource ID","messagePattern":"missing resource ID","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"upup/pkg/fi/cloudup/azure/azuremetadata/authenticator.go","lineNumber":56,"sourceCode":"\treturn &azureAuthenticator{}, nil\n}\n\n// CreateToken fetches the local VM identity from IMDS and returns a bootstrap token containing the\n// resource ID and signed attested document.\nfunc (h *azureAuthenticator) CreateToken(body []byte) (string, error) {\n\tklog.V(4).Infof(\"Azure authenticator creating bootstrap token\")\n\n\t// bootstrap.Authenticator.CreateToken carries no context; the IMDS HTTP client's own timeout\n\t// bounds these calls.\n\tctx := context.TODO()\n\n\t// Query IMDS for the VM's resource ID.\n\tmetadata, err := QueryComputeInstanceMetadata(ctx)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"querying instance metadata: %w\", err)\n\t}\n\tif metadata.ResourceID == \"\" {\n\t\treturn \"\", fmt.Errorf(\"missing resource ID\")\n\t}\n\tklog.V(4).Infof(\"Azure authenticator obtained resource ID %q\", metadata.ResourceID)\n\n\t// Query IMDS for a PKCS7-signed attested document containing the nonce.\n\tnonce := NonceForBody(body)\n\tdoc, err := queryIMDSAttestedDocument(ctx, nonce)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"querying attested document: %w\", err)\n\t}\n\tif doc.Signature == \"\" {\n\t\treturn \"\", fmt.Errorf(\"empty attested document signature\")\n\t}\n\tklog.V(2).Infof(\"Azure authenticator obtained attested document for %q\", metadata.ResourceID)\n\n\t// Token format: \"x-azure-id <resourceID> <base64-pkcs7-signature>\"\n\treturn AzureAuthenticationTokenPrefix + metadata.ResourceID + \" \" + doc.Signature, nil\n}\n","sourceCodeStart":38,"sourceCodeEnd":74,"githubUrl":"https://github.com/kubernetes/kops/blob/4c8573c808a73d578c5eadc86d410646ea0b0d73/upup/pkg/fi/cloudup/azure/azuremetadata/authenticator.go#L38-L74","documentation":"CreateToken successfully fetched IMDS compute metadata, but the resourceId field in the JSON response was empty. The authenticator refuses to mint a token without a resource ID because the server side validates node identity against the VM's Azure resource ID. This guards against a malformed or degenerate IMDS response being treated as a valid identity.","triggerScenarios":"QueryComputeInstanceMetadata returns a decodable JSON document whose resourceId field is an empty string (field absent or null also unmarshal to \"\").","commonSituations":"A middlebox or captive portal returning 200 with unexpected JSON at 169.254.169.254; very old/unusual IMDS api-version responses lacking resourceId; VM created outside a normal ARM deployment context; response shape drift after Azure API changes.","solutions":["Run the curl IMDS check and inspect whether resourceId is present in the JSON; if absent, verify the api-version and that the VM is a normal Azure Resource Manager VM","Confirm nothing is spoofing/intercepting 169.254.169.254 (check dnsmasq, custom routes, link-local routing)","Recreate the VM if it was provisioned in a way that lacks an ARM resource ID (e.g. classic resources)","Upgrade kOps/nodeup so the pinned imdsAPIVersion matches a response that includes resourceId"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// Validate the IMDS payload yourself before relying on it\nvar md struct {\n    ResourceID string `json:\"resourceId\"`\n}\nif err := json.Unmarshal(body, &md); err != nil { return err }\nif md.ResourceID == \"\" {\n    return fmt.Errorf(\"IMDS metadata lacks resourceId; not a valid ARM VM response\")\n}","typeGuard":"func hasResourceID(m *azuremetadata.InstanceMetadata) bool {\n    return m != nil && m.ResourceID != \"\"\n}","tryCatchPattern":null,"preventionTips":["Inspect the raw IMDS instance JSON once per image and assert resourceId is present","Ensure VMs are created via Azure Resource Manager (not classic) so resourceId exists","Block software (VPN clients, dnsmasq, custom routes) that can answer on 169.254.169.254","Re-run this check after Azure api-version upgrades"],"tags":["azure","imds","identity","bootstrap"],"backgroundTag":"missing-instance-identity","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"}