使用用户分配的托管标识创建 Django Web 应用并将其部署到 Azure

在本教程中,将 Django Web 应用部署到Azure App 服务。 Web 应用使用用户分配的托管标识(无密码连接)和 Azure 基于角色的访问控制来访问Azure 存储Azure Database for PostgreSQL 灵活服务器资源。 该代码使用用于 Python 的 Azure 标识客户端库的 DefaultAzureCredential 类。 该DefaultAzureCredential类会自动检测App 服务是否存在托管标识,并使用它访问其他 Azure 资源。

在本教程中,你将创建用户分配的托管标识并将其分配给App 服务,以便它可以访问数据库和存储帐户资源。 有关使用系统分配的托管标识的示例,请参阅 使用系统分配的托管标识创建 Flask Python Web 应用并将其部署到 Azure。 建议使用用户分配的托管标识,因为它们可由多个资源使用,并且其生命周期与与其关联的资源生命周期分离。 有关使用托管标识的最佳做法的详细信息,请参阅 托管标识最佳做法建议

本教程介绍如何使用 Azure CLI 部署 Python Web 应用和创建 Azure 资源。 本教程中的命令编写为在 Bash shell 中运行。 可以在安装 CLI 的任何 Bash 环境中运行教程命令,例如本地环境或 Azure Cloud Shell。 通过一些修改(例如设置和使用环境变量),可以在 Windows 命令行界面等其他环境中运行这些命令。

获取示例应用

使用示例 Django 示例应用程序与本教程一起操作。 将示例应用程序下载或克隆到开发环境。

  1. 克隆示例。

    git clone https://github.com/Azure-Samples/msdocs-django-web-app-managed-identity.git
    
  2. 导航到应用程序文件夹。

    cd msdocs-django-web-app-managed-identity
    

