Pulumi Azure-native下Key Vault创建后分配访问策略及循环依赖解决
解决方案
问题本质
循环依赖的根源是两个资源的创建互相依赖对方的输出属性:
- Function App的AppSettings需要Key Vault的密钥URI,且需要访问权限生效才能正常读取
- Key Vault的访问策略需要Function App部署完成后生成的托管标识ID
同时azure-native provider的资源粒度更细,没有classic provider那种隐式的访问策略独立管理逻辑,需要显式调用对应细粒度资源解决。
实现步骤
步骤1:创建带托管标识的基础Function App
先不配置需要Key Vault引用的应用设置,仅部署基础功能的Function App并开启系统托管标识,获取其托管标识的主体ID。
步骤2:为Function App托管标识配置Key Vault访问权限
使用azure-native原生的VaultAccessPolicy细粒度资源,单独为上述托管标识授予密钥读取权限,不需要修改Key Vault的整体配置。
步骤3:单独配置Function App的应用设置
使用azure-native原生的WebAppAppSettings细粒度资源管理应用配置,显式指定依赖上述访问策略完成后再部署,此时即可安全加入Key Vault密钥引用。
完整代码示例(TypeScript)
import * as pulumi from "@pulumi/pulumi"; import * as azure_native from "@pulumi/azure-native"; // 1. 创建基础资源组 const resourceGroup = new azure_native.resources.ResourceGroup("my-rg"); // 2. 创建Function App依赖的存储账户 const storageAccount = new azure_native.storage.StorageAccount("funcstor", { resourceGroupName: resourceGroup.name, sku: { name: azure_native.storage.SkuName.Standard_LRS }, kind: azure_native.storage.Kind.StorageV2, }); // 3. 创建App Service计划 const appServicePlan = new azure_native.web.AppServicePlan("func-plan", { resourceGroupName: resourceGroup.name, sku: { name: "Y1", tier: "Dynamic" }, kind: "FunctionApp", }); // 4. 创建带系统托管标识的基础Function App,暂不配置Key Vault相关应用设置 const funcApp = new azure_native.web.WebApp("my-func-app", { resourceGroupName: resourceGroup.name, serverFarmId: appServicePlan.id, identity: { type: azure_native.web.ManagedServiceIdentityType.SystemAssigned, }, siteConfig: { appSettings: [ { name: "FUNCTIONS_WORKER_RUNTIME", value: "node" }, { name: "FUNCTIONS_EXTENSION_VERSION", value: "~4" }, { name: "AzureWebJobsStorage", value: storageAccount.primaryConnectionString }, ], httpsOnly: true, }, }); // 5. 现有Key Vault 或 新建Key Vault,这里以新建为例 const keyVault = new azure_native.keyvault.Vault("my-kv", { resourceGroupName: resourceGroup.name, properties: { sku: { family: "A", name: azure_native.keyvault.SkuName.Standard }, tenantId: pulumi.config.require("azure-native:tenantId"), accessPolicies: [], // 初始可留空,后续用单独资源添加访问策略 enableRbacAuthorization: false, // 这里使用访问策略模式,若用RBAC请调整为true }, }); // 6. 单独为Function App托管标识添加Key Vault密钥读取权限 const secretAccessPolicy = new azure_native.keyvault.VaultAccessPolicy("func-secret-policy", { resourceGroupName: resourceGroup.name, vaultName: keyVault.name, properties: { accessPolicies: [{ tenantId: funcApp.identity.apply(id => id?.tenantId!), objectId: funcApp.identity.apply(id => id?.principalId!), permissions: { secrets: ["get"], }, }], }, }); // 7. 单独管理Function App应用设置,显式依赖访问策略部署完成 const funcAppSettings = new azure_native.web.WebAppAppSettings("func-app-settings", { resourceGroupName: resourceGroup.name, name: funcApp.name, properties: { // 保留基础配置 "FUNCTIONS_WORKER_RUNTIME": "node", "FUNCTIONS_EXTENSION_VERSION": "~4", "AzureWebJobsStorage": storageAccount.primaryConnectionString, // 新增Key Vault密钥引用 "DB_PASSWORD": pulumi.interpolate`@Microsoft.KeyVault(SecretUri=${keyVault.properties.vaultUri}secrets/db-password/)`, }, }, { dependsOn: [secretAccessPolicy] }); // 输出Function App域名 export const funcEndpoint = pulumi.interpolate`https://${funcApp.defaultHostName}/api`;
注意事项
- 若Key Vault使用RBAC权限模式,替换
VaultAccessPolicy资源为角色分配,给Function App标识分配Key Vault Secrets User角色即可,整体逻辑不变 WebAppAppSettings资源会覆盖Function App的所有应用设置,因此需要把基础配置也同步写入该资源的properties中- 单独的
VaultAccessPolicy资源只会增量添加访问策略,不会覆盖Key Vault上已有的其他访问策略配置
内容的提问来源于stack exchange,提问作者S2L
相关产品推荐
相关产品推荐

