【Azure Developer】Python代碼通過AAD認證訪問微軟Azure密鑰保管庫(Azure Key Vault)中機密信息(Secret)


關鍵字說明

什么是 Azure Active Directory?Azure Active Directory(Azure AD, AAD) 是 Microsoft 的基於雲的標識和訪問管理服務,可幫助員工登錄和訪問 Azure 中的資源:

  • 外部資源,例如 Microsoft 365、Azure 門戶(https://portal.azure.cn/)以及成千上萬的其他 SaaS 應用程序。

  • 內部資源,例如公司網絡和 Intranet 上的應用,以及由自己的組織開發的任何雲應用。

什么是Azure Key Vault?Azure Key Vault 是一個用於安全地存儲和訪問機密的雲服務。 機密是你想要嚴格控制對其的訪問的任何內容,例如 API 密鑰、密碼、證書或加密密鑰。 Key Vault 服務支持:保管庫。 保管庫支持存儲軟件密鑰、機密和證書。

  • 機密管理 - Azure Key Vault 可以用來安全地存儲令牌、密碼、證書、API 密鑰和其他機密,並對其訪問進行嚴格控制
  • 密鑰管理 - Azure Key Vault 也可用作密鑰管理解決方案。 可以通過 Azure Key Vault 輕松創建和控制用於加密數據的加密密鑰。
  • 證書管理 - Azure Key Vault 也是一項服務,可用來輕松預配、管理和部署公用和專用傳輸層安全性/安全套接字層 (TLS/SSL) 證書,以用於 Azure 以及內部連接資源。

 

問題描述

在官方的示例文檔中,我們可以發現Python 應用程序以使用 Azure 資源(虛擬機 VM)的托管標識(Identity)從 Azure Key Vault 讀取信息,那如果同樣的Python應用代碼,如果想在非Azure托管的客戶端運行,如何來實現呢?如何來解決如下的錯誤呢?

EnvironmentCredential.get_token failed: EnvironmentCredential authentication unavailable. Environment variables are not fully configured.
ManagedIdentityCredential.get_token failed: ManagedIdentityCredential authentication unavailable, no managed identity endpoint found.
SharedTokenCacheCredential.get_token failed: Azure Active Directory error '(invalid_resource) AADSTS500011: The resource principal named https://vault.azure.cn was not found in 
the tenant named xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx. This can happen if the application has not been installed by the administrator of the tenant or consented to by any user in the tenant. You might have sent your authentication request to the wrong tenant.
Trace ID: 11af8f36-693a-4105-8a6c-9e271a1b9f00
Correlation ID: 43cc4c0d-fd23-4b84-a03b-284ff93484a4
Timestamp: 2021-01-16 07:58:47Z'
DefaultAzureCredential.get_token failed: SharedTokenCacheCredential raised unexpected error "Azure Active Directory error '(invalid_resource) AADSTS500011: The resource principal named https://vault.azure.cn was not found in the tenant named xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx. This can happen if the application has not been installed by the administrator of the tenant or consented to by any user in the tenant. You might have sent your authentication request to the wrong tenant.
Trace ID: 11af8f36-693a-4105-8a6c-9e271a1b9f00
Correlation ID: 43cc4c0d-fd23-4b84-a03b-284ff93484a4
Timestamp: 2021-01-16 07:58:47Z'"
DefaultAzureCredential failed to retrieve a token from the included credentials.
Attempted credentials:
        EnvironmentCredential: EnvironmentCredential authentication unavailable. Environment variables are not fully configured.
        ManagedIdentityCredential: ManagedIdentityCredential authentication unavailable, no managed identity endpoint found.
        SharedTokenCacheCredential: Azure Active Directory error '(invalid_resource) AADSTS500011: The resource principal named https://vault.azure.cn was not found in the tenant named xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx. This can happen if the application has not been installed by the administrator of the tenant or consented to by any user in the tenant. You might have sent your authentication request to the wrong tenant.
Trace ID: 11af8f36-693a-4105-8a6c-9e271a1b9f00
Correlation ID: 43cc4c0d-fd23-4b84-a03b-284ff93484a4
Timestamp: 2021-01-16 07:58:47Z'
Traceback (most recent call last):
  File "case.py", line 26, in <module>
    retrieved_secret = client.get_secret(secretName)
  File "C:\Users\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.8_qbz5n2kfra8p0\LocalCache\local-packages\Python38\site-packages\azure\core\tracing\decorator.py", line 83, in wrapper_use_tracer
    return func(*args, **kwargs)
  File "C:\Users\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.8_qbz5n2kfra8p0\LocalCache\local-packages\Python38\site-packages\azure\keyvault\secrets\_client.py", line 67, in get_secret
    bundle = self._client.get_secret(
  File "C:\Users\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.8_qbz5n2kfra8p0\LocalCache\local-packages\Python38\site-packages\azure\keyvault\secrets\_generated\_operations_mixin.py", line 1475, in get_secret
    return mixin_instance.get_secret(vault_base_url, secret_name, secret_version, **kwargs)
  File "C:\Users\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.8_qbz5n2kfra8p0\LocalCache\local-packages\Python38\site-packages\azure\keyvault\secrets\_generated\v7_1\operations\_key_vault_client_operations.py", line 276, in get_secret
    pipeline_response = self._client._pipeline.run(request, stream=False, **kwargs)
  File "C:\Users\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.8_qbz5n2kfra8p0\LocalCache\local-packages\Python38\site-packages\azure\core\pipeline\_base.py", line 211, in run
    return first_node.send(pipeline_request)  # type: ignore
  File "C:\Users\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.8_qbz5n2kfra8p0\LocalCache\local-packages\Python38\site-packages\azure\core\pipeline\_base.py", line 71, in send
    response = self.next.send(request)
  File "C:\Users\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.8_qbz5n2kfra8p0\LocalCache\local-packages\Python38\site-packages\azure\core\pipeline\_base.py", line 71, in send
    response = self.next.send(request)
  File "C:\Users\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.8_qbz5n2kfra8p0\LocalCache\local-packages\Python38\site-packages\azure\core\pipeline\_base.py", line 71, in send
    response = self.next.send(request)
  [Previous line repeated 2 more times]
  File "C:\Users\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.8_qbz5n2kfra8p0\LocalCache\local-packages\Python38\site-packages\azure\core\pipeline\policies\_redirect.py", line 157, in send
    response = self.next.send(request)
  File "C:\Users\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.8_qbz5n2kfra8p0\LocalCache\local-packages\Python38\site-packages\azure\core\pipeline\policies\_retry.py", line 436, in send
    response = self.next.send(request)
  File "C:\Users\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.8_qbz5n2kfra8p0\LocalCache\local-packages\Python38\site-packages\azure\keyvault\secrets\_shared\challenge_auth_policy.py", line 111, in send
    self._handle_challenge(request, challenge)
  File "C:\Users\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.8_qbz5n2kfra8p0\LocalCache\local-packages\Python38\site-packages\azure\keyvault\secrets\_shared\challenge_auth_policy.py", line 137, in _handle_challenge
    self._token = self._credential.get_token(scope)
  File "C:\Users\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.8_qbz5n2kfra8p0\LocalCache\local-packages\Python38\site-packages\azure\identity\_credentials\default.py", line 144, in get_token
    return super(DefaultAzureCredential, self).get_token(*scopes, **kwargs)
  File "C:\Users\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.8_qbz5n2kfra8p0\LocalCache\local-packages\Python38\site-packages\azure\identity\_credentials\chained.py", line 90, in get_token
    raise ClientAuthenticationError(message=message)
azure.core.exceptions.ClientAuthenticationError: DefaultAzureCredential failed to retrieve a token from the included credentials.
Attempted credentials:
        EnvironmentCredential: EnvironmentCredential authentication unavailable. Environment variables are not fully configured.
        ManagedIdentityCredential: ManagedIdentityCredential authentication unavailable, no managed identity endpoint found.
        SharedTokenCacheCredential: Azure Active Directory error '(invalid_resource) AADSTS500011: The resource principal named https://vault.azure.cn was not found in the tenant named xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx. This can happen if the application has not been installed by the administrator of the tenant or consented to by any user in the tenant. You might have sent your authentication request to the wrong tenant.
Trace ID: 11af8f36-693a-4105-8a6c-9e271a1b9f00
Correlation ID: 43cc4c0d-fd23-4b84-a03b-284ff93484a4
Timestamp: 2021-01-16 07:58:47Z'

 

解決思路

根據錯誤提示,需要在Azure AD中為Python應用程序注冊一個授權應用(AAD Application)。並獲取AAD應用中的客戶端訪問密碼(Secret)客戶端ID(Client ID),租戶ID(Tenant ID),配置Python應用端的環境變量,調用azure.identity庫中的DefaultAzureCredential函數,完成訪問Key Vault資源的授權。整個方案需要以下3個關鍵步驟:

  1. 注冊AAD應用並設置客戶端密碼
  2. 在Key Vault中對AAD應用完成訪問授權(Access Policy)
  3. 配置Python應用端的環境變量

下文為整個方案的操作步驟

 

操作步驟

一:注冊AAD 應用,復制出應用的關鍵信息(Client ID, Tenant ID, Object ID)

二:設置AAD 應用客戶端密碼

  •  在AAD應用頁面,進入“證書和密碼”頁面,點擊“新客戶端密碼”按鈕,添加新的Secret(因密碼值只能在最開始創建時可見,所以必須在離開頁面前復制它

三:在Key Vault中設置訪問授權

  • 登錄Azure門戶,進入Key Vault頁面(https://portal.azure.cn/#blade/HubsExtension/BrowseResourceBlade/resourceType/Microsoft.KeyVault%2Fvaults)
  • 選擇“Access policies”,點擊“Add access policy”,使用第一步中的AAD應用名稱或Application ID作為Principal。點擊“Add”后“Save”。

四:設置環境變量

 使用azure.identity庫中的DefaultAzureCredential函數,默認會去檢測當前環境中是否包含AZURE_CLIENT_ID,AZURE_TENANT_ID,AZURE_CLIENT_SECRET三個變量。

  • AZURE_CLIENT_ID:第一步中的Client ID
  • AZURE_TENANT_ID:第一步中的Tenant ID
  • AZURE_CLIENT_SECRET:第二步中的Secret Value

五:運行Python應用

可以在代碼中輸出上一步中設定的環境變量,以驗證值是否正確。

import os
import cmd
from azure.keyvault.secrets import SecretClient
from azure.identity import DefaultAzureCredential

# print('AZURE_TENANT_ID:' +os.environ["AZURE_TENANT_ID"])
# print('AZURE_CLIENT_ID:' +os.environ["AZURE_CLIENT_ID"])
# print('AZURE_CLIENT_SECRET:' +os.environ["AZURE_CLIENT_SECRET"])

keyVaultName = 'mykeyvalue01'
secretName = 'mysecret'
KVUri = f"https://{keyVaultName}.vault.azure.cn"

print(KVUri)
credential = DefaultAzureCredential()
token = credential.get_token("https://vault.azure.cn/.default")
print(token)
client = SecretClient(vault_url=KVUri, credential=credential)

retrieved_secret = client.get_secret(secretName)

print(f"Your secret is '{retrieved_secret.value}'.")
print(f"Your secret properties not_before(nbf) is '{retrieved_secret.properties.not_before}'.")
print(f"Your secret properties expires_on is '{retrieved_secret.properties.expires_on}'.")

 

六:附加:如何獲取代碼中的Token值

DefaultAzureCredential方法返回credential對象,如果需要知道請求中使用的token值,調用get_token方法,同時需要指定scope,如這里使用的為"https://vault.azure.cn/.default"

credential = DefaultAzureCredential()
token = credential.get_token("https://vault.azure.cn/.default")
print(token)

測試結果如圖:

 

 

 

附錄一:如遺忘以上第三步,沒有在Key Vault中對AAD應用賦予訪問策略(Access Policy),則獲取的錯誤消息為

azure.core.exceptions.HttpResponseError: (Forbidden) The user, group or application 'appid=xxxxxxxx-05ad-4999-8679-xxxxxxxxxxxx;oid=xxxxxxxx-e256-4650-8ef8-xxxxxxxxxxxx;iss=https://sts.chinacloudapi.cn/xxxxxxxx-66d7-47a8-8f9f-xxxxxxxxxxxx/' does not have secrets get permission on key vault 'keyvault01;location=chinanorth'. For help resolving this issue, please see https://go.microsoft.com/fwlink/?linkid=2125287

 

參考資料

什么是 Azure Active Directory? https://docs.microsoft.com/zh-cn/azure/active-directory/fundamentals/active-directory-whatis

關於 Azure Key Vault: https://docs.azure.cn/zh-cn/key-vault/general/overview

Azure Key Vault 基本概念 : https://docs.azure.cn/zh-cn/key-vault/general/basic-concepts

將 Azure Key Vault 與通過 Python 編寫的虛擬機配合使用 :https://docs.azure.cn/zh-cn/key-vault/general/tutorial-python-virtual-machine

DefaultAzureCredential get_token : https://docs.microsoft.com/en-us/python/api/azure-identity/azure.identity.defaultazurecredential?view=azure-python#get-token--scopes----kwargs-

使用Postman獲取Azure AD中注冊應用程序的授權Token,及為Azure REST API設置Authorization : https://www.cnblogs.com/lulight/p/14279338.html

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM