如何在 Azure Function 中使用 Azure Managed Identity 通过触发器访问 Service Bus?

Posted

技术标签:

【中文标题】如何在 Azure Function 中使用 Azure Managed Identity 通过触发器访问 Service Bus?【英文标题】:How to use Azure Managed Identity in Azure Function to access Service Bus with a trigger? 【发布时间】:2019-01-26 17:10:36 【问题描述】:

我在 Azure 中创建了一个 ServiceBus 命名空间,以及一个主题和一个订阅。我还有一个简单的 Azure 版本 1 函数,它在 ServiceBus 中触发接收到的主题,如下所示:

[FunctionName("MyServiceBusTriggerFunction")]
public static void Run([ServiceBusTrigger("myTopic", "mySubscription", Connection = "MyConnection")]string mySbMsg, TraceWriter log)

    log.Info($"C# ServiceBus topic trigger function processed message: mySbMsg");

当我使用主题的共享访问策略在函数应用程序设置中定义连接字符串时,该函数很好地触发了 ServiceBus 中的主题,如下所示:

Endpoint=sb://MyNamespace.servicebus.windows.net/;SharedAccessKeyName=mypolicy;SharedAccessKey=UZ...E0=

现在,我想使用托管服务标识 (MSI) 而不是共享访问密钥来访问 ServiceBus。根据这个 (https://docs.microsoft.com/en-us/azure/active-directory/managed-service-identity/services-support-msi) 应该是可能的,除非我误解了什么。不过,我还没有设法让它工作。

我尝试过的是

在 Azure 门户中为我的函数设置“开启”托管服务标识 为 Azure 门户的 ServiceBus 访问控制部分中的函数授予所有者角色 为 MyFunction 设置连接字符串,如下所示:Endpoint=sb://MyNamespace.servicebus.windows.net/

此设置中未触发该功能,所以我错过了什么或我做错了什么? 我将不胜感激任何可以帮助我进一步发展的建议。谢谢。

【问题讨论】:

我怀疑它是如何工作的。我认为它仅用于允许代码连接到资源。我不认为您可以使用 MSI 进行功能级别的轮询 因此,如果我想使用 MSI 从 Azure 函数访问 ServiceBus,我需要创建例如一个计时器触发的函数并从其中轮询 ServiceQueue。 我不确定,所以不要相信我的话,但我真的怀疑 MSI 可以替换这种情况下的连接字符串 如前所述,一个技巧是使用 Key Vault 来保存连接字符串,本机 MSI 尚不支持触发器,并且有一个 Azure Feedback 项目来注册兴趣 【参考方案1】:

Microsoft.Azure.WebJobs.Extensions.ServiceBus 5.x 版更新

现在在here 中提供了该软件包最新版本的官方文档。


  "Values": 
    "<connection_name>__fullyQualifiedNamespace": "<service_bus_namespace>.servicebus.windows.net"
  

上一个答案

现在这实际上似乎是可能的,至少对我来说效果很好。你需要使用这个连接字符串:

Endpoint=sb://service-bus-namespace-name.servicebus.windows.net/;Authentication=ManagedIdentity

我实际上并没有在 Microsoft 网站上找到任何关于此的文档,但在博客 here 中。

Microsoft 确实有关于您可以使用的角色以及如何将它们限制在here 范围内的文档。示例:

az role assignment create \
    --role $service_bus_role \
    --assignee $assignee_id \
    --scope /subscriptions/$subscription_id/resourceGroups/$resource_group/providers/Microsoft.ServiceBus/namespaces/$service_bus_namespace/topics/$service_bus_topic/subscriptions/$service_bus_subscription

【讨论】:

【参考方案2】:

同意从 azure 函数我们不能直接访问像 ASB 这样的资源。但是,在这种情况下,仍然不需要直接在连接字符串中输入密码“SharedAccessKeyName”。 Azure 功能可以与 Azure KeyVault 一起使用。因此,可以将带有敏感信息的连接字符串作为机密存储在 KeyVault 中,然后通过 KeyVault 授予来自天蓝色函数的系统分配的身份访问权限,然后将门户中的设置值指定为 @Microsoft.KeyVault(SecretUri=theSecretUri) 以下博客中提到了如何实现上述目标的详细信息。 https://medium.com/statuscode/getting-key-vault-secrets-in-azure-functions-37620fd20a0b

这仍将避免直接在 Azure 函数中指定连接字符串,并通过 Vault 提供单点访问以在安全漏洞的情况下被禁用

【讨论】:

是的,keyvault 参考是一个非常好的功能,我期待它能够普遍使用。不幸的是,它目前仍处于预览阶段(2019 年 8 月),所以我有点犹豫是否将其投入生产。 (docs.microsoft.com/en-us/azure/app-service/…) 现在最新的包有内置方式,请看下面我的回答【参考方案3】:

我错过了什么或者我做错了什么?

您可能会混淆 MSI 和共享访问策略。它们使用不同的提供商来访问 Azure 服务总线。您可以只使用连接字符串或只使用 MSI 进行身份验证。

当您使用Managed Service Identity(MSI) 进行身份验证时,您需要使用以下代码为托管服务身份创建令牌提供者。

TokenProvider.CreateManagedServiceIdentityTokenProvider(ServiceAudience.ServiceBusAudience).

这个TokenProvider 的实现使用了Microsoft.Azure.Services.AppAuthentication 库中的AzureServiceTokenProviderAzureServiceTokenProvider 将根据环境采用一系列不同的方法来获取访问令牌。然后初始化客户端来操作服务总线。 更多详情可以参考这个article。

当你使用 servicebus 连接字符串访问时,使用共享访问令牌 (SAS) 令牌提供者,所以你可以直接操作。

【讨论】:

具有 ServiceBusTrigger 的 Azure 函数需要连接字符串作为参数。当它被触发运行时,它已经需要被授权。那时为 MSI 创建 TokenProvider 为时已晚,所以看起来我不能使用它。我认为 MSI 应该在幕后处理访问令牌,但似乎并非如此。对吗? 其实就是这样!您无法使用 MSI 来验证服务总线触发功能。 现在最新的包有内置方式,请看下面我的回答

以上是关于如何在 Azure Function 中使用 Azure Managed Identity 通过触发器访问 Service Bus?的主要内容,如果未能解决你的问题,请参考以下文章

Azure 函数中的 Az.Functions 模块引发错误

使用 Azure AZ Powershell Cmdlet 列出 Azure 安全中心策略状态

用于获取 Azure Monitor 日志的 AZ 命令

在 Docker 中运行 Azure DevOps 作业时出现“找不到具有给定版本的模块 Az.Accounts”错误

如何使用 AZ Powershell 获取 VMSize 的成本/月?

az login 从 github 操作任务失败