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

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

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

比较身份验证选项

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

Microsoft Entra 身份验证

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

使用 Microsoft Entra ID 进行身份验证具有以下优势:

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

PostgreSQL 身份验证

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

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

引入无密码连接

使用无密码连接,无需在应用程序代码、配置文件或环境变量中存储任何凭据即可连接到 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_POSTGRESQL_AD_NON_ADMIN_USERNAME=<YOUR_AZURE_AD_NON_ADMIN_USER_DISPLAY_NAME>
export AZ_LOCAL_IP_ADDRESS=<YOUR_LOCAL_IP_ADDRESS>
export CURRENT_USERNAME=$(az ad signed-in-user show --query userPrincipalName --output tsv)

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

  • <YOUR_RESOURCE_GROUP>:资源位于的资源组的名称。
  • <YOUR_DATABASE_SERVER_NAME>:PostgreSQL 服务器的名称。 它在 Azure 中应是唯一的。
  • <YOUR_AZURE_AD_NON_ADMIN_USER_DISPLAY_NAME>:Microsoft Entra 非管理员用户的显示名称。 请确保该名称是 Microsoft Entra 租户中的有效用户。
  • <YOUR_LOCAL_IP_ADDRESS>:你将在其中运行 Spring Boot 应用程序的本地计算机的 IP 地址。 一种查看 IP 地址的便捷方法是打开 whatismyip.akamai.com

1) 配置 Azure Database for PostgreSQL

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

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

若要在创建服务器后设置 Microsoft Entra 管理员,请按照 Azure Database for PostgreSQL 灵活服务器中的“管理 Microsoft Entra 角色”中的步骤操作。

注意

PostgreSQL 灵活服务器可以创建多个 Microsoft Entra 管理员。

2) 为本地开发配置 Azure Database for PostgreSQL

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

Azure Database for PostgreSQL 实例在默认情况下受保护。 它们有不允许任何传入连接的防火墙。 为了能够使用数据库,需要添加一项防火墙规则,允许本地 IP 地址访问数据库服务器。

由于我们已在本文开头配置了本地 IP 地址,因此你可通过运行以下命令来打开服务器的防火墙:

az postgres flexible-server firewall-rule create \
    --resource-group $AZ_RESOURCE_GROUP \
    --name $AZ_DATABASE_SERVER_NAME \
    --rule-name $AZ_DATABASE_SERVER_NAME-database-allow-local-ip \
    --start-ip-address $AZ_LOCAL_IP_ADDRESS \
    --end-ip-address $AZ_LOCAL_IP_ADDRESS \
    --output tsv

如果要从 Windows 计算机上的 适用于 Linux 的 Windows 子系统 (WSL) 连接到 PostgreSQL 服务器,则需要将 WSL 主机 ID 添加到防火墙。

通过在 WSL 中运行以下命令获取主机的 IP 地址:

cat /etc/resolv.conf

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

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

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

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

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

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

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

cat << EOF > create_ad_user_local.sql
select * from pgaadauth_create_principal('$AZ_POSTGRESQL_AD_NON_ADMIN_USERNAME', false, false);
EOF

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

psql "host=$AZ_DATABASE_SERVER_NAME.postgres.database.azure.com user=$CURRENT_USERNAME dbname=postgres port=5432 password=$(az account get-access-token --resource-type oss-rdbms --output tsv --query accessToken) sslmode=require" < create_ad_user_local.sql

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

rm create_ad_user_local.sql

注意

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

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

对于本地开发,请确保使用在 PostgreSQL 上分配了角色的同一 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 PostgreSQL 身份验证插件。 确定代码中当前创建 java.sql.Connection 用于连接到 Azure Database for PostgreSQL 的位置。 在 application.properties 文件中更新urluser匹配以下值:

    url=jdbc:postgresql://$AZ_DATABASE_SERVER_NAME.postgres.database.azure.com:5432/$AZ_DATABASE_NAME?sslmode=require&authenticationPluginClassName=com.azure.identity.extensions.jdbc.postgresql.AzurePostgresqlAuthenticationPlugin
    user=$AZ_POSTGRESQL_AD_NON_ADMIN_USERNAME
    
  3. 将这 $AZ_POSTGRESQL_AD_NON_ADMIN_USERNAME$AZ_DATABASE_SERVER_NAME 个变量替换为本文开头配置的值。

在本地运行应用

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

4) 配置 Azure 托管环境

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

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

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

注意

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

重要

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

使用Azure 门户分配托管标识

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

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

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

    Screenshot of Azure portal Identity page of App Service resource with System assigned tab showing and Status field highlighted.

还可以使用 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)

为托管标识分配角色

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

如果使用 Service 连接or 连接了服务,则上一步的命令已分配了角色,因此可以跳过此步骤。

测试应用程序

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

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

注意

如果使用了 Service 连接or 命令,请跳过此步骤。

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

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

后续步骤

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

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