於本機開發期間使用服務主體向 Azure 服務驗證 Python 應用程式
建立雲端應用程式時,開發人員必須在本機工作站上偵錯及測試應用程式。 當應用程式在本機開發期間於開發人員的工作站上執行時,仍必須向應用程式使用的任何 Azure 服務進行驗證。 本文說明如何設定在本機開發期間要使用的專用應用程式服務主體物件。
本機開發專用的應用程式服務主體可讓您遵循應用程式開發期間最低權限的準則。 由於權限的範圍會限定為開發期間應用程式所需的內容,因此應用程式之程式碼無法意外存取要供不同應用程式使用的 Azure 資源。 這也可防止應用程式在移至生產環境時發生錯誤,因為應用程式在開發環境中擁有較多權限。
在 Azure 中註冊應用程式時,會為應用程式設定應用程式服務主體。 為本機開發註冊應用程式時,建議您:
- 為每個在應用程式上作業的開發人員建立個別的應用程式註冊。 這麼做會建立不同的應用程式服務主體,供開發人員於本機開發期間使用,且能避免開發人員針對單一應用程式服務主體共用認證。
- 為每個應用程式建立個別的應用程式註冊。 這麼做會限制應用程式的權限,使之僅具備所需的權限。
在本機開發期間,會使用應用程式服務主體的身分識別來設定環境變數。 適用於 Python 的 Azure SDK 會讀取這些環境變數,並使用此資訊向所需的 Azure 資源驗證應用程式。
1:在 Azure 中註冊應用程式
系統會用於 Azure 註冊的應用程式建立應用程式服務主體物件。 這可透過 Azure 入口網站或 Azure CLI 來完成。
Azure CLI 命令可以在 Azure Cloud Shell 或已安裝 Azure CLI 的工作站上執行。
首先,使用 az ad sp create-for-rbac 命令為應用程式建立新的服務主體。 此命令也會同時為應用程式建立應用程式註冊。
az ad sp create-for-rbac --name <service-principal-name>
此命令的輸出會如下所示。 請記下這些值,或讓此視窗保持開啟,因為您在後續步驟中需要這些值,而且無法再次檢視密碼 (客戶端密碼) 值。 不過,您可以稍後新增密碼,而不需視需要使服務主體或現有密碼失效。
{
"appId": "00001111-aaaa-2222-bbbb-3333cccc4444",
"displayName": "<service-principal-name>",
"password": "Ee5Ff~6Gg7.-Hh8Ii9Jj0Kk1Ll2Mm3_Nn4Oo5Pp6",
"tenant": "aaaabbbb-0000-cccc-1111-dddd2222eeee"
}
2 - 建立Microsoft專案安全組以進行本機開發
由於通常有多個開發人員在應用程式上工作,因此建議建立Microsoft Entra 安全組來封裝應用程式在本機開發中所需的角色(許可權),而不是將角色指派給個別服務主體物件。 這提供下列優點:
- 由於角色是在群組層級指派,因此指派給每位開發人員的角色都能保證相同。
- 如果應用程式需要新的角色,則只需要將它新增至應用程式的 Microsoft Entra 群組。
- 如有新開發人員加入小組,則系統會為其建立新的應用程式服務主體並新增至群組,確定開發人員具備處理應用程式的適當權限。
az ad group create 命令是用來在 entra ID Microsoft中建立安全組。 --display-name
和 --main-nickname
是必要參數。 提供給群組的名稱應根據應用程式而定。 在群組名稱中納入 'local-dev' 之類的字詞也很實用,這能指出群組的目的。
az ad group create \
--display-name MyDisplay \
--mail-nickname MyDisplay \
--description "<group-description>"
在輸出的命令中複製 id
屬性的值。 這是群組的物件識別碼。 您在後續步驟中需要用到它。 您也可以使用 az ad group show 命令來擷取此屬性。
若要將成員新增至群組,您需要應用程式服務主體的物件識別碼,這與應用程式識別碼不同。 請用 az ad sp list 列出可用的服務主體。 --filter
參數命令會接受 OData 樣式篩選條件,且可如下所示用於篩選清單。 --query
參數僅適用於相關的資料行。
az ad sp list \
--filter "startswith(displayName, 'msdocs')" \
--query "[].{objectId:id, displayName:displayName}" \
--output table
之後可用 az ad group member add 命令來將成員新增至群組。
az ad group member add \
--group <group-name> \
--member-id <object-id>
注意
根據預設,Microsoft Entra 安全組的建立僅限於目錄中的特定特殊許可權角色。 如果無法建立群組,請連絡目錄的系統管理員。 如果無法將成員新增至現有的群組,請連絡群組擁有者或目錄系統管理員。 若要深入了解,請參閱管理 Microsoft Entra 群組和群組成員資格。
3:為應用程式指派角色
接著,您必須決定應用程式針對哪些資源需要哪些角色 (權限),並將這些角色指派給應用程式。 在此範例中,角色會指派給步驟 2 中建立的 Microsoft Entra 群組。 角色可以在資源、資源群組或訂用帳戶範圍指派。 此範例示範如何在資源群組範圍中指派角色,因為大部分的應用程式都會將其所有 Azure 資源群組組成單一資源群組。
使用者、群組或應用程式服務主體會使用 az role assignment create 命令,在 Azure 中指派角色。 您可以使用其物件識別碼來指定群組。 您可以使用其 appId 來指定應用程式服務主體。
az role assignment create --assignee <appId or objectId> \
--scope /subscriptions/<subscriptionId>/resourceGroups/<resourceGroupName> \
--role "<roleName>"
若要取得可指派的角色名稱,請使用 az role definition list 命令。
az role definition list \
--query "sort_by([].{roleName:roleName, description:description}, &roleName)" \
--output table
例如,若要允許應用程式服務主體具有 appId 的00001111-aaaa-2222-bbbb-3333cccc4444
讀取、寫入和刪除存取權,以 Azure 儲存體 存取 msdocs-python-sdk-auth-example 資源群組中 aaaa0a0a-bb1b-cc2c-dd3d-eeeeee4e4e4e
msdocs-python-sdk-auth-example 資源群組中的所有記憶體帳戶中,使用下列命令將應用程式服務主體指派給記憶體 Blob 數據參與者角色。
az role assignment create --assignee 00001111-aaaa-2222-bbbb-3333cccc4444 \
--scope /subscriptions/aaaa0a0a-bb1b-cc2c-dd3d-eeeeee4e4e4e/resourceGroups/msdocs-python-sdk-auth-example \
--role "Storage Blob Data Contributor"
如需在資源或訂閱等級使用 Azure CLI 指派權限的更多資訊,請參閱使用 Azure CLI 指派 Azure 角色一文。
4 - 設定本機開發環境變數
DefaultAzureCredential
物件會於執行階段在一組環境變數中尋找服務主體的資訊。 由於大多數開發人員都處理多個應用程式,因此建議您使用 python-dotenv 之類的套件,從.env
應用程式目錄中儲存的檔案在開發期間存取環境。 這會限定用來向 Azure 驗證應用程式的環境變數,讓它們只能供此應用程式使用。
檔案 .env
永遠不會簽入原始檔控制,因為它包含 Azure 的應用程式秘密密鑰。 適用於 Python 的標準 .gitignore 檔案會自動從簽入中排除 .env
檔案。
若要使用 python-dotenv 套件,請先在應用程式中安裝套件。
pip install python-dotenv
然後,在應用程式根目錄中建立 .env
檔案。 使用從應用程式註冊程式取得的值來設定環境變數值,如下所示:
AZURE_CLIENT_ID
→ 應用程式識別碼的值。AZURE_TENANT_ID
→ 租用戶識別碼的值。AZURE_CLIENT_SECRET
→ 為應用程式產生的密碼/認證。
AZURE_CLIENT_ID=00001111-aaaa-2222-bbbb-3333cccc4444
AZURE_TENANT_ID=aaaabbbb-0000-cccc-1111-dddd2222eeee
AZURE_CLIENT_SECRET=Ee5Ff~6Gg7.-Hh8Ii9Jj0Kk1Ll2Mm3_Nn4Oo5Pp6
最後,在應用程式的啟動程式代碼中,使用連結 python-dotenv
庫從啟動時從 .env
檔案讀取環境變數。
from dotenv import load_dotenv
if ( os.environ['ENVIRONMENT'] == 'development'):
print("Loading environment variables from .env file")
load_dotenv(".env")
5:在應用程式中實作 DefaultAzureCredential
若要向 Azure 驗證 Azure SDK 用戶端物件,您的應用程式應該使用 DefaultAzureCredential
套件中的 azure.identity
類別。 在此案例中, DefaultAzureCredential
將會偵測環境變數 AZURE_CLIENT_ID
、 AZURE_TENANT_ID
和 AZURE_CLIENT_SECRET
已設定並讀取這些變數,以取得要連線到 Azure 的應用程式服務主體資訊。
首先,將 azure.identity 套件新增至您的應用程式。
pip install azure-identity
接下來,針對在應用程式中建立 Azure SDK 用戶端物件的任何 Python 程式代碼,您會想要:
- 從模組匯入
DefaultAzureCredential
azure.identity
類別。 - 建立
DefaultAzureCredential
物件。 - 將
DefaultAzureCredential
對象傳遞至 Azure SDK 用戶端物件建構函式。
下列程式碼區段示範其中一種範例。
from azure.identity import DefaultAzureCredential
from azure.storage.blob import BlobServiceClient
# Acquire a credential object
token_credential = DefaultAzureCredential()
blob_service_client = BlobServiceClient(
account_url="https://<my_account_name>.blob.core.windows.net",
credential=token_credential)