Skip to content

Honor AZURE_CLIENT_ID in DefaultAzureCredential managed identity - #7520

Open
Hari (hasethuraman) wants to merge 1 commit into
Azure:mainfrom
hasethuraman:hari/default-credential-client-id
Open

Hari (hasethuraman) wants to merge 1 commit into
Azure:mainfrom
hasethuraman:hari/default-credential-client-id

Conversation

@hasethuraman

Copy link
Copy Markdown

Summary

  • Read AZURE_CLIENT_ID when DefaultAzureCredential constructs the managed identity credential in its chain.
  • Preserve selector-free behavior when the variable is unset or empty, and leave standalone ManagedIdentityCredential constructors unchanged.
  • Add regression tests and update expected logs, API documentation, README and changelog.

Motivation

On an Azure host with multiple user-assigned managed identities, IMDS can reject a token request without an identity selector. Setting AZURE_CLIENT_ID currently does not select an identity for the C++ default chain's managed identity credential.

This brings parity with the environment-based managed identity client-ID selection supported by DefaultAzureCredential in Python, .NET, Java, JavaScript/TypeScript, and Go:

SDK Existing behavior
Python Defaults managed_identity_client_id from AZURE_CLIENT_ID, then passes it to ManagedIdentityCredential.
.NET DefaultAzureCredentialOptions.ManagedIdentityClientId defaults to AZURE_CLIENT_ID.
Java loadFallbackValuesFromEnvironment() reads AZURE_CLIENT_ID when no managed identity client ID is configured.
JavaScript/TypeScript createDefaultManagedIdentityCredential() falls back to process.env.AZURE_CLIENT_ID.
Go Reads AZURE_CLIENT_ID and passes it to ManagedIdentityCredentialOptions.ID.

This comparison is specifically about default-chain client-ID selection, not identical credential ordering, endpoint support, retry behavior, or standalone managed identity constructors.

The change also applies when AZURE_TOKEN_CREDENTIALS=ManagedIdentityCredential; it does not change credential ordering or IMDS probe/retry configuration.

Validation

  • Built the identity library and its unit-test executable with GCC 9.4 and C++14.
  • Confirmed the new environment-selector regression fails without the fix and passes with it.
  • All 21 default-chain tests passed, including configured/empty client IDs across default, prod, and managed-identity-only chains, plus unchanged standalone behavior.
  • Broader identity suite: 194/198 passed. Two Azure Arc tests failed because the isolated container lacked sudo; two recorded TokenCredentialTest cases failed because the playback proxy was unavailable. These four cases remain incomplete, not passing or skipped.
  • Changed C++ lines pass clang-format 20; git diff --check passes.

Native application A/B check

Built otherwise-identical RunAI Model Streamer core/Azure wheels from unchanged application source, once with unpatched C++ Identity and once with this patch. Only the Azure native backend binary differed between wheel contents, excluding wheel RECORD checksums; Python files and the common native library were byte-identical.

Ran SafetensorsStreamer.stream_files([uri]) against a public-model fixture in Azure Blob Storage on the same existing AKS CPU node:

C++ Identity SDK Node managed identity with AZURE_CLIENT_ID Workload identity
Unpatched Failed to acquire a token Passed
Patched Passed Passed

All successful cases consumed 272 tensors (269,030,016 payload bytes) and matched the known content fingerprint. Runtime native-library hashes matched the built artifacts.

The node case had no workload identity token, account key, SAS, client secret, credential-chain override, or DACS cache. No Python Azure SDK download_blob() call substituted for native streaming.

Compatibility review

This intentionally changes default-chain behavior when AZURE_CLIENT_ID is non-empty: the managed identity credential now selects that identity instead of issuing an unselected request. Applications setting this variable for another credential may therefore observe different fallback behavior. Managed identity sources that reject user-assigned identity selectors also need compatibility review.

Standalone managed identity credential construction remains explicit and unchanged. Opening as a draft for maintainer feedback on this behavior change.

Use the environment client ID for managed identity selection in the default credential chain while preserving standalone ManagedIdentityCredential behavior. Add selector regression tests and document the compatibility change.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 11d8863b-ee0a-4f8e-94c4-e63edc82546b
Signed-off-by: Hariharan Sethuraman <srnhari@gmail.com>
@github-actions github-actions Bot added Azure.Identity Community Contribution Community members are working on the issue customer-reported Issues that are reported by GitHub users external to the Azure organization. labels Oct 30, 2026
@github-actions

Copy link
Copy Markdown

Thank you for your contribution Hari (@hasethuraman)! We will review the pull request and get back to you soon.

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 3 pipeline(s).
7 pipeline(s) were filtered out due to trigger conditions.
There may be pipelines that require an authorized user to comment /azp run to run.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

On Cloud Shell or Azure Arc, a non-empty AZURE_CLIENT_ID causes eager managed-identity construction to throw, preventing DefaultAzureCredential from using an otherwise working EnvironmentCredential.

1 open issue
What changed in this PR

This PR makes the Azure Identity default credential chain use AZURE_CLIENT_ID for managed identity selection, aligning its behavior with other Azure SDKs while leaving standalone constructors unchanged.

Changes:

  • Pass the environment client ID to managed identity, including managed-identity-only chains.
  • Add selector and standalone-behavior regression tests and update expected logs.
  • Document configuration and compatibility implications.
File Description
sdk/​identity/​azure-identity/​test/​ut/​default_azure_credential_test.cpp Tests client-ID selection and unchanged standalone behavior; updates logs.
sdk/​identity/​azure-identity/​src/​default_azure_credential.cpp Passes AZURE_CLIENT_ID to the chain’s managed identity credential.
sdk/​identity/​azure-identity/​README.md Explains environment-based managed identity selection.
sdk/​identity/​azure-identity/​inc/​azure/​identity/​default_azure_credential.hpp Documents the updated default-chain behavior.
sdk/​identity/​azure-identity/​CHANGELOG.md Records the feature and compatibility change.

Review effort: Balanced

Comment on lines +101 to +102
return std::shared_ptr<ManagedIdentityCredential>(new ManagedIdentityCredential(
Environment::GetVariable("AZURE_CLIENT_ID"), !specificCred, options));

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Azure.Identity Community Contribution Community members are working on the issue customer-reported Issues that are reported by GitHub users external to the Azure organization.

Projects

Status: Untriaged

Development

Successfully merging this pull request may close these issues.

2 participants