迁移应用程序以将无密码连接用于 Azure Database for MySQL

本文介绍如何从传统身份验证方法迁移到与 Azure Database for MySQL 建立更安全的无密码连接。

必须对 Azure Database for MySQL 的应用程序请求进行身份验证。 Azure Database for MySQL 为应用提供多种不同的连接方式。 其中一种方法是使用密码。 但是,应尽可能确定应用程序中无密码连接的优先级。

比较身份验证选项

当应用程序使用 Azure Database for MySQL 进行身份验证时,它提供用于连接到数据库的用户名和密码对。 根据标识的存储位置,有两种类型的身份验证:Microsoft Entra 身份验证和 MySQL 身份验证。

Microsoft Entra 身份验证

Microsoft Entra 身份验证是一种使用 Microsoft Entra ID 中定义的标识连接到 Azure Database for MySQL 的机制。 通过 Microsoft Entra 身份验证,可以在一个中心位置集中管理数据库用户标识和其他 Microsoft 服务,从而简化权限管理。

使用 Microsoft Entra ID 进行身份验证可提供以下优势:

  • 以统一的方式在 Azure 服务中对用户进行身份验证。
  • 在统一的位置管理密码策略和密码轮换。
  • Microsoft Entra ID 支持的多种形式的身份验证,因此无需存储密码。
  • 客户可以使用外部 (Microsoft Entra ID) 组来管理数据库权限。
  • Microsoft Entra 身份验证使用 MySQL 数据库用户对数据库级别的标识进行身份验证。
  • 对连接到 Azure Database for MySQL 的应用程序支持基于令牌的身份验证。

MySQL 身份验证

可以在 MySQL 中创建帐户。 如果你选择使用密码作为帐户的凭据,这些凭据将存储在 user 表中。 由于这些密码存储在 MySQL 中,因此需要自行管理密码的轮换。

尽管可以使用密码连接到 Azure Database for MySQL,但应谨慎使用它们。 必须勤奋地不要在不安全的位置公开密码。 获得密码访问权限的任何人都可以进行身份验证。 例如,如果意外将连接字符串签入源代码管理、通过不安全的电子邮件发送、粘贴到错误的聊天中或由不应具有权限的人员查看,恶意用户可能会访问该应用程序。 请考虑改为将应用程序更新为使用无密码连接。

引入无密码连接

使用无密码连接,无需在应用程序代码、配置文件或环境变量中存储任何凭据即可连接到 Azure 服务。

许多 Azure 服务支持无密码连接,例如通过 Azure 托管标识。 这些技术提供可靠的安全功能,可以使用 Azure 标识客户端库中的 DefaultAzureCredential 实现。 本教程介绍如何更新现有应用程序以使用DefaultAzureCredential,而不是连接字符串等替代方法。

DefaultAzureCredential 支持多种身份验证方法,并自动确定应在运行时使用哪种方法。 应用通过此方法能够在不同环境(本地开发与生产)中使用不同的身份验证方法,而无需实现特定于环境的代码。

可在 Azure 标识库概述中找到搜索凭据的顺序和位置DefaultAzureCredential。 例如,在本地工作时, DefaultAzureCredential 通常会使用开发人员用于登录 Visual Studio 的帐户进行身份验证。 将应用部署到 Azure 后,DefaultAzureCredential 将自动切换为使用托管标识。 此转换不需要进行任何代码更改。

若要确保连接无密码,必须同时考虑本地开发和生产环境。 如果任一位置都需要连接字符串,则应用程序不是无密码的。

在本地开发环境中,可以使用适用于 Visual Studio Code 或 IntelliJ 的 Azure CLI、Azure PowerShell、Visual Studio 或 Azure 插件进行身份验证。 在这种情况下,可以在应用程序中使用该凭据,而不是配置属性。

将应用程序部署到 Azure 托管环境(例如虚拟机)时,可以在该环境中分配托管标识。 然后,无需提供凭据即可连接到 Azure 服务。

注意

托管标识提供用于表示应用或服务的安全标识。 标识由 Azure 平台托管,无需设置或转交任何机密。 可以在概述文档中详细了解托管标识。

迁移现有应用程序以使用无密码连接

以下步骤说明如何迁移现有应用程序以使用无密码连接,而不是基于密码的解决方案。

0) 准备工作环境

首先,使用以下命令设置一些环境变量。

export AZ_RESOURCE_GROUP=<YOUR_RESOURCE_GROUP>
export AZ_DATABASE_SERVER_NAME=<YOUR_DATABASE_SERVER_NAME>
export AZ_DATABASE_NAME=demo
export AZ_MYSQL_AD_NON_ADMIN_USERNAME=<YOUR_AZURE_AD_NON_ADMIN_USER_DISPLAY_NAME>
export AZ_MYSQL_AD_MI_USERNAME=<YOUR_AZURE_AD_MI_DISPLAY_NAME>
export AZ_USER_IDENTITY_NAME=<YOUR_USER_ASSIGNED_MANAGEMED_IDENTITY_NAME>
export CURRENT_USERNAME=$(az ad signed-in-user show --query userPrincipalName --output tsv)
export CURRENT_USER_OBJECTID=$(az ad signed-in-user show --query id --output tsv)

使用以下值替换占位符,在本文中将使用这些值:

  • <YOUR_RESOURCE_GROUP>:资源位于的资源组的名称。
  • <YOUR_DATABASE_SERVER_NAME>:MySQL 服务器的名称,该名称应在整个 Azure 中独一无二。
  • <YOUR_AZURE_AD_NON_ADMIN_USER_DISPLAY_NAME>:Microsoft Entra 非管理员用户的显示名称。 请确保该名称是 Microsoft Entra 租户中的有效用户。
  • <YOUR_AZURE_AD_MI_DISPLAY_NAME>:托管标识的 Microsoft Entra 用户的显示名称。 请确保该名称是 Microsoft Entra 租户中的有效用户。
  • <YOUR_USER_ASSIGNED_MANAGEMED_IDENTITY_NAME>:用户分配的托管标识服务器的名称,在 Azure 中应是唯一的。

1) 配置 Azure Database for MySQL

1.1) 启用基于 entra ID 的身份验证Microsoft

若要将 Microsoft Entra ID 访问与 Azure Database for MySQL 配合使用,应首先设置 Microsoft Entra 管理员用户。 只有 Microsoft Entra 管理员用户才能为基于 Microsoft Entra ID 的身份验证创建/启用用户。

如果使用 Azure CLI,请运行以下命令以确保该用户拥有足够的权限:

az login --scope https://graph.microsoft.com/.default

运行以下命令以创建用户标识进行分配:

az identity create \
    --resource-group $AZ_RESOURCE_GROUP \
    --name $AZ_USER_IDENTITY_NAME

重要

创建用户分配的标识后,请让“全局管理员”或“特权角色管理员”为此标识授予以下权限:User.Read.AllGroupMember.Read.AllApplication.Read.ALL。 有关详细信息,请参阅 Active Directory 身份验证权限部分。

运行以下命令,将标识分配给 MySQL 服务器以创建 Microsoft Entra 管理员:

az mysql flexible-server identity assign \
    --resource-group $AZ_RESOURCE_GROUP \
    --server-name $AZ_DATABASE_SERVER_NAME \
    --identity $AZ_USER_IDENTITY_NAME

然后运行以下命令来设置 Microsoft Entra 管理员:

az mysql flexible-server ad-admin create \
    --resource-group $AZ_RESOURCE_GROUP \
    --server-name $AZ_DATABASE_SERVER_NAME \
    --display-name $CURRENT_USERNAME \
    --object-id $CURRENT_USER_OBJECTID \
    --identity $AZ_USER_IDENTITY_NAME

此命令会将 Microsoft Entra 管理员设置为当前登录用户。

注意

对于每个 MySQL 服务器,只能创建一个 Microsoft Entra 管理员。 选择另一个选项将覆盖为服务器配置的现有 Microsoft Entra 管理员。

2) 配置 Azure Database for MySQL 进行本地开发

2.1) 为本地 IP 配置防火墙规则

Azure Database for MySQL 实例在默认情况下受保护。 它们有不允许任何传入连接的防火墙。

如果你使用的是 Bash,则可以跳过此步骤,因为 flexible-server create 命令已检测到你的本地 IP 地址并在 MySQL 服务器上设置了该地址。

如果要从 Windows 计算机上的 适用于 Linux 的 Windows 子系统 (WSL) 连接到 MySQL 服务器,则需要将 WSL 主机 ID 添加到防火墙。 通过在 WSL 中运行以下命令获取主机的 IP 地址:

cat /etc/resolv.conf

复制术语 nameserver后面的 IP 地址,然后使用以下命令为 WSL IP 地址设置环境变量:

export AZ_WSL_IP_ADDRESS=<the-copied-IP-address>

然后使用以下命令向基于 WSL 的应用开放服务器的防火墙:

az mysql server firewall-rule create \
    --resource-group $AZ_RESOURCE_GROUP \
    --name $AZ_DATABASE_SERVER_NAME-database-allow-local-ip-wsl \
    --server $AZ_DATABASE_SERVER_NAME \
    --start-ip-address $AZ_WSL_IP_ADDRESS \
    --end-ip-address $AZ_WSL_IP_ADDRESS \
    --output tsv

2.2) 创建 MySQL 非管理员用户并授予权限

接下来,创建非管理员Microsoft Entra 用户并向其授予数据库 $AZ_DATABASE_NAME 的所有权限。 可以更改数据库名称 $AZ_DATABASE_NAME 以满足需求。

创建一个名为 create_ad_user.sql 的 SQL 脚本用于创建非管理员用户。 添加以下内容,在本地保存该脚本:

export AZ_MYSQL_AD_NON_ADMIN_USERID=$(az ad signed-in-user show --query id --output tsv)

cat << EOF > create_ad_user.sql
SET aad_auth_validate_oids_in_tenant = OFF;
CREATE AADUSER '$AZ_MYSQL_AD_NON_ADMIN_USERNAME' IDENTIFIED BY '$AZ_MYSQL_AD_NON_ADMIN_USERID';
GRANT ALL PRIVILEGES ON $AZ_DATABASE_NAME.* TO '$AZ_MYSQL_AD_NON_ADMIN_USERNAME'@'%';
FLUSH privileges;
EOF

然后,使用以下命令运行该 SQL 脚本以创建 Microsoft Entra 非管理员用户:

mysql -h $AZ_DATABASE_SERVER_NAME.mysql.database.azure.com --user $CURRENT_USERNAME --enable-cleartext-plugin --password=$(az account get-access-token --resource-type oss-rdbms --output tsv --query accessToken) < create_ad_user.sql

现在使用以下命令删除临时 SQL 脚本文件:

rm create_ad_user.sql

注意

可以阅读在 Azure Database for MySQL 中创建用户来获取有关创建 MySQL 用户的更详细信息。

3) 登录并迁移应用代码以使用无密码连接

对于本地开发,请确保使用为 MySQL 分配了角色的同一Microsoft Entra 帐户进行身份验证。 可通过 Azure CLI、Visual Studio、Azure PowerShell 或其他工具(如 IntelliJ)进行身份验证。

使用以下命令通过 Azure CLI 登录到 Azure:

az login

接下来,使用以下步骤更新代码以使用无密码连接。 虽然从概念上讲相似,但每种语言使用不同的实现详细信息。

  1. 在项目中,添加对包的以下引用 azure-identity-extensions 。 此库包含实现无密码连接所需的所有实体。

    <dependency>
        <groupId>com.azure</groupId>
        <artifactId>azure-identity-extensions</artifactId>
        <version>1.0.0</version>
    </dependency>
    
  2. 在 JDBC URL 中启用 Azure MySQL 身份验证插件。 确定代码中当前创建 java.sql.Connection 用于连接到 Azure Database for MySQL 的位置。 在 application.properties 文件中更新urluser匹配以下值:

    url=jdbc:mysql://$AZ_DATABASE_SERVER_NAME.mysql.database.azure.com:3306/$AZ_DATABASE_NAME?serverTimezone=UTC&sslMode=REQUIRED&defaultAuthenticationPlugin=com.azure.identity.extensions.jdbc.mysql.AzureMysqlAuthenticationPlugin&authenticationPlugins=com.azure.identity.extensions.jdbc.mysql.AzureMysqlAuthenticationPlugin
    user=$AZ_MYSQL_AD_NON_ADMIN_USERNAME
    

    注意

    如果将 MysqlConnectionPoolDataSource 类用作应用程序中的数据源,请务必从 URL 中删除 defaultAuthenticationPlugin=com.azure.identity.extensions.jdbc.mysql.AzureMysqlAuthenticationPlugin

    url=jdbc:mysql://$AZ_DATABASE_SERVER_NAME.mysql.database.azure.com:3306/$AZ_DATABASE_NAME?serverTimezone=UTC&sslMode=REQUIRED&authenticationPlugins=com.azure.identity.extensions.jdbc.mysql.AzureMysqlAuthenticationPlugin
    user=$AZ_MYSQL_AD_NON_ADMIN_USERNAME
    
  3. 将一个 $AZ_DATABASE_SERVER_NAME 变量、一个 $AZ_DATABASE_NAME 变量和一个 $AZ_MYSQL_AD_NON_ADMIN_USERNAME 变量替换为本文开头配置的值。

  4. password从 JDBC URL 中删除该 URL。

在本地运行应用

进行这些代码更改后,在本地运行应用程序。 如果登录到兼容的 IDE 或命令行工具(例如 Azure CLI、Visual Studio 或 IntelliJ),新配置应选取本地凭据。 分配给 Azure 中本地开发用户的角色将允许应用在本地连接到 Azure 服务。

4) 配置 Azure 托管环境

将应用程序配置为使用无密码连接并在本地运行后,相同的代码可以在部署到 Azure 后向 Azure 服务进行身份验证。 例如,部署到已分配托管标识的Azure App 服务实例的应用程序可以连接到Azure 存储。

在本部分中,你将执行两个步骤,使应用程序能够以无密码方式在 Azure 托管环境中运行:

  • 为 Azure 托管环境分配托管标识。
  • 将角色分配给托管标识。

注意

Azure 还提供 服务连接器,可帮助将托管服务与 PostgreSQL 连接。 使用服务连接器配置托管环境时,可以省略将角色分配给托管标识的步骤,因为服务连接器会为你执行此操作。 以下部分介绍如何通过两种方式配置 Azure 托管环境:一种是通过服务连接器,另一种是通过直接配置每个托管环境。

重要

服务连接器的命令需要 Azure CLI 2.41.0 或更高版本。

使用Azure 门户分配托管标识

以下步骤演示如何为各种 Web 托管服务分配系统分配的托管标识。 托管标识可以使用之前设置的应用配置安全地连接到其他 Azure 服务。

  1. 在Azure App 服务实例的主概述页上,从导航窗格中选择“标识”。

  2. “系统分配 ”选项卡上,确保将 “状态 ”字段设置为 “打开”。 系统分配的标识由 Azure 在内部进行管理,并为你处理管理任务。 标识的详细信息和 ID 永远不会在代码中公开。

还可以使用 Azure CLI 在 Azure 托管环境中分配托管标识。

可以使用 az webapp identity assign 命令将托管标识分配给Azure App 服务实例,如以下示例所示:

export AZ_MI_OBJECT_ID=$(az webapp identity assign \
    --resource-group $AZ_RESOURCE_GROUP \
    --name <service-instance-name> \
    --query principalId \
    --output tsv)

为托管标识分配角色

接下来,向分配的托管标识授予访问 MySQL 实例的权限。

这些步骤将为托管标识创建Microsoft Entra 用户,并向其授予数据库 $AZ_DATABASE_NAME 的所有权限。 可以更改数据库名称 $AZ_DATABASE_NAME 以满足需求。

首先,创建名为create_ad_user.sqlSQL 脚本,以创建非管理员用户。 添加以下内容,在本地保存该脚本:

export AZ_MYSQL_AD_MI_USERID=$(az ad sp show --id $AZ_MI_OBJECT_ID --query appId --output tsv)

cat << EOF > create_ad_user.sql
SET aad_auth_validate_oids_in_tenant = OFF;
CREATE AADUSER '$AZ_MYSQL_AD_MI_USERNAME' IDENTIFIED BY '$AZ_MYSQL_AD_MI_USERID';
GRANT ALL PRIVILEGES ON $AZ_DATABASE_NAME.* TO '$AZ_MYSQL_AD_MI_USERNAME'@'%';
FLUSH privileges;
EOF

然后,使用以下命令运行该 SQL 脚本以创建 Microsoft Entra 非管理员用户:

mysql -h $AZ_DATABASE_SERVER_NAME.mysql.database.azure.com --user $CURRENT_USERNAME --enable-cleartext-plugin --password=$(az account get-access-token --resource-type oss-rdbms --output tsv --query accessToken) < create_ad_user.sql

现在使用以下命令删除临时 SQL 脚本文件:

rm create_ad_user.sql

测试应用程序

将应用部署到托管环境之前,需要再对代码进行更改,因为应用程序将使用为托管标识创建的用户连接到 MySQL。

更新代码以使用为托管标识创建的用户:

properties.put("user", "$AZ_MYSQL_AD_MI_USERNAME");

进行这些代码更改后,可以生成并重新部署应用程序。 然后,在浏览器中浏览到托管的应用程序。 应用应能够成功连接到 MySQL 数据库。 请记住,角色分配通过 Azure 环境传播最长可能需要五分钟的时间。 应用程序现在配置为在本地和生产环境中运行,开发人员无需管理应用程序本身的机密。

后续步骤

本教程介绍了如何将应用程序迁移到无密码连接。

可以阅读以下资源,更深入地了解本文中讨论的概念: