Skip to content

Commit 2d61792

Browse files
xiangyan99pvaneckchlowell
authored
Added WorkloadIdentityCredential (Azure#28536)
* Added `WorkloadIdentityCredential` * update * updates * updates * update * update * updates * update * Update sdk/identity/azure-identity/azure/identity/_credentials/workload_identity.py Co-authored-by: Paul Van Eck <paulvaneck@microsoft.com> * Update sdk/identity/azure-identity/CHANGELOG.md Co-authored-by: Paul Van Eck <paulvaneck@microsoft.com> * Update sdk/identity/azure-identity/azure/identity/_credentials/workload_identity.py Co-authored-by: Paul Van Eck <paulvaneck@microsoft.com> * updates * updates * update * Updates * update * Update sdk/identity/azure-identity/azure/identity/_credentials/default.py Co-authored-by: Charles Lowell <10964656+chlowell@users.noreply.github.com> * Update sdk/identity/azure-identity/azure/identity/aio/_credentials/default.py Co-authored-by: Charles Lowell <10964656+chlowell@users.noreply.github.com> --------- Co-authored-by: Paul Van Eck <paulvaneck@microsoft.com> Co-authored-by: Charles Lowell <10964656+chlowell@users.noreply.github.com>
1 parent 3a8db5b commit 2d61792

File tree

16 files changed

+122
-63
lines changed

16 files changed

+122
-63
lines changed

sdk/identity/azure-identity/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
### Features Added
66

77
- Added `AzureDeveloperCredential` for Azure Developer CLI. ([#27916](https://github.com/Azure/azure-sdk-for-python/pull/27916))
8+
- Added `WorkloadIdentityCredential` for Workload Identity Federation on Kubernetes ([#28536](https://github.com/Azure/azure-sdk-for-python/pull/28536))
89
- Added support to use "TryAutoDetect" as the value for `AZURE_REGIONAL_AUTHORITY_NAME` to enable auto detecting the appropriate authority ([#526](https://github.com/AzureAD/microsoft-authentication-library-for-python/issues/526))
910

1011
## 1.13.0b1 (2023-01-10)

sdk/identity/azure-identity/README.md

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -50,13 +50,11 @@ authentication flow. This can also be selected manually by running `az login --u
5050

5151
#### Authenticate via the Azure Developer CLI
5252

53-
`DefaultAzureCredential` and `AzureDeveloperCliCredential` can authenticate as the user
54-
signed in to the [Azure Developer CLI][azd_cli]. To sign in to the Azure Developer CLI, run
55-
`azd login`. On a system with a default web browser, the Azure Developer CLI will launch
56-
the browser to authenticate a user.
53+
Developers coding outside of an IDE can also use the [Azure Developer CLI][azure_developer_cli] to authenticate. Applications using the `DefaultAzureCredential` or the `AzureDeveloperCliCredential` can then use this account to authenticate calls in their application when running locally.
54+
55+
To authenticate with the [Azure Developer CLI][azure_developer_cli], users can run the command `azd login`. For users running on a system with a default web browser, the Azure Developer CLI will launch the browser to authenticate the user.
5756

58-
When no default browser is available, `azd login` will use the device code
59-
authentication flow. This can also be selected manually by running `azd login --use-device-code`.
57+
For systems without a default web browser, the `azd login --use-device-code` command will use the device code authentication flow.
6058

6159
## Key concepts
6260

@@ -82,7 +80,9 @@ this library's credential classes.
8280
![DefaultAzureCredential authentication flow](https://raw.githubusercontent.com/Azure/azure-sdk-for-python/main/sdk/identity/azure-identity/images/mermaidjs/DefaultAzureCredentialAuthFlow.svg)
8381

8482
1. **Environment** - `DefaultAzureCredential` will read account information specified via [environment variables](#environment-variables "environment variables") and use it to authenticate.
83+
1. **Workload Identity** - If the application is deployed to an Azure Kubernetes service with Managed Identity enabled, `DefaultAzureCredential` will authenticate with it.
8584
1. **Managed Identity** - If the application is deployed to an Azure host with Managed Identity enabled, `DefaultAzureCredential` will authenticate with it.
85+
1. **Azure Developer CLI** - If the developer has authenticated via the Azure Developer CLI `azd login` command, the `DefaultAzureCredential` will authenticate with that account.
8686
1. **Azure CLI** - If a user has signed in via the Azure CLI `az login` command, `DefaultAzureCredential` will authenticate as that user.
8787
1. **Azure PowerShell** - If a user has signed in via Azure PowerShell's `Connect-AzAccount` command, `DefaultAzureCredential` will authenticate as that user.
8888
1. **Interactive browser** - If enabled, `DefaultAzureCredential` will interactively authenticate a user via the default browser. This is disabled by default.
@@ -400,6 +400,7 @@ additional questions or comments.
400400
[auth_code_cred_ref]: https://aka.ms/azsdk/python/identity/authorizationcodecredential
401401
[azure_appconfiguration]: https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/appconfiguration/azure-appconfiguration
402402
[azure_cli]: https://learn.microsoft.com/cli/azure
403+
[azure_developer_cli]:https://aka.ms/azure-dev
403404
[azure_core_transport_doc]: https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/core/azure-core/CLIENT_LIBRARY_DEVELOPER.md#transport
404405
[azure_eventhub]: https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/eventhub/azure-eventhub
405406
[azure_keyvault_certificates]: https://github.com/Azure/azure-sdk-for-python/blob/main/sdk//keyvault/azure-keyvault-certificates

sdk/identity/azure-identity/azure/identity/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
SharedTokenCacheCredential,
2626
UsernamePasswordCredential,
2727
VisualStudioCodeCredential,
28+
WorkloadIdentityCredential,
2829
)
2930
from ._persistent_cache import TokenCachePersistenceOptions
3031

@@ -53,6 +54,7 @@
5354
"TokenCachePersistenceOptions",
5455
"UsernamePasswordCredential",
5556
"VisualStudioCodeCredential",
57+
"WorkloadIdentityCredential",
5658
]
5759

5860
from ._version import VERSION

sdk/identity/azure-identity/azure/identity/_constants.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,4 +49,4 @@ class EnvironmentVariables:
4949
AZURE_REGIONAL_AUTHORITY_NAME = "AZURE_REGIONAL_AUTHORITY_NAME"
5050

5151
AZURE_FEDERATED_TOKEN_FILE = "AZURE_FEDERATED_TOKEN_FILE"
52-
TOKEN_EXCHANGE_VARS = (AZURE_AUTHORITY_HOST, AZURE_TENANT_ID, AZURE_FEDERATED_TOKEN_FILE)
52+
WORKLOAD_IDENTITY_VARS = (AZURE_AUTHORITY_HOST, AZURE_TENANT_ID, AZURE_FEDERATED_TOKEN_FILE)

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
from .user_password import UsernamePasswordCredential
2020
from .vscode import VisualStudioCodeCredential
2121
from .client_assertion import ClientAssertionCredential
22+
from .workload_identity import WorkloadIdentityCredential
2223

2324

2425
__all__ = [
@@ -39,5 +40,6 @@
3940
"SharedTokenCacheCredential",
4041
"AzureCliCredential",
4142
"UsernamePasswordCredential",
43+
"WorkloadIdentityCredential",
4244
"VisualStudioCodeCredential",
4345
]

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

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
# ------------------------------------
55
import logging
66
import os
7-
from typing import List, TYPE_CHECKING, Any
7+
from typing import List, TYPE_CHECKING, Any, cast
88

99
from azure.core.credentials import AccessToken
1010
from .._constants import EnvironmentVariables
@@ -18,6 +18,7 @@
1818
from .azure_cli import AzureCliCredential
1919
from .azd_cli import AzureDeveloperCliCredential
2020
from .vscode import VisualStudioCodeCredential
21+
from .workload_identity import WorkloadIdentityCredential
2122

2223
if TYPE_CHECKING:
2324
from azure.core.credentials import TokenCredential
@@ -33,12 +34,15 @@ class DefaultAzureCredential(ChainedTokenCredential):
3334
3435
1. A service principal configured by environment variables. See :class:`~azure.identity.EnvironmentCredential` for
3536
more details.
36-
2. An Azure managed identity. See :class:`~azure.identity.ManagedIdentityCredential` for more details.
37-
3. On Windows only: a user who has signed in with a Microsoft application, such as Visual Studio. If multiple
37+
2. WorkloadIdentityCredential if environment variable configuration is set by the Azure workload
38+
identity webhook.
39+
3. An Azure managed identity. See :class:`~azure.identity.ManagedIdentityCredential` for more details.
40+
4. The identity currently logged in to the Azure Developer CLI.
41+
5. On Windows only: a user who has signed in with a Microsoft application, such as Visual Studio. If multiple
3842
identities are in the cache, then the value of the environment variable ``AZURE_USERNAME`` is used to select
3943
which identity to use. See :class:`~azure.identity.SharedTokenCacheCredential` for more details.
40-
4. The identity currently logged in to the Azure CLI.
41-
5. The identity currently logged in to Azure PowerShell.
44+
6. The identity currently logged in to the Azure CLI.
45+
7. The identity currently logged in to Azure PowerShell.
4246
4347
This default behavior is configurable with keyword arguments.
4448
@@ -64,6 +68,8 @@ class DefaultAzureCredential(ChainedTokenCredential):
6468
AZURE_TENANT_ID, if any. If unspecified, users will authenticate in their home tenants.
6569
:keyword str managed_identity_client_id: The client ID of a user-assigned managed identity. Defaults to the value
6670
of the environment variable AZURE_CLIENT_ID, if any. If not specified, a system-assigned identity will be used.
71+
:keyword str workload_identity_client_id: The client ID of an identity assigned to the pod. Defaults to the value
72+
of the environment variable AZURE_CLIENT_ID, if any. If not specified, the pod's default identity will be used.
6773
:keyword str interactive_browser_client_id: The client ID to be used in interactive browser credential. If not
6874
specified, users will authenticate to an Azure development application.
6975
:keyword str shared_cache_username: Preferred username for :class:`~azure.identity.SharedTokenCacheCredential`.
@@ -76,7 +82,7 @@ class DefaultAzureCredential(ChainedTokenCredential):
7682
Directory work or school accounts.
7783
"""
7884

79-
def __init__(self, **kwargs: Any) -> None:
85+
def __init__(self, **kwargs: Any) -> None: # pylint: disable=too-many-statements
8086
if "tenant_id" in kwargs:
8187
raise TypeError("'tenant_id' is not supported in DefaultAzureCredential.")
8288

@@ -100,6 +106,9 @@ def __init__(self, **kwargs: Any) -> None:
100106
managed_identity_client_id = kwargs.pop(
101107
"managed_identity_client_id", os.environ.get(EnvironmentVariables.AZURE_CLIENT_ID)
102108
)
109+
workload_identity_client_id = kwargs.pop(
110+
"workload_identity_client_id", managed_identity_client_id
111+
)
103112
interactive_browser_client_id = kwargs.pop("interactive_browser_client_id", None)
104113

105114
shared_cache_username = kwargs.pop("shared_cache_username", os.environ.get(EnvironmentVariables.AZURE_USERNAME))
@@ -119,6 +128,13 @@ def __init__(self, **kwargs: Any) -> None:
119128
credentials = [] # type: List[TokenCredential]
120129
if not exclude_environment_credential:
121130
credentials.append(EnvironmentCredential(authority=authority, **kwargs))
131+
if all(os.environ.get(var) for var in EnvironmentVariables.WORKLOAD_IDENTITY_VARS):
132+
client_id = workload_identity_client_id
133+
credentials.append(WorkloadIdentityCredential(
134+
client_id=cast(str, client_id),
135+
tenant_id=os.environ[EnvironmentVariables.AZURE_TENANT_ID],
136+
file=os.environ[EnvironmentVariables.AZURE_FEDERATED_TOKEN_FILE],
137+
**kwargs))
122138
if not exclude_managed_identity_credential:
123139
credentials.append(ManagedIdentityCredential(client_id=managed_identity_client_id, **kwargs))
124140
if not exclude_azd_cli_credential:

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

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -63,18 +63,18 @@ def __init__(self, **kwargs: Any) -> None:
6363
from .cloud_shell import CloudShellCredential
6464

6565
self._credential = CloudShellCredential(**kwargs)
66-
elif all(os.environ.get(var) for var in EnvironmentVariables.TOKEN_EXCHANGE_VARS):
67-
_LOGGER.info("%s will use token exchange", self.__class__.__name__)
68-
from .token_exchange import TokenExchangeCredential
66+
elif all(os.environ.get(var) for var in EnvironmentVariables.WORKLOAD_IDENTITY_VARS):
67+
_LOGGER.info("%s will use workload identity", self.__class__.__name__)
68+
from .workload_identity import WorkloadIdentityCredential
6969

7070
client_id = kwargs.pop("client_id", None) or os.environ.get(EnvironmentVariables.AZURE_CLIENT_ID)
7171
if not client_id:
7272
raise ValueError('Configure the environment with a client ID or pass a value for "client_id" argument')
7373

74-
self._credential = TokenExchangeCredential(
74+
self._credential = WorkloadIdentityCredential(
7575
tenant_id=os.environ[EnvironmentVariables.AZURE_TENANT_ID],
7676
client_id=client_id,
77-
token_file_path=os.environ[EnvironmentVariables.AZURE_FEDERATED_TOKEN_FILE],
77+
file=os.environ[EnvironmentVariables.AZURE_FEDERATED_TOKEN_FILE],
7878
**kwargs
7979
)
8080
else:

sdk/identity/azure-identity/azure/identity/_credentials/token_exchange.py renamed to sdk/identity/azure-identity/azure/identity/_credentials/workload_identity.py

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,35 +11,44 @@
1111
class TokenFileMixin:
1212
def __init__(
1313
self,
14-
token_file_path: str,
14+
file: str,
1515
**_: Any
1616
) -> None:
1717
super(TokenFileMixin, self).__init__()
1818
self._jwt = ""
1919
self._last_read_time = 0
20-
self._token_file_path = token_file_path
20+
self._file = file
2121

2222
def get_service_account_token(self) -> str:
2323
now = int(time.time())
24-
if now - self._last_read_time > 300:
25-
with open(self._token_file_path) as f:
24+
if now - self._last_read_time > 600:
25+
with open(self._file) as f:
2626
self._jwt = f.read()
2727
self._last_read_time = now
2828
return self._jwt
2929

3030

31-
class TokenExchangeCredential(ClientAssertionCredential, TokenFileMixin):
31+
class WorkloadIdentityCredential(ClientAssertionCredential, TokenFileMixin):
32+
"""WorkloadIdentityCredential supports Azure workload identity on Kubernetes.
33+
See the `workload identity overview <https://learn.microsoft.com/azure/aks/workload-identity-overview>`_
34+
for more information.
35+
36+
:param str tenant_id: ID of the application's Azure Active Directory tenant. Also called its "directory" ID.
37+
:param str client_id: The client ID of an Azure AD app registration.
38+
:param str file: The path to a file containing a Kubernetes service account token that authenticates the identity.
39+
"""
40+
3241
def __init__(
3342
self,
3443
tenant_id: str,
3544
client_id: str,
36-
token_file_path: str,
45+
file: str,
3746
**kwargs: Any
3847
) -> None:
39-
super(TokenExchangeCredential, self).__init__(
48+
super(WorkloadIdentityCredential, self).__init__(
4049
tenant_id=tenant_id,
4150
client_id=client_id,
4251
func=self.get_service_account_token,
43-
token_file_path=token_file_path,
52+
file=file,
4453
**kwargs
4554
)

sdk/identity/azure-identity/azure/identity/aio/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
SharedTokenCacheCredential,
2020
VisualStudioCodeCredential,
2121
ClientAssertionCredential,
22+
WorkloadIdentityCredential,
2223
)
2324

2425

@@ -37,4 +38,5 @@
3738
"SharedTokenCacheCredential",
3839
"VisualStudioCodeCredential",
3940
"ClientAssertionCredential",
41+
"WorkloadIdentityCredential",
4042
]

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
from .azd_cli import AzureDeveloperCliCredential
1717
from .vscode import VisualStudioCodeCredential
1818
from .client_assertion import ClientAssertionCredential
19+
from .workload_identity import WorkloadIdentityCredential
1920

2021

2122
__all__ = [
@@ -33,4 +34,5 @@
3334
"SharedTokenCacheCredential",
3435
"VisualStudioCodeCredential",
3536
"ClientAssertionCredential",
37+
"WorkloadIdentityCredential",
3638
]

0 commit comments

Comments
 (0)