Skip to content

[BUG] azure-resourcemanager-msi: IdentityInner.toJson() drops properties (isolationScope silently lost) #49836

Description

@weidongxu-microsoft

Reported by Dennis Menge. Quoting his message:


Do you have a rough timeline when we are GA'ing azure-resourcemanager-msi 2.54 that contains this fix.

Problem

User Assigned Managed Identities (UAMIs) created by CreateOrUpdateKeyVaultUamiTask and CreateOrUpdateSqlIdentityTask were showing "isolationScope": "None" in Azure Portal, even though the code explicitly requested IsolationScope.REGIONAL.

{
  "properties": {
    "isolationScope": "None",
    "principalId": "...",
    "clientId": "..."
  }
}

The expected value was "isolationScope": "Regional".

Approaches That Did Not Work

Attempt 1 — Fluent API (Identity.DefinitionStages.WithCreate)

The most natural approach: use the MSI Fluent API to define and create the identity.

this.getMsiManager().identities()
    .define(name)
    .withRegion(this.cloud().getRegion())
    .withExistingResourceGroup(resourceGroup)
    .create();

Why it failed: Identity.DefinitionStages.WithCreate has no withIsolationScope() method. The Fluent API never exposed isolationScope as a builder option at any version.

Attempt 2 — Low-level typed client with IdentityInner

Using the inner REST client to pass an IdentityInner with isolationScope set:

final IdentityInner inner = new IdentityInner()
    .withLocation(this.cloud().getRegion())
    .withIsolationScope(IsolationScope.REGIONAL);
final IdentityInner created = this.getMsiManager().serviceClient()
    .getUserAssignedIdentities()
    .createOrUpdate(resourceGroup, name, inner);

This compiles and runs without errors, but Azure still returned "isolationScope": "None".

Why it failed: This is the SDK bug described below. IdentityInner.toJson() does not serialize the properties block at all, so isolationScope is silently dropped from the HTTP request body before it ever reaches Azure.

Root Cause — Azure SDK Bug in IdentityInner.toJson()

In azure-resourcemanager-msi versions ≤ 2.53.7, IdentityInner.toJson() only serializes location and tags, omitting the properties block entirely:

// azure-resourcemanager-msi 2.53.6 — BUG
@Override
public JsonWriter toJson(JsonWriter jsonWriter) throws IOException {
    jsonWriter.writeStartObject();
    jsonWriter.writeStringField("location", location());
    jsonWriter.writeMapField("tags", tags(), (writer, element) -> writer.writeString(element));
    return jsonWriter.writeEndObject();  // ← innerProperties never written
}

The properties object (which carries isolationScope) is stored in a private field innerProperties of type UserAssignedIdentityProperties. That class's own toJson() correctly serializes isolationScope:

// UserAssignedIdentityProperties.toJson() — correct
public JsonWriter toJson(JsonWriter jsonWriter) throws IOException {
    jsonWriter.writeStartObject();
    jsonWriter.writeStringField(
        "isolationScope",
        this.isolationScope == null ? null : this.isolationScope.toString());
    return jsonWriter.writeEndObject();
}

But since IdentityInner.toJson() never calls jsonWriter.writeJsonField("properties", this.innerProperties), the outer serializer never reaches it. The actual HTTP PUT body sent to Azure is:

{ "location": "westeurope", "tags": {} }

Azure receives no properties.isolationScope, and defaults the field to "None".

The bug was introduced when the module was split during a codebase reorganisation (commit f39bb5b, 2025-09-04) and was not caught because the missing field has no visible runtime error — the API call succeeds, just with the wrong value.

Metadata

Metadata

Labels

MgmtThis issue is related to a management-plane library.

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions