本文是关于 Azure Functions 如何连接远程服务的主要参考资料。 它根据连接类型和认证方法提供了具体指导。
Important
尽可能使用带有 Microsoft Entra ID 的托管身份。 这种认证方法消除了秘密,提供了最高的安全性。
连接类别
Azure Functions 连接主要分为以下几类:
- 所需主机:功能主机运行所需的连接,如存储和监控。
- 绑定:主机为你的触发器和绑定管理的连接。
- 客户端SDK:你在自己的函数代码中创建和管理的连接。
Functions主机要求你的应用拥有以下特定命名连接,这些连接支持函数执行和日志记录:
AzureWebJobsStorage: 函数使用该默认存储账户来启用核心行为,如协调定时触发器的单例执行和函数访问密钥的默认存储。 主机要求此连接连接到受支持的存储帐户。 没有这个连接设置,你的功能应用无法启动。 有关详细信息,请参阅 Azure Functions 的存储注意事项。APPLICATIONINSIGHTS_CONNECTION_STRING你还应该配置主机写入 Application Insights 实例的日志。WEBSITE_AZUREFILESCONNECTIONSTRING:仅由运行在 消费计划 或 弹性高级计划中的应用使用。 定义包含维护你应用部署包的Azure 文件存储共享的存储账户。
身份验证方法
Important
如果可能,使用托管身份来管理你的连接。 这种方法完全消除了秘密。 当目标服务不支持 Microsoft Entra ID 认证时,使用 Azure 密钥保管库 集中管理密钥。 只有在应用设置里直接使用共享机密作为最后手段。
功能支持连接远程服务时的以下认证方法:
| 身份验证方法 | 安全性 | 何时使用 |
|---|---|---|
| 管理标识 | 最高 | Target服务支持Microsoft Entra ID。 没有要管理的机密。 |
| Azure 密钥保管库 | 高 | 服务不支持托管身份,或者你需要轮换的集中密钥管理。 |
| 共享秘密 | 低 | 旧版默认值。 尽快迁移到托管身份或 密钥保管库。 |
在 文章顶部 选择您偏好的认证方式,查看详细配置指南。
定义连接
在运行时,函数应用会从以下位置以环境变量的形式访问连接信息:
| 环境 | 设置的存储位置 |
|---|---|
| Azure | 应用设置 (静止加密) |
| 本地开发 | local.settings.json (可选加密) |
在这两个环境中,设置都以环境变量的形式暴露给你的代码。 你需要的具体设置取决于 连接类型 和你选择的 认证方式 。
当你使用 Microsoft Entra 认证连接 Azure 服务时,具体应用设置取决于连接服务以及你是使用系统分配的身份还是用户指定的身份来认证连接。
你用于连接的身份必须拥有执行预期操作的权限。 对于大多数 Azure 服务,这一要求意味着你需要在 Azure RBAC 中分配一个角色,使用内置或自定义的角色来提供这些权限。 欲了解更多信息,请参见 “授予身份权限”。
使用基于身份的连接时请牢记以下几点:
在由 Functions 托管的应用中,基于标识的连接使用 托管标识。 系统分配的身份是针对你的应用的,默认使用。 但是,用户分配标识也需要
*__credential和*__clientID属性,不过它们更灵活,因此更受推荐。当你的应用在其他上下文中运行时,例如在本地开发环境中,则会改用你的开发者身份。 更多信息请参见 本地开发 相关条目。
基于身份的连接仅支持于 Functions 运行时的 4.x 及以后版本。 如果你在 Functions 运行时的 1.x 版本上运行一个遗留的 C# 应用,必须先 迁移到 4.x 版本。
你可以将函数应用配置为在连接到默认存储帐户 (AzureWebJobsStorage) 和其他主机所需的连接时,使用身份而不是连接字符串。
AzureWebJobsStorage 的托管身份支持因托管计划而异:
| 托管计划 | MI用于主机存储 | Azure 文件存储 要求 | Recommendation |
|---|---|---|---|
| 专用(应用服务) | 完全支持 | 无(无动态缩放) | 完整支持 MI,无需变通方案 |
| 消费 | Blob、队列、表 | 密钥保管库 或移除 Azure 文件存储 | 将WEBSITE_AZUREFILESCONNECTIONSTRING存储在 密钥保管库 中 |
| 弹性高级版 | Blob、队列、表 | 密钥保管库 或移除 Azure 文件存储 | 将WEBSITE_AZUREFILESCONNECTIONSTRING存储在 密钥保管库 中 |
在为主机要求连接使用托管身份之前,请考虑以下限制:
对于消费型和高级版计划,可以为 Azure 文件存储 实施以下变通方案之一:
- 仅将
WEBSITE_AZUREFILESCONNECTIONSTRING连接字符串存储在 密钥保管库 中,这是次安全的选项。 - 创建一个无需Azure 文件存储运行的消费型或高级套餐应用。 不运行 Azure 文件存储 会有性能影响。 有关详细信息,请参阅创建没有 Azure 文件存储的应用。
- 仅将
这些触发器依赖
AzureWebJobsStorage才能正常运行:- Azure Blob 存储
- Azure 事件中心
- Durable Functions(默认)
- Timer
如果你的应用使用了这些扩展中的任意一个,确保其版本也支持托管身份。
AzureWebJobsStorage在 Linux 消耗计划中维护服务器端(远程)构建中的部署工件。 在这种情况下,你必须从 外部部署包部署并运行你的应用。你的函数应用中的其他组件也可能会重用
AzureWebJobsStorage连接,这些组件可能包括存储绑定扩展或使用 Azure SDK 创建的存储客户端。 使用托管身份时,为这些非主机组件创建新的应用设置,即使它们支持托管身份。
这些特定的应用设置定义了与 AzureWebJobsStorage 和 APPLICATIONINSIGHTS_CONNECTION_STRING 的基于身份的连接:
| 设置 | Description |
|---|---|
AzureWebJobsStorage__blobServiceUri |
默认存储帐户中 Blob 存储的 URI。 对于主权云或自定义存储DNS(如: https://mystorageaccount.blob.contoso.com)是必需的。
HTTPS 必需。 |
AzureWebJobsStorage__queueServiceUri |
默认存储帐户中队列存储的 URI。 对于主权云或自定义存储DNS(如: https://mystorageaccount.queue.contoso.com)是必需的。
HTTPS 必需。 |
AzureWebJobsStorage__tableServiceUri |
默认存储帐户中表存储的 URI。 对于主权云或自定义存储DNS(如: https://mystorageaccount.table.contoso.com)是必需的。
HTTPS 必需。 |
AzureWebJobsStorage__credential |
将其设置为 managedidentity 以使用托管标识身份验证。 托管环境中必须提供托管标识。 |
AzureWebJobsStorage__clientId 或AzureWebJobsStorage__managedIdentityResourceId |
返回用于获取访问令牌用于管理身份认证的特定用户分配身份。 当两者都未被设置时,应用的系统分配身份被使用。 |
APPLICATIONINSIGHTS_AUTHENTICATION_STRING |
通过 Microsoft Entra 认证实现与应用洞察的连接。 设置为 Authorization=AAD (系统分配)或 ClientId=<YOUR_CLIENT_ID>;Authorization=AAD (用户分配)。 |
由于双重下划线值(__)在运行时被解释为冒号(:),这一系列设置被解释为对象的 AzureWebJobsStorage 属性。 例如,考虑以下 AzureWebJobsStorage 连接设置:
AzureWebJobsStorage__blobServiceUri=https://<STORAGE_ACCOUNT_NAME>.blob.core.chinacloudapi.cnAzureWebJobsStorage__queueServiceUri=https://<STORAGE_ACCOUNT_NAME>.queue.core.chinacloudapi.cnAzureWebJobsStorage__tableServiceUri=https://<STORAGE_ACCOUNT_NAME>.table.core.chinacloudapi.cnAzureWebJobsStorage__credential=managedidentityAzureWebJobsStorage__clientId=<MY_USER_ASSIGNED_IDENTITY_ID>
运行时,主机将这些设置解读为复杂的 AzureWebJobsStorage 设置。
"AzureWebJobsStorage":
{
"blobServiceUri": "https://<STORAGE_ACCOUNT_NAME>.blob.core.chinacloudapi.cn",
"queueServiceUri": "https://<STORAGE_ACCOUNT_NAME>.queue.core.chinacloudapi.cn",
"tableServiceUri": "https://<STORAGE_ACCOUNT_NAME>.table.core.chinacloudapi.cn",
"credential": "managedidentity",
"clientId": "<MY_USER_ASSIGNED_IDENTITY_ID>"
}
你还必须在默认存储账户中为该身份授予权限,这样主机才能以足够的权限连接完成所需任务。 想了解如何操作,请参见 “授予身份权限”。
授予身份权限
当你使用带有 Microsoft Entra ID 认证的托管身份时,必须为应用连接远程服务时所使用的身份专门分配权限。 授予应用最低权限的最简单方法是分配内置角色。
在授予应用身份RBAC权限时,请记住以下建议:
- 尽可能遵守 最小权限原则 ,只授予身份最低要求的权限。 例如,如果应用只需要从数据源读取,使用一个只允许读取且不写入数据的角色。
- 不要用像 所有者这样宽泛的内置角色,哪怕只是为了让应用正常工作。
- 创建或修改角色分配后,变更最多可能需要 10 分钟才能生效。 在此期间,即使角色分配正确,你的职能仍可能收到授权错误(403)。 如果在创建角色分配后立即遇到错误,请等待几分钟再试一次。
- 当多个连接需要对同一服务的权限时,使用该服务所有连接权限最小子集的角色。
- 某些绑定需要在你的存储帐户中拥有比
AzureWebJobsStorage连接所需权限更广泛的权限。 - 要通过管理身份访问 密钥保管库 中的密钥,请将您的应用分配为 密钥保管库 秘密用户角色。 你也可以使用 密钥保管库 访问策略,为托管身份分配获取秘密权限。 欲了解更多信息,请参阅 授予应用中的标识对密钥保管库的访问权限。
- 本文仅涉及提供最低权限的 内置角色 。 根据你的应用需求,你可能需要自己创建 自定义角色。
你需要的权限取决于连接类型:
AzureWebJobsStorage: 存储块数据所有者 角色提供主机所需AzureWebJobsStorage连接的最低存储账户权限。 该角色在遵循 最小权限原则的前提下,赋予功能主机所需的存储访问级别。对于某些类型的问题,Functions可以触发诊断事件,帮助你排查故障,即使应用无法启动。 你还必须添加 存储表数据参与者 角色,该角色提供对表存储的访问权限,这些诊断事件会持久保存在其中。 没有这些额外权限,你可能会在日志中看到无法写入这些事件的警告。
其他几种绑定可能需要你使用权限范围稍宽的角色。 在绑定选项卡的表格中,主机所需存储列列出了这些角色要求。
APPLICATIONINSIGHTS_AUTHENTICATION_STRING:监视指标发布者角色授予主机连接到 Application Insights 用于记录日志所需的最低权限。
注意
仅在目前不支持 Microsoft Entra ID 且由 Azure 管理身份的连接时使用 密钥保管库。
由于部分服务尚未支持 Microsoft Entra 认证,在某些情况下你的应用可能仍需密钥。 在这种情况下,Azure 密钥保管库 可以帮助简化基于秘密认证的管理生命周期。 你的应用可以使用 密钥保管库 更安全地存储和访问共享机密,包括默认存储帐户连接字符串。 虽然连接仍使用共享密钥,但 密钥保管库 为密钥提供了更高级别的安全保障,包括密钥维护和轮换。 即使服务本身尚未支持基于托管身份的连接,您的应用仍可以通过托管身份连接到 密钥保管库。
使用 密钥保管库 时,请使用密钥保管库 引用而不是实际机密来创建连接的应用设置。 欲了解更多信息,请参见 密钥库中的源应用设置。
在维护密钥保管库连接时请牢记以下几点:
若要访问保管库中的密钥,您必须为应用中的某个标识授予对密钥保管库的访问权限。
你可以用 密钥保管库 存储基于托管身份的连接设置。 当你的应用使用 密钥保管库 时,引用必须使用
:或/作为键分隔符,例如Storage1:blobServiceUri。 当你使用常规的应用设置分隔符__时,引用名称无法正确解析。
你可以配置AzureWebJobsStorage该设置,使其返回包含连接字符串的密钥保管库 引用,而不是返回连接字符串本身。 若要了解如何操作,请参阅 将 密钥保管库 引用用作应用设置。
Azure 文件存储 目前不支持托管身份连接。 由于这一限制,请使用 密钥保管库 保护 WEBSITE_AZUREFILESCONNECTIONSTRING 设置,因为消费计划和高级计划的动态缩放都需要此设置。
Caution
避免直接接触共享的秘密。 尽可能使用更安全的连接认证方式。
通过使用带有 Microsoft Entra ID 认证的托管身份,降低秘密丢失或泄露的潜在风险。 当远程服务不支持托管身份时,至少使用Azure 密钥保管库,它更安全地维护共享秘密。
如果由于某种原因你无法使用更安全的身份验证方法,平台会对你的应用程序设置中静态存储的数据进行加密。 尽快将应用从共享密钥迁移到更安全的认证方式。
在 AzureWebJobsStorage 设置中设置默认存储账户的连接字符串。 这个设置是你创建函数应用时的默认连接行为。
管理SDK客户端连接
当你在函数代码中创建自己的客户端SDK连接时,务必在调用间重复使用客户端实例,而不是创建新的实例。 这一适用于所有托管方案的最佳实践可降低延迟,避免套接字资源耗尽,并提高资源利用效率。
重用客户端实例
在Azure Functions应用中使用服务专用客户端时,请遵循以下指南:
- 不要 每次调用函数都创建新客户端。
- 一定要 创建一个单一的共享客户端,每个函数调用都可以重复使用。
- 如果不同函数使用同一服务,考虑在辅助类中创建一个单一共享客户端。
推荐的做法取决于你的语言:
使用依赖注入来注册单例或有作用域的客户端。
请参阅 客户端代码示例 以了解每种语言的完整模式。
消费计划中的连接限制
注意
本节中所述的连接数硬性限制仅适用于旧版消费计划。
在旧版的消费计划中,函数应用运行在 沙盒环境中 ,每个实例的出站连接数限制为600个活跃连接(总共1200个)。 当达到这个限制时,函数主机会向日志写入以下消息: Host thresholds exceeded: Connections。 有关详细信息,请参阅 Functions 服务限制。
此限制适用于每个实例。 缩放控制器添加函数应用实例以处理更多请求时,每个实例都有单独的连接限制。 这意味着没有全局连接限制,你可以在所有活跃实例中拥有超过600个活跃连接。
排查连接问题时,确保你的函数应用启用了应用洞察。 借助 Application Insights,你可以查看函数应用的指标,如执行。 有关详细信息,请参阅在 Application Insights 中查看遥测。
客户端代码示例
本部分演示了用于通过函数代码创建和使用客户端的最佳做法。
HTTP 请求
通过依赖注入注册共享 HttpClient ,使所有函数调用重复使用同一个实例。 在这种情况下,你不必丢弃客户端,因为运行时管理其生命周期。
using Microsoft.Azure.Functions.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection;
[assembly: FunctionsStartup(typeof(MyNamespace.Startup))]
namespace MyNamespace;
public class Startup : FunctionsStartup
{
public override void Configure(IFunctionsHostBuilder builder)
{
builder.Services.AddHttpClient();
}
}
然后在你的函数类中注入 IHttpClientFactory 或 HttpClient :
using Microsoft.Azure.Functions.Worker;
using Microsoft.Extensions.Logging;
namespace MyNamespace;
public class MyFunction(HttpClient httpClient, ILogger<MyFunction> logger)
{
[Function("MyFunction")]
public async Task Run([TimerTrigger("0 */5 * * * *")] TimerInfo timer)
{
var response = await httpClient.GetAsync("https://example.com");
logger.LogInformation("Response status: {Status}", response.StatusCode);
}
}
Azure Cosmos DB客户端
在你的初创公司注册一个单例 Cosmos客户端 ,让所有功能共享一个连接。 Azure Cosmos DB 文档建议你在整个应用生命周期内使用单例客户端。
using Microsoft.Azure.Cosmos;
using Microsoft.Azure.Functions.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection;
[assembly: FunctionsStartup(typeof(MyNamespace.Startup))]
namespace MyNamespace;
public class Startup : FunctionsStartup
{
public override void Configure(IFunctionsHostBuilder builder)
{
builder.Services.AddSingleton(_ =>
{
var connectionString = Environment.GetEnvironmentVariable("CosmosDBConnection");
return new CosmosClient(connectionString);
});
}
}
然后在你的函数类中注入 CosmosClient :
using Microsoft.Azure.Cosmos;
using Microsoft.Azure.Functions.Worker;
using Microsoft.Extensions.Logging;
namespace MyNamespace;
public class MyCosmosFunction(CosmosClient cosmosClient, ILogger<MyCosmosFunction> logger)
{
private readonly Container _container = cosmosClient.GetContainer("mydb", "mycontainer");
[Function("MyCosmosFunction")]
public async Task Run([TimerTrigger("0 */5 * * * *")] TimerInfo timer)
{
var item = new { id = "myId", partitionKey = "myPartitionKey", data = "example" };
await _container.UpsertItemAsync(item, new PartitionKey("myPartitionKey"));
logger.LogInformation("Item upserted");
}
}
SqlClient 连接实例
函数代码可以使用 .NET Framework 数据提供程序(SqlClient)来连接到 SQL 关系数据库。 该提供者也是依赖ADO.NET的数据框架的底层提供者,如Entity Framework。 与 HttpClient 和 DocumentClient 连接不同,ADO.NET默认实现连接池。 但是,由于连接仍可能耗尽,因此应优化数据库连接。 有关详细信息,请参阅 SQL Server 连接池(ADO.NET)。
提示
某些数据框架(例如实体框架)通常从配置文件的 ConnectionStrings 节获取连接字符串。 在这种情况下,必须将 SQL 数据库连接字符串显式添加到函数应用设置的连接字符串集合以及本地项目中的 local.settings.json 文件中。 如果你在函数代码中创建 SqlConnection 实例,把 连接字符串 值和其他连接一起存储在应用设置里。
Azure 应用程序配置
Azure 应用程序配置 是一项 Azure 服务,你可以用它来集中管理应用设置。 应用配置支持层级键值对和版本管理,并与 Azure 密钥保管库 集成,实现更安全的秘密管理。 有关详细信息,请参阅 什么是 Azure 应用配置?
为了提高安全性,你的功能应用使用带有 Microsoft Entra 认证的托管身份来访问应用商店中的设置。 欲了解更多信息,请参见 Use App Configuration references for Azure Functions。
注意
当使用 Azure 应用程序配置 存储基于托管标识的连接设置时,引用必须使用 : 或 / 作为键分隔符,格式为 <CONNECTION_NAME_PREFIX>:fullyQualifiedNamespace。 当你使用常规的应用设置分隔符 __ 时,引用名称无法正确解析。
相关内容
- 有关更多 Azure Functions 性能提示,请参阅 优化 Azure Functions 的性能和可靠性。