You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.03 11:06:04