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

關鍵字說明

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

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

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

什麼是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託管的客戶端運行,如何來實現呢?如何來解決以下的錯誤呢?python

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個關鍵步驟:api

  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應用

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

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"ide

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 : http://www.javashuo.com/article/p-waqgmoyh-nz.html

相關文章
相關標籤/搜索