"Could not retrieve credential from local cache for service principal" 在 Azure Devops MS 代理上的 Python SDK 中使用 Azure CLI 2.30.0 凭据时

"Could not retrieve credential from local cache for service principal" when using Azure CLI 2.30.0 credentials in Python SDK on Azure Devops MS agent

我在 自托管代理上使用 Azure Pipeline 我使用此任务

      - task: AzureCLI@2
        displayName: Azure CLI task with Python SDK
        inputs:
          azureSubscription: 'SUBSCRIPTION-SERVICE-CONNECTION'
          scriptType: bash
          scriptLocation: inlineScript
          inlineScript: |
            python ./magic-script.py

这样我就可以使用凭证来验证 Azure Python SDK:

client = get_client_from_cli_profile(GraphRbacManagementClient)

当我将此进程转移到 MS 托管代理 时,出现此错误:

  File "/opt/hostedtoolcache/Python/3.7.12/x64/lib/python3.7/site-packages/azure/common/client_factory.py", line 85, in get_client_from_cli_profile
    with_tenant=True,
  File "/opt/hostedtoolcache/Python/3.7.12/x64/lib/python3.7/site-packages/azure/common/credentials.py", line 98, in get_azure_cli_credentials
    cred, subscription_id, tenant_id = profile.get_login_credentials(resource=resource)
  File "/opt/hostedtoolcache/Python/3.7.12/x64/lib/python3.7/site-packages/azure/cli/core/_profile.py", line 335, in get_login_credentials
    credential = self._create_credential(account, client_id=client_id)
  File "/opt/hostedtoolcache/Python/3.7.12/x64/lib/python3.7/site-packages/azure/cli/core/_profile.py", line 592, in _create_credential
    return identity.get_service_principal_credential(username_or_sp_id)
  File "/opt/hostedtoolcache/Python/3.7.12/x64/lib/python3.7/site-packages/azure/cli/core/auth/identity.py", line 185, in get_service_principal_credential
    entry = self._msal_secret_store.load_entry(client_id, self.tenant_id)
  File "/opt/hostedtoolcache/Python/3.7.12/x64/lib/python3.7/site-packages/azure/cli/core/auth/identity.py", line 270, in load_entry
    .format(sp_id))
knack.util.CLIError: Could not retrieve credential from local cache for service principal ***. Run `az login` for this service principal.

基于此migration guide I also tried AzureCliCredential

credential = AzureCliCredential()
client = GraphRbacManagementClient(credential, os.environ["subscriptionId"])   

我的脚本已登录 - 但是在使用 GraphRbacManagementClient 时,我在我的开发箱和代理上本地收到此错误:

    root_group = [g for g in graph_client.groups.list(
  File "C:\Python38\lib\site-packages\msrest\paging.py", line 143, in __next__
    self.advance_page()
  File "C:\Python38\lib\site-packages\msrest\paging.py", line 129, in advance_page
    self._response = self._get_next(self.next_link)
  File "C:\Python38\lib\site-packages\azure\graphrbac\operations\groups_operations.py", line 336, in internal_paging
    response = self._client.send(request, stream=False, **operation_config)
  File "C:\Python38\lib\site-packages\msrest\service_client.py", line 336, in send
    pipeline_response = self.config.pipeline.run(request, **kwargs)
  File "C:\Python38\lib\site-packages\msrest\pipeline\__init__.py", line 197, in run
    return first_node.send(pipeline_request, **kwargs)  # type: ignore
  File "C:\Python38\lib\site-packages\msrest\pipeline\__init__.py", line 150, in send
    response = self.next.send(request, **kwargs)
  File "C:\Python38\lib\site-packages\msrest\pipeline\requests.py", line 65, in send
    self._creds.signed_session(session)
AttributeError: 'AzureCliCredential' object has no attribute 'signed_session'

对于 StorageManagementClient 这行得通。似乎取决于所使用的 SDK 客户端。

这个issue是由Azure CLI版本2.30.0引起的,该版本似乎已推出MS 托管代理 最近。

因此,我将(MS 和自我)托管代理上的所有 Python 脚本 运行 改编为此模型:

def get_graph_client(subscription_id):
    if "tenantId" in os.environ:
        print('using environment variables')
        config_dict = {
            "clientId": os.environ["servicePrincipalId"],
            "clientSecret": os.environ["servicePrincipalKey"],
            "subscriptionId": subscription_id,
            "tenantId": os.environ["tenantId"],
            "activeDirectoryEndpointUrl": "https://login.microsoftonline.com",
            "resourceManagerEndpointUrl": "https://management.azure.com/",
            "activeDirectoryGraphResourceId": "https://graph.windows.net/",
            "managementEndpointUrl": "https://management.core.windows.net/"
        }
        client = get_client_from_json_dict(
            GraphRbacManagementClient, config_dict)
    else:
        print('using CLI credentials')
        credential = AzureCliCredential()
        client = GraphRbacManagementClient(credential, subscription_id)        
    return client

The error AttributeError: 'AzureCliCredential' object has no attribute 'signed_session' I showed in my question was due to corrupt dependencies. Once virtual environment was cleaned up and the correct dependencies where installed, it worked for all Python Azure SDK clients.

这允许我在两种模式下操作,使用 Azure CLI 凭据,也可以通过在相应的管道任务中设置 addSpnToEnvironment: true 使用显式凭据:

      - task: AzureCLI@2
        displayName: Azure CLI task with Python SDK
        inputs:
          azureSubscription: 'SUBSCRIPTION-SERVICE-CONNECTION'
          scriptType: bash
          scriptLocation: inlineScript
          addSpnToEnvironment: true
          inlineScript: |
            python ./magic-script.py

这似乎是由于 Azure-CLI 在 2.29.0 和 2.30 之间的更新所致。在我们的管道中,az login 任务直接在代理(MS 托管)中 运行,因此正在使用该版本。然后,我们与 API 的交互是在一个 conda 环境中进行的,该环境具有固定的旧版本 azure-cli。通过在与后续调用相同的环境中执行 az login(使 Azure CLI 版本一致),解决了它。

本github期有详细介绍:https://github.com/Azure/azure-cli/issues/20153#issuecomment-958684723