kubernetes/kops · error
missing resource ID
Error message
missing resource ID
What it means
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.
Source
Thrown at upup/pkg/fi/cloudup/azure/azuremetadata/authenticator.go:56
return &azureAuthenticator{}, nil
}
// CreateToken fetches the local VM identity from IMDS and returns a bootstrap token containing the
// resource ID and signed attested document.
func (h *azureAuthenticator) CreateToken(body []byte) (string, error) {
klog.V(4).Infof("Azure authenticator creating bootstrap token")
// bootstrap.Authenticator.CreateToken carries no context; the IMDS HTTP client's own timeout
// bounds these calls.
ctx := context.TODO()
// Query IMDS for the VM's resource ID.
metadata, err := QueryComputeInstanceMetadata(ctx)
if err != nil {
return "", fmt.Errorf("querying instance metadata: %w", err)
}
if metadata.ResourceID == "" {
return "", fmt.Errorf("missing resource ID")
}
klog.V(4).Infof("Azure authenticator obtained resource ID %q", metadata.ResourceID)
// Query IMDS for a PKCS7-signed attested document containing the nonce.
nonce := NonceForBody(body)
doc, err := queryIMDSAttestedDocument(ctx, nonce)
if err != nil {
return "", fmt.Errorf("querying attested document: %w", err)
}
if doc.Signature == "" {
return "", fmt.Errorf("empty attested document signature")
}
klog.V(2).Infof("Azure authenticator obtained attested document for %q", metadata.ResourceID)
// Token format: "x-azure-id <resourceID> <base64-pkcs7-signature>"
return AzureAuthenticationTokenPrefix + metadata.ResourceID + " " + doc.Signature, nil
}
View on GitHub (pinned to 4c8573c808)
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
Defensive patterns
Strategy: validation
Validate before calling
// Validate the IMDS payload yourself before relying on it
var md struct {
ResourceID string `json:"resourceId"`
}
if err := json.Unmarshal(body, &md); err != nil { return err }
if md.ResourceID == "" {
return fmt.Errorf("IMDS metadata lacks resourceId; not a valid ARM VM response")
} Type guard
func hasResourceID(m *azuremetadata.InstanceMetadata) bool {
return m != nil && m.ResourceID != ""
} Prevention
- 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
When it happens
Trigger: QueryComputeInstanceMetadata returns a decodable JSON document whose resourceId field is an empty string (field absent or null also unmarshal to "").
Common situations: 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.
Related errors
- querying instance metadata: %w
- querying attested document: %w
- failed to get region from ec2 metadata: %w
- empty subscription ID
- empty attested document signature
AI-assisted analysis of kubernetes/kops@4c8573c808 (2026-09-05).
Data as JSON: /api/errors/822a9eaf0cd963e9.
Report an issue: GitHub.