Skip to content

Commit 902b5e8

Browse files
authored
Add managed_identity_client_id argument to DefaultAzureCredential (#13218)
1 parent 3891c08 commit 902b5e8

File tree

5 files changed

+47
-20
lines changed

5 files changed

+47
-20
lines changed

sdk/identity/azure-identity/CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@
55
- Application authentication APIs from 1.4.0b7
66
- `ManagedIdentityCredential` supports the latest version of App Service
77
([#11346](https://github.com/Azure/azure-sdk-for-python/issues/11346))
8+
- `DefaultAzureCredential` allows specifying the client ID of a user-assigned
9+
managed identity via keyword argument `managed_identity_client_id`
10+
([#12991](https://github.com/Azure/azure-sdk-for-python/issues/12991))
811

912
## 1.4.0 (2020-08-10)
1013
### Added

sdk/identity/azure-identity/azure/identity/_credentials/default.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,8 @@ class DefaultAzureCredential(ChainedTokenCredential):
6262
:keyword str interactive_browser_tenant_id: Tenant ID to use when authenticating a user through
6363
:class:`~azure.identity.InteractiveBrowserCredential`. Defaults to the value of environment variable
6464
AZURE_TENANT_ID, if any. If unspecified, users will authenticate in their home tenants.
65+
:keyword str managed_identity_client_id: The client ID of a user-assigned managed identity. Defaults to the value
66+
of the environment variable AZURE_CLIENT_ID, if any. If not specified, a system-assigned identity will be used.
6567
:keyword str shared_cache_username: Preferred username for :class:`~azure.identity.SharedTokenCacheCredential`.
6668
Defaults to the value of environment variable AZURE_USERNAME, if any.
6769
:keyword str shared_cache_tenant_id: Preferred tenant for :class:`~azure.identity.SharedTokenCacheCredential`.
@@ -79,6 +81,10 @@ def __init__(self, **kwargs):
7981
"interactive_browser_tenant_id", os.environ.get(EnvironmentVariables.AZURE_TENANT_ID)
8082
)
8183

84+
managed_identity_client_id = kwargs.pop(
85+
"managed_identity_client_id", os.environ.get(EnvironmentVariables.AZURE_CLIENT_ID)
86+
)
87+
8288
shared_cache_username = kwargs.pop("shared_cache_username", os.environ.get(EnvironmentVariables.AZURE_USERNAME))
8389
shared_cache_tenant_id = kwargs.pop(
8490
"shared_cache_tenant_id", os.environ.get(EnvironmentVariables.AZURE_TENANT_ID)
@@ -99,9 +105,7 @@ def __init__(self, **kwargs):
99105
if not exclude_environment_credential:
100106
credentials.append(EnvironmentCredential(authority=authority, **kwargs))
101107
if not exclude_managed_identity_credential:
102-
credentials.append(
103-
ManagedIdentityCredential(client_id=os.environ.get(EnvironmentVariables.AZURE_CLIENT_ID), **kwargs)
104-
)
108+
credentials.append(ManagedIdentityCredential(client_id=managed_identity_client_id, **kwargs))
105109
if not exclude_shared_token_cache_credential and SharedTokenCacheCredential.supported():
106110
try:
107111
# username and/or tenant_id are only required when the cache contains tokens for multiple identities

sdk/identity/azure-identity/azure/identity/aio/_credentials/default.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,8 @@ class DefaultAzureCredential(ChainedTokenCredential):
5050
Defaults to **False**.
5151
:keyword bool exclude_shared_token_cache_credential: Whether to exclude the shared token cache. Defaults to
5252
**False**.
53+
:keyword str managed_identity_client_id: The client ID of a user-assigned managed identity. Defaults to the value
54+
of the environment variable AZURE_CLIENT_ID, if any. If not specified, a system-assigned identity will be used.
5355
:keyword str shared_cache_username: Preferred username for :class:`~azure.identity.SharedTokenCacheCredential`.
5456
Defaults to the value of environment variable AZURE_USERNAME, if any.
5557
:keyword str shared_cache_tenant_id: Preferred tenant for :class:`~azure.identity.SharedTokenCacheCredential`.
@@ -67,6 +69,10 @@ def __init__(self, **kwargs: "Any") -> None:
6769
"shared_cache_tenant_id", os.environ.get(EnvironmentVariables.AZURE_TENANT_ID)
6870
)
6971

72+
managed_identity_client_id = kwargs.pop(
73+
"managed_identity_client_id", os.environ.get(EnvironmentVariables.AZURE_CLIENT_ID)
74+
)
75+
7076
vscode_tenant_id = kwargs.pop(
7177
"visual_studio_code_tenant_id", os.environ.get(EnvironmentVariables.AZURE_TENANT_ID)
7278
)
@@ -82,7 +88,7 @@ def __init__(self, **kwargs: "Any") -> None:
8288
credentials.append(EnvironmentCredential(authority=authority, **kwargs))
8389
if not exclude_managed_identity_credential:
8490
credentials.append(
85-
ManagedIdentityCredential(client_id=os.environ.get(EnvironmentVariables.AZURE_CLIENT_ID), **kwargs)
91+
ManagedIdentityCredential(client_id=managed_identity_client_id, **kwargs)
8692
)
8793
if not exclude_shared_token_cache_credential and SharedTokenCacheCredential.supported():
8894
try:

sdk/identity/azure-identity/tests/test_default.py

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -265,20 +265,27 @@ def test_default_credential_shared_cache_use(mock_credential):
265265

266266

267267
def test_managed_identity_client_id():
268-
"""The credential should initialize ManagedIdentityCredential with the value of AZURE_CLIENT_ID"""
268+
"""the credential should accept a user-assigned managed identity's client ID by kwarg or environment variable"""
269269

270-
expected_client_id = "the-client"
271-
with patch.dict(os.environ, {EnvironmentVariables.AZURE_CLIENT_ID: expected_client_id}, clear=True):
272-
with patch(DefaultAzureCredential.__module__ + ".ManagedIdentityCredential") as mock_credential:
273-
DefaultAzureCredential()
270+
expected_args = {"client_id": "the-client"}
274271

275-
mock_credential.assert_called_once_with(client_id=expected_client_id)
272+
with patch(DefaultAzureCredential.__module__ + ".ManagedIdentityCredential") as mock_credential:
273+
DefaultAzureCredential(managed_identity_client_id=expected_args["client_id"])
274+
mock_credential.assert_called_once_with(**expected_args)
276275

277-
with patch.dict(os.environ, {}, clear=True):
276+
# client id can also be specified in $AZURE_CLIENT_ID
277+
with patch.dict(os.environ, {EnvironmentVariables.AZURE_CLIENT_ID: expected_args["client_id"]}, clear=True):
278278
with patch(DefaultAzureCredential.__module__ + ".ManagedIdentityCredential") as mock_credential:
279279
DefaultAzureCredential()
280+
mock_credential.assert_called_once_with(**expected_args)
280281

281-
mock_credential.assert_called_once_with(client_id=None)
282+
# keyword argument should override environment variable
283+
with patch.dict(
284+
os.environ, {EnvironmentVariables.AZURE_CLIENT_ID: "not-" + expected_args["client_id"]}, clear=True
285+
):
286+
with patch(DefaultAzureCredential.__module__ + ".ManagedIdentityCredential") as mock_credential:
287+
DefaultAzureCredential(managed_identity_client_id=expected_args["client_id"])
288+
mock_credential.assert_called_once_with(**expected_args)
282289

283290

284291
def get_credential_for_shared_cache_test(expected_refresh_token, expected_access_token, cache, **kwargs):

sdk/identity/azure-identity/tests/test_default_async.py

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -253,20 +253,27 @@ async def test_default_credential_shared_cache_use():
253253

254254

255255
def test_managed_identity_client_id():
256-
"""The credential should initialize ManagedIdentityCredential with the value of AZURE_CLIENT_ID"""
256+
"""the credential should accept a user-assigned managed identity's client ID by kwarg or environment variable"""
257257

258-
expected_client_id = "the-client"
259-
with patch.dict(os.environ, {EnvironmentVariables.AZURE_CLIENT_ID: expected_client_id}, clear=True):
260-
with patch(DefaultAzureCredential.__module__ + ".ManagedIdentityCredential") as mock_credential:
261-
DefaultAzureCredential()
258+
expected_args = {"client_id": "the client"}
262259

263-
mock_credential.assert_called_once_with(client_id=expected_client_id)
260+
with patch(DefaultAzureCredential.__module__ + ".ManagedIdentityCredential") as mock_credential:
261+
DefaultAzureCredential(managed_identity_client_id=expected_args["client_id"])
262+
mock_credential.assert_called_once_with(**expected_args)
264263

265-
with patch.dict(os.environ, {}, clear=True):
264+
# client id can also be specified in $AZURE_CLIENT_ID
265+
with patch.dict(os.environ, {EnvironmentVariables.AZURE_CLIENT_ID: expected_args["client_id"]}, clear=True):
266266
with patch(DefaultAzureCredential.__module__ + ".ManagedIdentityCredential") as mock_credential:
267267
DefaultAzureCredential()
268+
mock_credential.assert_called_once_with(**expected_args)
268269

269-
mock_credential.assert_called_once_with(client_id=None)
270+
# keyword argument should override environment variable
271+
with patch.dict(
272+
os.environ, {EnvironmentVariables.AZURE_CLIENT_ID: "not-" + expected_args["client_id"]}, clear=True
273+
):
274+
with patch(DefaultAzureCredential.__module__ + ".ManagedIdentityCredential") as mock_credential:
275+
DefaultAzureCredential(managed_identity_client_id=expected_args["client_id"])
276+
mock_credential.assert_called_once_with(**expected_args)
270277

271278

272279
def get_credential_for_shared_cache_test(expected_refresh_token, expected_access_token, cache, **kwargs):

0 commit comments

Comments
 (0)