创建 Azure PostgreSQL 灵活服务器

  1. 设置本教程所需的环境变量。

    LOCATION="eastus"
    RAND_ID=$RANDOM
    RESOURCE_GROUP_NAME="msdocs-mi-web-app"
    APP_SERVICE_NAME="msdocs-mi-web-$RAND_ID"
    DB_SERVER_NAME="msdocs-mi-postgres-$RAND_ID"
    ADMIN_USER="demoadmin"
    ADMIN_PW="ChAnG33#ThsPssWD$RAND_ID"
    UA_NAME="UAManagedIdentityPythonTest$RAND_ID"
    

    重要

    必须 ADMIN_PW 包含以下三个类别中的 8 到 128 个字符:英语大写字母、英文小写字母、数字和非字母数字。 创建用户名或密码时不要使用 $ 字符。 稍后,将使用这些值创建环境变量,其中 $ 字符在用于运行 Python 应用的 Linux 容器中具有特殊含义。

  2. 使用“az group create”命令创建资源组。

    az group create --location $LOCATION --name $RESOURCE_GROUP_NAME
    
  3. 使用 az postgres flexible-server create 命令创建 PostgreSQL 灵活服务器。 (此命令和后续命令对 Bash Shell 使用行延续字符('\')。 更改其他 shell 的行延续字符。

    az postgres flexible-server create \
      --resource-group $RESOURCE_GROUP_NAME \
      --name $DB_SERVER_NAME \
      --location $LOCATION \
      --admin-user $ADMIN_USER \
      --admin-password $ADMIN_PW \
      --sku-name Standard_D2ds_v4 \
      --active-directory-auth Enabled \
      --public-access 0.0.0.0
    

    SKU 名称是定价层和计算配置的名称。 有关详细信息,请参阅 Azure Database for PostgreSQL 定价。 若要列出可用的 SKU,请使用 az postgres flexible-server list-skus --location $LOCATION

  4. 使用 az postgres flexible-server ad-admin create 命令将 Azure 帐户添加为服务器的 Microsoft Entra 管理员。

    ACCOUNT_EMAIL=$(az ad signed-in-user show --query userPrincipalName --output tsv)
    ACCOUNT_ID=$(az ad signed-in-user show --query id --output tsv)
    echo $ACCOUNT_EMAIL, $ACCOUNT_ID
    az postgres flexible-server ad-admin create \
      --resource-group $RESOURCE_GROUP_NAME \
      --server-name $DB_SERVER_NAME \
      --display-name $ACCOUNT_EMAIL \
      --object-id $ACCOUNT_ID \
      --type User
    
  5. 使用 az postgres flexible-server firewall-rule create 命令在服务器上配置防火墙规则。 此规则允许本地环境访问连接到服务器。 (如果使用 Azure Cloud Shell,可以跳过此步骤。

    IP_ADDRESS=<your IP>
    az postgres flexible-server firewall-rule create \
       --resource-group $RESOURCE_GROUP_NAME \
       --name $DB_SERVER_NAME \
       --rule-name AllowMyIP \
       --start-ip-address $IP_ADDRESS \
       --end-ip-address $IP_ADDRESS
    

    使用任何显示 IP 地址的工具或网站在命令中替换 <your IP> 。 例如,可以使用 “我的 IP 地址 ”网站。

  6. 使用 az postgres flexible-server execute 命令创建名为restaurant的数据库。

    az postgres flexible-server execute \
      --name $DB_SERVER_NAME \
      --admin-user $ADMIN_USER \
      --admin-password $ADMIN_PW \
      --database-name postgres \
      --querytext 'create database restaurant;'
    

创建Azure App 服务并部署代码

在示例应用的根文件夹中运行这些命令,以创建App 服务并向其部署代码。

  1. 使用 az webapp up 命令创建应用服务。

    az webapp up \
      --resource-group $RESOURCE_GROUP_NAME \
      --location $LOCATION \
      --name $APP_SERVICE_NAME \
      --runtime PYTHON:3.9 \
      --sku B1
    

    SKU 定义App 服务计划的大小(CPU、内存)和成本。 B1(基本)服务计划在 Azure 订阅中会产生少量成本。 有关应用服务计划的完整列表,请查看应用服务定价页。

  2. 将App 服务配置为将示例存储库中的 start.sh 与 az webapp config set 命令配合使用

    az webapp config set \
      --resource-group $RESOURCE_GROUP_NAME \
      --name $APP_SERVICE_NAME \
      --startup-file "start.sh"
    

创建存储帐户和容器

示例应用将审阅者提交的照片存储为Azure 存储中的 blob。

  • 当用户使用审阅提交照片时,示例应用使用托管标识将映像写入容器,并 DefaultAzureCredential 访问存储帐户。

  • 当用户查看餐馆的评论时,该应用将返回 Blob 存储中照片的链接,该照片的每个评论都有一个与之关联的评论。 要使浏览器能够显示照片,它必须能够在存储帐户中访问它。 Blob 数据必须可用于通过匿名(未经身份验证)访问公开读取。

在本部分中,将创建一个存储帐户和容器,该存储帐户和容器允许对容器中的 Blob 进行公共读取访问。 在后面的部分中,将创建用户分配的托管标识,并将其配置为将 Blob 写入存储帐户。

  1. 使用 az storage create 命令创建存储帐户。

    STORAGE_ACCOUNT_NAME="msdocsstorage$RAND_ID"
    az storage account create \
      --name $STORAGE_ACCOUNT_NAME \
      --resource-group $RESOURCE_GROUP_NAME \
      --location $LOCATION \
      --sku Standard_LRS \
      --allow-blob-public-access true
    
  2. 使用 az storage container create 命令在存储帐户中创建名为照片容器。

    az storage container create \
      --account-name $STORAGE_ACCOUNT_NAME \
      --name photos \
      --public-access blob \
      --auth-mode login
    

    注意

    例如,如果命令失败,指出请求可能被存储帐户的网络规则阻止,请输入以下命令以确保为 Azure 用户帐户分配了有权创建容器的 Azure 角色。

    az role assignment create --role "Storage Blob Data Contributor" --assignee $ACCOUNT_EMAIL --scope "/subscriptions/$SUBSCRIPTION_ID/resourceGroups/$RESOURCE_GROUP_NAME/providers/Microsoft.Storage/storageAccounts/$STORAGE_ACCOUNT_NAME"
    

    有关详细信息,请参阅 快速入门:使用 Azure CLI 创建、下载和列出 Blob。 请注意,多个 Azure 角色允许在存储帐户中创建容器,包括“所有者”、“参与者”、“存储 Blob 数据所有者”和“存储 Blob 数据参与者”。

创建用户分配的托管标识

创建用户分配的托管标识并将其分配给App 服务。 托管标识用于访问数据库和存储帐户。

  1. 使用 az identity create 命令创建用户分配的托管标识,并将客户端 ID 输出到变量以供以后使用。

    UA_CLIENT_ID=$(az identity create --name $UA_NAME --resource-group $RESOURCE_GROUP_NAME --query clientId --output tsv)
    echo $UA_CLIENT_ID
    
  2. 使用 az account show 命令获取订阅 ID 并将其输出到可用于构造托管标识的资源 ID 的变量。

    SUBSCRIPTION_ID=$(az account show --query id --output tsv)
    RESOURCE_ID="/subscriptions/$SUBSCRIPTION_ID/resourceGroups/$RESOURCE_GROUP_NAME/providers/Microsoft.ManagedIdentity/userAssignedIdentities/$UA_NAME"
    echo $RESOURCE_ID
    
  3. 使用 az webapp identity assign 命令将托管标识分配到App 服务。

    export MSYS_NO_PATHCONV=1
    az webapp identity assign \
        --resource-group $RESOURCE_GROUP_NAME \
        --name $APP_SERVICE_NAME \
        --identities $RESOURCE_ID
    
  4. 使用 az webapp config appsettings set 命令创建包含托管标识的客户端 ID 和其他配置信息的App 服务应用设置。

    az webapp config appsettings set \
      --resource-group $RESOURCE_GROUP_NAME \
      --name $APP_SERVICE_NAME \
      --settings AZURE_CLIENT_ID=$UA_CLIENT_ID \
        STORAGE_ACCOUNT_NAME=$STORAGE_ACCOUNT_NAME \
        STORAGE_CONTAINER_NAME=photos \
        DBHOST=$DB_SERVER_NAME \
        DBNAME=restaurant \
        DBUSER=$UA_NAME
    

示例应用使用环境变量(应用设置)来定义数据库和存储帐户的连接信息,但这些变量不包括密码。 相反,身份验证是使用 DefaultAzureCredential.

示例应用代码使用 DefaultAzureCredential 类构造函数,而无需将用户分配的托管标识客户端 ID 传递给构造函数。 在此方案中,回退是针对AZURE_CLIENT_ID环境变量检查,该环境变量设置为应用设置。

如果AZURE_CLIENT_ID环境变量不存在,则会在配置托管标识时使用系统分配的托管标识。 有关详细信息,请参阅 DefaultAzureCredential 简介。

为托管标识创建角色

在本部分中,将为托管标识创建角色分配,以启用对存储帐户和数据库的访问。

  1. 使用 az role assignment create 命令为托管标识创建角色分配,以便访问存储帐户

    export MSYS_NO_PATHCONV=1
    az role assignment create \
    --assignee $UA_CLIENT_ID \
    --role "Storage Blob Data Contributor" \
    --scope "/subscriptions/$SUBSCRIPTION_ID/resourcegroups/$RESOURCE_GROUP_NAME"
    

    该命令指定分配给资源组的角色分配的范围。 有关详细信息,请参阅 “了解角色分配”。

  2. 使用 az postgres flexible-server execute 命令连接到 Postgres 数据库,并运行相同的命令将角色分配给托管标识。

    ACCOUNT_EMAIL_TOKEN=$(az account get-access-token --resource-type oss-rdbms --output tsv --query accessToken)
    az postgres flexible-server execute \
      --name $DB_SERVER_NAME \
      --admin-user $ACCOUNT_EMAIL \
      --admin-password $ACCOUNT_EMAIL_TOKEN \
      --database-name postgres \
      --querytext "select * from pgaadauth_create_principal('"$UA_NAME"', false, false);select * from pgaadauth_list_principals(false);"
    

    如果在运行命令时遇到问题,请确保已将用户帐户添加为 PosgreSQL 服务器的 Microsoft Entra 管理员,并且已允许访问防火墙规则中的 IP 地址。 有关详细信息,请参阅“创建 Azure PostgreSQL 灵活服务器”部分

在 Azure 中测试 Python Web 应用

示例 Python 应用使用 azure.identity 包及其 DefaultAzureCredential 类。 当应用在 Azure 中运行时,DefaultAzureCredential自动检测App 服务是否存在托管标识,如果是,则使用它访问其他 Azure 资源(在本例中为存储和 PostgreSQL)。 无需向App 服务提供存储密钥、证书或凭据即可访问这些资源。

  1. 在 URL http://$APP_SERVICE_NAME.azurewebsites.net中浏览到已部署的应用程序。

    应用可能需要一两分钟才能启动。 如果看到不是默认示例应用页面的默认应用页面,请等待一分钟并刷新浏览器。

  2. 通过添加餐厅以及一些带有餐厅照片的评论来测试示例应用的功能。

    餐厅和评论信息存储在 Azure Database for PostgreSQL 中,照片存储在Azure 存储中。 下面是示例屏幕截图:

    示例应用的屏幕截图,其中显示了使用 Azure App 服务、Azure Postgre SQL 数据库 和 Azure 存储 的餐馆评审功能。

清理

在本教程中,所有 Azure 资源都在同一资源组中创建。 使用 az group delete 命令删除资源组会删除资源组中的所有资源,并且是删除用于应用的所有 Azure 资源的最快捷方法。

az group delete  --name $RESOURCE_GROUP_NAME 

可以选择性地添加 --no-wait 参数,以允许命令在操作完成之前返回。

后续步骤