必须使用帐户访问密钥或无密码连接对 Azure 服务总线的应用程序请求进行身份验证。 但是,应尽可能确定应用程序中无密码连接的优先级。 本教程介绍如何从传统身份验证方法迁移到更安全、无密码的连接。
与访问密钥相关的安全风险
以下代码示例演示如何使用包含访问密钥的连接字符串连接到 Azure 服务总线。 当你创建服务总线时,Azure 会自动生成这些密钥和连接字符串。 许多开发人员倾向于此解决方案,因为它与他们以前使用的选项相似。 如果应用程序当前使用连接字符串,请考虑使用本文档介绍的步骤迁移到使用无密码连接。
await using ServiceBusClient client = new("<CONNECTION-STRING>");
client, err := azservicebus.NewClientFromConnectionString(
"<CONNECTION-STRING>",
nil)
if err != nil {
// handle error
}
JMS:
ConnectionFactory factory = new ServiceBusJmsConnectionFactory(
"<CONNECTION-STRING>",
new ServiceBusJmsConnectionFactorySettings());
接收方客户端:
ServiceBusReceiverClient receiver = new ServiceBusClientBuilder()
.connectionString("<CONNECTION-STRING>")
.receiver()
.topicName("<TOPIC-NAME>")
.subscriptionName("<SUBSCRIPTION-NAME>")
.buildClient();
发送方客户端:
ServiceBusSenderClient client = new ServiceBusClientBuilder()
.connectionString("<CONNECTION-STRING>")
.sender()
.queueName("<QUEUE-NAME>")
.buildClient();
const client = new ServiceBusClient("<CONNECTION-STRING>");
client = ServiceBusClient(
fully_qualified_namespace = "<CONNECTION-STRING>"
)
应慎用连接字符串。 开发人员必须尽量避免在不安全的位置公开密钥。 能够访问密钥的任何人员都可以进行身份验证。 例如,如果帐户密钥被意外签入源代码管理、通过不安全的电子邮件发送或由不应具有权限的人员查看,则恶意用户访问应用程序存在风险。 请考虑改为将应用程序更新为使用无密码连接。
迁移到无密码连接
许多 Azure 服务通过 Microsoft Entra ID 和基于角色的访问控制 (RBAC) 支持无密码连接。 这些技术提供可靠的安全功能,可使用 Azure 标识客户端库中的 DefaultAzureCredential 实现。
Important
某些语言必须在代码中显式实现 DefaultAzureCredential,而其他语言则通过基础插件或驱动程序在内部使用 DefaultAzureCredential。
DefaultAzureCredential 支持多种身份验证方法,并自动确定应在运行时使用哪种方法。 应用通过此方法能够在不同环境(本地开发与生产)中使用不同的身份验证方法,而无需实现特定于环境的代码。
DefaultAzureCredential 搜索凭据的顺序和位置可在 Azure 标识库概述中找到,并且因语言而异。 例如,在本地使用 .NET 时,DefaultAzureCredential 通常会使用开发人员用于登录 Visual Studio、Azure CLI 或 Azure PowerShell 的帐户进行身份验证。 将应用部署到 Azure 时,DefaultAzureCredential 将自动发现并使用关联托管服务(例如 Azure 应用服务)的托管标识。 此转换不需要进行任何代码更改。
Note
托管标识提供用于表示应用或服务的安全标识。 标识由 Azure 平台托管,无需设置或转交任何机密。 可以在概述文档中详细了解托管标识。
以下代码示例演示如何使用无密码连接连接到服务总线。 下一部分将更详细地介绍如何为特定服务迁移到此设置。
.NET 应用程序可以将 DefaultAzureCredential 的实例传递给服务客户端类的构造函数。
DefaultAzureCredential 将自动发现该环境中可用的凭据。
client = new ServiceBusClient(
"<NAMESPACE-NAME>.servicebus.windows.net",
new DefaultAzureCredential());
将应用迁移到使用无密码身份验证的步骤
以下步骤说明如何将现有应用程序迁移到使用无密码连接,而不是使用基于密钥的解决方案。 首先配置本地开发环境,然后将这些概念应用到 Azure 应用托管环境。 无论是直接使用访问密钥还是通过连接字符串,这些迁移步骤都应适用。
在本地开发时,请确保访问服务总线的用户帐户具有正确的权限。 在此示例中,你将使用“Azure 服务总线数据所有者”角色来发送和接收数据,不过也可以使用更精细的角色。 要为自己分配此角色,需要具有“用户访问管理员”角色或包含 Microsoft.Authorization/roleAssignments/write 操作的其他角色。 可使用 Azure 门户、Azure CLI 或 Azure PowerShell 向用户分配 Azure RBAC 角色。 可以在范围概述页面上详细了解角色分配的可用范围。
在此方案中,你将为自己的用户帐户分配权限(范围限定为特定的服务总线命名空间)以遵循最低特权原则。 这种做法只为用户提供所需的最低权限,并创建更安全的生产环境。
以下示例将“Azure 服务总线数据所有者”角色分配到你的用户帐户,这样你就可以发送和接收数据。
Important
在大多数情况下,角色分配在 Azure 中传播需要一两分钟,最多可能需要 8 分钟,但这种情况极少见。 如果在首次运行代码时收到身份验证错误,请稍等片刻再试。
在 Azure 门户中,使用主搜索栏或左侧导航找到你的服务总线命名空间。
在服务总线概述页上,从左侧菜单中选择“访问控制(IAM)”。
在“访问控制(IAM)”页上,选择“角色分配”选项卡。
从顶部菜单中选择“+ 添加”,然后从出现的下拉菜单中选择“添加角色分配”。
使用搜索框筛选结果来找到所需角色。 对于此示例,请搜索“Azure 服务总线数据所有者”,选择匹配的结果,然后选择“下一步”。
在“将访问权限分配到”下,选择“用户、组或服务主体”,然后选择“+ 选择成员”。
在对话框中,搜索 Microsoft Entra 用户名(通常是 user@domain 电子邮件地址),然后选中对话框底部的“选择”。
选择“查看 + 分配”转到最后一页,然后再次选择“查看 + 分配”来完成该过程。
若要使用 Azure CLI 在资源级别分配角色,首先必须使用 az servicebus namespace show 命令检索资源 ID。 可以使用 --query 参数筛选输出属性。
az servicebus namespace show --resource-group '<your-resource-group-name>' --name '<your-service-bus-namespace>' --query id
复制上述命令的输出 ID。 然后,可以使用 Azure CLI 的 az role 命令分配角色。
az role assignment create --assignee "<user@domain>" \
--role "Azure Service Bus Data Owner" \
--scope "<your-resource-id>"
若要使用 Azure PowerShell 在资源级别分配角色,首先必须使用 Get-AzResource 命令检索资源 ID。
Get-AzResource -ResourceGroupName "<yourResourceGroupname>" -Name "<yourServiceBusName>"
复制上述命令输出中的 ID 值。 然后,可以使用 PowerShell 中的 New-AzRoleAssignment 命令分配角色。
New-AzRoleAssignment -SignInName <user@domain> `
-RoleDefinitionName "Azure Service Bus Data Owner" `
-Scope <yourServiceBusId>
登录并迁移应用代码以使用无密码连接
对于本地开发,请确保使用角色所分配到的 Microsoft Entra 帐户(范围限定为服务总线命名空间)进行身份验证。 可通过 Azure CLI、Visual Studio、Azure PowerShell 或其他工具(如 IntelliJ)进行身份验证。
对于本地开发,请确保使用分配了该角色的同一 Microsoft Entra 帐户进行身份验证。 可以通过常用的开发工具(如 Azure CLI 或 Azure PowerShell)进行身份验证。 可用于进行身份验证的开发工具因语言而异。
使用以下命令通过 Azure CLI 登录到 Azure:
az login
选择 Visual Studio 右上角的“登录”按钮。
使用你之前为其分配角色的 Microsoft Entra 帐户登录。
需要安装 Azure CLI 才能通过 Visual Studio Code 使用 DefaultAzureCredential。
在 Visual Studio Code 的主菜单上,导航到“终端”>“新建终端”。
使用以下命令通过 Azure CLI 登录到 Azure:
az login
通过以下命令使用 PowerShell 登录到 Azure:
Connect-AzAccount
接下来,更新代码以使用无密码连接。
若要在 .NET 应用程序中使用 DefaultAzureCredential,请安装 Azure.Identity 包:
dotnet add package Azure.Identity
在文件的顶部,添加以下代码:
using Azure.Identity;
识别创建连接到 Azure 服务总线的 ServiceBusClient 对象的代码。 更新代码,使之与以下示例一致:
var serviceBusNamespace = $"{namespace}.servicebus.windows.net";
ServiceBusClient client = new(
serviceBusNamespace,
new DefaultAzureCredential());
若要在 Go 应用程序中使用 DefaultAzureCredential,请安装 azidentity 模块:
go get -u github.com/Azure/azure-sdk-for-go/sdk/azidentity
在文件的顶部,添加以下代码:
import (
"github.com/Azure/azure-sdk-for-go/sdk/azidentity"
)
确定代码中创建 Client 实例以连接到 Azure 服务总线的位置。 更新代码,使之与以下示例一致:
credential, err := azidentity.NewDefaultAzureCredential(nil)
if err != nil {
// handle error
}
serviceBusNamespace := fmt.Sprintf(
"%s.servicebus.windows.net",
namespace)
client, err := azservicebus.NewClient(serviceBusNamespace, credential, nil)
if err != nil {
// handle error
}
使用 DefaultAzureCredential 的步骤:
在 JMS 应用程序中,将 azure-servicebus-jms 包的最低 1.0.0 版本添加到你的应用程序:
<dependency>
<groupId>com.microsoft.azure</groupId>
<artifactId>azure-servicebus-jms</artifactId>
<version>1.0.0</version>
</dependency>
在 Java 应用程序中,通过以下方法之一安装 azure-identity 包:
在文件的顶部,添加以下代码:
import com.azure.identity.DefaultAzureCredentialBuilder;
更新连接到 Azure 服务总线的代码:
在 JMS 应用程序中,识别创建连接到 Azure 服务总线的 ServiceBusJmsConnectionFactory 对象的代码。 更新代码,使之与以下示例一致:
DefaultAzureCredential credential = new DefaultAzureCredentialBuilder()
.build();
String serviceBusNamespace =
namespace + ".servicebus.windows.net";
ConnectionFactory factory = new ServiceBusJmsConnectionFactory(
credential,
serviceBusNamespace,
new ServiceBusJmsConnectionFactorySettings());
在 Java 应用程序中,识别创建服务总线发送方或接收方客户端对象以连接到 Azure 服务总线的代码。 更新代码,使之与以下某个示例一致:
接收方客户端:
DefaultAzureCredential credential = new DefaultAzureCredentialBuilder()
.build();
String serviceBusNamespace =
namespace + ".servicebus.windows.net";
ServiceBusReceiverClient receiver = new ServiceBusClientBuilder()
.credential(serviceBusNamespace, credential)
.receiver()
.topicName("<TOPIC-NAME>")
.subscriptionName("<SUBSCRIPTION-NAME>")
.buildClient();
发送方客户端:
DefaultAzureCredential credential = new DefaultAzureCredentialBuilder()
.build();
String serviceBusNamespace =
namespace + ".servicebus.windows.net";
ServiceBusSenderClient client = new ServiceBusClientBuilder()
.credential(serviceBusNamespace, credential)
.sender()
.queueName("<QUEUE-NAME>")
.buildClient();
若要在 Node.js 应用程序中使用 DefaultAzureCredential,请安装 @azure/identity 包:
npm install --save @azure/identity
在文件的顶部,添加以下代码:
const { DefaultAzureCredential } = require("@azure/identity");
识别创建连接到 Azure 服务总线的 ServiceBusClient 对象的代码。 更新代码,使之与以下示例一致:
const credential = new DefaultAzureCredential();
const serviceBusNamespace = `${namespace}.servicebus.windows.net`;
const client = new ServiceBusClient(
serviceBusNamespace,
credential
);
若要在 Python 应用程序中使用 DefaultAzureCredential,请安装 azure-identity 包:
pip install azure-identity
在文件的顶部,添加以下代码:
from azure.identity import DefaultAzureCredential
识别创建连接到 Azure 服务总线的 ServiceBusClient 对象的代码。 更新代码,使之与以下示例一致:
credential = DefaultAzureCredential()
service_bus_namespace = "%s.servicebus.windows.net" % namespace
client = ServiceBusClient(
fully_qualified_namespace = service_bus_namespace,
credential = credential
)
在本地运行应用
进行这些代码更改后,在本地运行应用程序。 新配置应选取本地凭据,例如 Azure CLI、Visual Studio 或 IntelliJ。 你在 Azure 中分配给本地开发用户的角色将允许应用在本地连接到 Azure 服务。
将应用程序配置为使用无密码连接并在本地运行后,相同的代码可以在部署到 Azure 时向 Azure 服务进行身份验证。 例如,部署到启用了托管标识的 Azure 应用服务实例的应用程序可以连接到 Azure 服务总线。
使用 Azure 门户创建托管标识
以下步骤演示如何为各种 Web 托管服务创建系统分配的托管标识。 托管标识可以使用之前设置的应用配置安全地连接到其他 Azure 服务。
某些应用托管环境支持服务连接器,这有助于将 Azure 计算服务连接到其他支持服务。 服务连接器会自动配置网络设置和连接信息。 可以在概述页上详细了解服务连接器以及支持哪些方案。
目前支持以下计算服务:
- Azure App 服务
- Azure Spring Cloud
- Azure 容器应用(预览版)
在本迁移指南中,你将使用应用服务,但步骤与 Azure Spring Apps 和 Azure 容器应用的类似。
Note
Azure Spring Apps 目前仅支持使用连接字符串的服务连接器。
在应用服务的主概述页上,从左侧导航中选择“服务连接器”。
在顶部菜单中选择“+ 创建”,这将打开“创建连接”面板。 输入以下值:
-
服务类型:选择“服务总线”。
-
订阅:选择要使用的订阅。
-
连接名称:为连接输入一个名称,例如“connector_appservice_servicebu”。
-
客户端类型:保持选中默认值,或选择要使用的特定客户端。
选择“下一步: 身份验证”。
确保已选中“系统分配的托管标识(推荐)”,然后选择“下一步: 网络”。
保持选中默认值,然后选择“下一步: 查看 + 创建”。
在 Azure 验证你的设置后,请选择“创建”。
服务连接器将自动为应用服务创建系统分配的托管标识。 连接器还会为托管标识分配所选服务总线的“Azure 服务总线数据所有者”角色。
在 Azure 应用服务实例的主概述页上,从左侧导航中选择“标识”。
在“系统分配”选项卡下,确保将“状态”字段设置为“启用”。 系统分配的标识由 Azure 在内部进行管理,并为你处理管理任务。 标识的详细信息和 ID 永远不会在代码中公开。
在 Azure Spring App 实例的主概述页上,从左侧导航中选择“标识”。
在“系统分配”选项卡下,确保将“状态”字段设置为“启用”。 系统分配的标识由 Azure 在内部进行管理,并为你处理管理任务。 标识的详细信息和 ID 永远不会在代码中公开。
在 Azure 容器应用实例的主概述页上,从左侧导航中选择“标识”。
在“系统分配”选项卡下,确保将“状态”字段设置为“启用”。 系统分配的标识由 Azure 在内部进行管理,并为你处理管理任务。 标识的详细信息和 ID 永远不会在代码中公开。
在虚拟机的主概述页上,从左侧导航中选择“标识”。
在“系统分配”选项卡下,确保将“状态”字段设置为“启用”。 系统分配的标识由 Azure 在内部进行管理,并为你处理管理任务。 标识的详细信息和 ID 永远不会在代码中公开。
另外,你还可以使用 Azure CLI 在 Azure 托管环境中启用托管标识。
可以使用 Azure CLI 通过服务连接器在 Azure 计算托管环境和目标服务之间创建连接。 CLI 会自动处理创建托管标识并分配适当的角色,如门户说明中所述。
如果使用的是 Azure 应用服务,请使用 az webapp connection 命令:
az webapp connection create servicebus \
--resource-group <resource-group-name> \
--name <webapp-name> \
--target-resource-group <target-resource-group-name> \
--namespace <target-service-bus-namespace> \
--system-identity
如果使用的是 Azure Spring Apps,请使用 az spring connection 命令:
az spring connection create servicebus \
--resource-group <resource-group-name> \
--service <service-instance-name> \
--app <app-name> \
--deployment <deployment-name> \
--target-resource-group <target-resource-group> \
--namespace <target-service-bus-namespace> \
--system-identity
如果使用的是 Azure 容器应用,请使用 az containerapp connection 命令:
az containerapp connection create servicebus \
--resource-group <resource-group-name> \
--name <webapp-name> \
--target-resource-group <target-resource-group-name> \
--namespace <target-service-bus-namespace> \
--system-identity
可以使用 az webapp identity assign 命令将托管标识分配给 Azure 应用服务实例。
az webapp identity assign \
--resource-group <resource-group-name> \
--name <webapp-name>
可以使用 az spring app identity assign 命令将托管标识分配给 Azure Spring Apps 实例。
az spring app identity assign \
--resource-group <resource-group-name> \
--name <app-name> \
--service <service-name>
可以使用 az vm identity assign 命令将托管标识分配给虚拟机。
az vm identity assign \
--resource-group <resource-group-name> \
--name <virtual-machine-name>
可以使用 az aks update 命令将托管标识分配给 Azure Kubernetes 服务 (AKS) 实例。
az aks update \
--resource-group <resource-group-name> \
--name <virtual-machine-name> \
--enable-managed-identity
为托管标识分配角色
接下来,需要向创建的托管标识授予访问服务总线的权限。 将角色分配给托管标识,就像对本地开发用户的操作一样。
如果使用服务连接器连接服务,则无需完成此步骤。 已为你完成必要的配置:
导航到服务总线概述页,并在左侧导航栏中选择“访问控制(IAM)”。
选择“添加角色分配”。
在“角色”搜索框中,搜索“Azure 服务总线数据所有者”,这是用于管理 Blob 数据操作的常用角色。 可以分配适合你的用例的任何角色。 从列表中选择“Azure 服务总线数据所有者”,然后选择“下一步”。
在“添加角色分配”屏幕上,针对“将访问权限分配到”选项,请选择“托管标识”。 然后选择“+ 选择成员”。
在浮出控件中,通过输入应用服务的名称搜索你创建的托管标识。 选择系统分配的标识,然后选择“选择”以关闭浮出控件菜单。
多次选择“下一步”,直到可以选择“查看+分配”,以完成角色分配。
若要使用 Azure CLI 在资源级别分配角色,首先必须使用 az servicebus show 命令检索资源 ID。 可以使用 --query 参数筛选输出属性。
az servicebus show \
--resource-group '<your-resource-group-name>' \
--name '<your-service-bus-namespace>' \
--query id
复制上述命令中的输出 ID。 然后,可以使用 Azure CLI 的 az role 命令分配角色。
az role assignment create \
--assignee "<your-username>" \
--role "Azure Service Bus Data Owner" \
--scope "<your-resource-id>"
测试应用程序
进行这些代码更改后,在浏览器中浏览到托管应用程序。 应用应该可以成功连接到服务总线。 请记住,角色分配通过 Azure 环境传播最长可能需要五分钟的时间。 应用程序现在配置为在本地和生产环境中运行,开发人员无需管理应用程序本身的机密。
后续步骤
本教程介绍了如何将应用程序迁移到无密码连接。