Allow Azure Arc managed identity requests to forward user-assigned identity selectors - #944
Conversation
There was a problem hiding this comment.
Pull request overview
This PR updates the Azure Arc managed identity flow in MSAL Python to allow forwarding user-assigned identity selectors (client ID, resource ID, object ID) instead of rejecting user-assigned managed identities on Arc. It threads the managed_identity input into the Arc request path and maps resource_id to Arc/App Service’s expected wire name mi_res_id for both the challenge and authenticated HTTP calls.
Changes:
- Remove the Arc-only rejection of
UserAssignedManagedIdentityand passmanaged_identityinto_obtain_token_on_arc(...). - Add Arc-specific selector parameter mapping (including
resource_id→mi_res_id) on both Arc HTTP requests. - Update tests to validate selectors are forwarded for Arc user-assigned MI (client_id, mi_res_id, object_id) on both Arc calls.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
msal/managed_identity.py |
Allows Arc MI token acquisition to include user-assigned selector parameters (with Arc-specific mapping) on both Arc HTTP calls. |
tests/test_mi.py |
Replaces the “user-assigned not supported on Arc” expectation with happy-path tests asserting selector forwarding on both Arc requests. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 593fce2a-8559-422e-92e2-46fb29c251a4
|
Gladwin Johnson (@gladjohn) - is this one review-able now? |
Live testing against the Azure Connected Machine agent (1.67, user-assigned preview) showed the Arc token endpoint only honors the IMDS 'msi_res_id' spelling for the resource-id selector; 'mi_res_id' is silently ignored and returns the system-assigned identity, so a resource-id UAMI never resolved. Forward 'msi_res_id' on the Arc request (matching the VM/IMDS source). Update the unit test accordingly. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 5ad57850-7d1f-4b9a-bf9f-723d69a9687c
…e Arc MI The publish-pipeline edits (BuildDist Linux->Windows pool, python -m build -> setup.py, dropped twine check, Windows-style artifact paths on Linux pools) are unrelated to the Azure Arc managed identity selector forwarding this PR targets and were flagged in review as non-deterministic and broken on Linux. Restore .Pipelines/pipeline-publish.yml to the dev baseline so those concerns are removed and the PR only carries the Arc change. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 5ad57850-7d1f-4b9a-bf9f-723d69a9687c
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 3 out of 3 changed files in this pull request and generated no new comments.
Suppressed comments (1)
msal/managed_identity.py:650
- The Arc selector mapping uses
msi_res_idforManagedIdentity.RESOURCE_ID, but the PR description/example says Arc should send resource IDs asmi_res_id. Please confirm which spelling Arc actually honors and align either the code/tests or the PR description/release notes so consumers aren’t misled.
_adjust_param(params, managed_identity, types_mapping={
ManagedIdentity.CLIENT_ID: "client_id",
ManagedIdentity.RESOURCE_ID: "msi_res_id", # Azure Arc honors the IMDS msi_res_id spelling; mi_res_id is ignored and returns the system-assigned identity
ManagedIdentity.OBJECT_ID: "object_id",
})
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 3 out of 3 changed files in this pull request and generated no new comments.
Suppressed comments (1)
msal/managed_identity.py:650
- PR description says Arc should map user-assigned
resource_idto themi_res_idquery param, but the implementation (and tests) usemsi_res_id. Please align the PR description and implementation: either update the PR description/snippet tomsi_res_id(if this is correct for Arc HIMDS), or switch this mapping (and the tests) tomi_res_idif that was the intended behavior.
params = {"api-version": "2020-06-01", "resource": resource}
if managed_identity:
_adjust_param(params, managed_identity, types_mapping={
ManagedIdentity.CLIENT_ID: "client_id",
ManagedIdentity.RESOURCE_ID: "msi_res_id", # Azure Arc honors the IMDS msi_res_id spelling; mi_res_id is ignored and returns the system-assigned identity
ManagedIdentity.OBJECT_ID: "object_id",
})
…ed identity Mirrors the response verification already present in MSAL .NET (VerifyUserAssignedIdentityWasHonored) and Go (verifyAzureArcUserAssignedIdentity), addressing review feedback that the Python PR only forwarded the selector without verifying the token response. A legacy Azure Arc agent ignores the client_id/object_id/msi_res_id selector and silently returns the machine's system-assigned identity. After a 200, compare the echoed identity (client_id/object_id/msi_res_id; mi_res_id accepted as a safety net) to the requested selector and raise ManagedIdentityError if missing or mismatched, so MSAL never returns a token for a different identity than the one requested. System-assigned is unaffected. Existing UAMI forwarding tests now echo the identity; added a fail-closed test. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 5ad57850-7d1f-4b9a-bf9f-723d69a9687c
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 3 out of 3 changed files in this pull request and generated no new comments.
Suppressed comments (1)
msal/managed_identity.py:676
- The wire name for ResourceId on Azure Arc is set to
msi_res_id, but the PR description/example refers tomi_res_id. Please reconcile the naming (either update the PR description/example and test naming tomsi_res_id, or switch the Arc mapping tomi_res_idif that is actually the intended/required Arc parameter) to avoid confusing consumers and future maintainers.
params = {"api-version": "2020-06-01", "resource": resource}
if managed_identity:
_adjust_param(params, managed_identity, types_mapping={
ManagedIdentity.CLIENT_ID: "client_id",
ManagedIdentity.RESOURCE_ID: "msi_res_id", # Azure Arc honors the IMDS msi_res_id spelling; mi_res_id is ignored and returns the system-assigned identity
ManagedIdentity.OBJECT_ID: "object_id",
})
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 3 out of 3 changed files in this pull request and generated no new comments.
Suppressed comments (2)
msal/managed_identity.py:676
- The Arc selector mapping passed to _adjust_param duplicates ManagedIdentity._types_mapping (client_id/object_id/msi_res_id). Keeping a second hard-coded mapping here adds drift risk and makes it harder to reason about which mapping is authoritative. Prefer relying on the shared default mapping and keep the Arc-specific note as a comment.
if managed_identity:
_adjust_param(params, managed_identity, types_mapping={
ManagedIdentity.CLIENT_ID: "client_id",
ManagedIdentity.RESOURCE_ID: "msi_res_id", # Azure Arc honors the IMDS msi_res_id spelling; mi_res_id is ignored and returns the system-assigned identity
ManagedIdentity.OBJECT_ID: "object_id",
msal/managed_identity.py:665
- When Azure Arc does not echo back the requested selector, the exception message doesn’t include which selector was requested nor what value was echoed. Including those details would make it much easier to diagnose whether the agent ignored the selector vs. returned a different identity.
if not echoed or str(echoed).lower() != str(requested).lower():
raise ManagedIdentityError(
"Azure Arc did not confirm the requested user-assigned managed identity "
"in the token response. The agent likely does not support user-assigned "
"managed identities and returned the system-assigned identity.")
Azure Arc now previews user-assigned managed identity support. This change aligns MSAL Python with that behavior by removing the Arc-only rejection path and forwarding the selected identity on Arc token requests.
Azure Arc request flow
UserAssignedManagedIdentity.managed_identityinto_obtain_token_on_arc(...).client_idmi_res_idobject_idParameter mapping
_adjust_param(...)helper with an explicit Arc/App Service-style mapping so resource IDs are sent asmi_res_idrather than the defaultresource_id.Tests
client_idresource_id→mi_res_idobject_id