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

配置ADAL时Pulumi中AD应用与Azure函数的循环依赖问题

解决Pulumi部署Azure Function与AD App的循环依赖问题

这种循环依赖确实很常见——Function App需要AD应用的Client ID来配置认证,而AD应用又需要Function App的回调URL来设置回复地址。下面给你两种可行的解决方案,根据你的场景选择:

方法一:提前构造默认域名(最简单,适用于默认Azure域名)

如果你的Function App使用的是Azure默认的*.azurewebsites.net域名,那你完全可以提前通过Function App的名称构造出回调URL,不需要等资源创建完成。因为Function App的名称是你自己定义的(${projectName}-${env}),默认域名就是https://{app-name}.azurewebsites.net。

修改后的代码如下:

const projectName = "your-project"; // 替换为你的项目名
const env = "dev"; // 替换为你的环境名

const adAppName = `${projectName}-${env}`;
const appFunctionName = `${projectName}-${env}`;

// 提前构造Function App的回调URL(默认域名)
const functionCallbackUrl = `https://${appFunctionName}.azurewebsites.net/.auth/login/aad/callback`;

// 1. 先创建AD应用,用提前构造好的回调URL
const adApp = new azuread.Application(adAppName, { 
    name: adAppName, 
    requiredResourceAccesses: [ 
        { 
            resourceAccesses: [ 
                { id: "311a71cc-e848-46a1-bdf8-97ff7156d8e6", type: "Scope", }, 
            ], 
            resourceAppId: "00000002-0000-0000-c000-000000000000", 
        } 
    ], 
    replyUrls: [functionCallbackUrl] 
}); 

// 2. 创建Function App,依赖AD应用的Client ID
const appFunction = new azure.appservice.FunctionApp(appFunctionName, { 
    ...resourceGroupArgs, 
    name: appFunctionName, 
    appServicePlanId: appServicePlan.id, 
    authSettings: { 
        enabled: true, 
        unauthenticatedClientAction: 'RedirectToLoginPage', 
        defaultProvider: 'AzureActiveDirectory', 
        issuer: `https://sts.windows.net/${azure.config.tenantId}/`, 
        activeDirectory: { clientId: adApp.applicationId } 
    }, 
    storageConnectionString: storageAccount.primaryConnectionString, 
    version: '~2', 
    appSettings: appSettings, 
}); 

优点:代码简洁,没有额外的资源操作,部署流程更顺畅。
缺点:仅适用于默认Azure域名,如果后续要使用自定义域名,这个方法就不适用了。

方法二:分阶段更新AD应用(灵活支持自定义域名)

如果需要支持自定义域名,或者你不想依赖提前构造的URL,可以分三步打破循环:

  1. 先创建AD应用,初始时不设置回复URL(或设置一个临时占位URL);
  2. 创建Function App,获取它实际的域名输出;
  3. 用Function App的域名更新AD应用的回复URL。

修改后的代码如下:

const projectName = "your-project";
const env = "dev";

const adAppName = `${projectName}-${env}`;
const appFunctionName = `${projectName}-${env}`;

// 1. 创建AD应用,初始回复URL设为空数组
const adApp = new azuread.Application(adAppName, { 
    name: adAppName, 
    requiredResourceAccesses: [ 
        { 
            resourceAccesses: [ 
                { id: "311a71cc-e848-46a1-bdf8-97ff7156d8e6", type: "Scope", }, 
            ], 
            resourceAppId: "00000002-0000-0000-c000-000000000000", 
        } 
    ], 
    replyUrls: [] 
}); 

// 2. 创建Function App,依赖AD应用的Client ID
const appFunction = new azure.appservice.FunctionApp(appFunctionName, { 
    ...resourceGroupArgs, 
    name: appFunctionName, 
    appServicePlanId: appServicePlan.id, 
    authSettings: { 
        enabled: true, 
        unauthenticatedClientAction: 'RedirectToLoginPage', 
        defaultProvider: 'AzureActiveDirectory', 
        issuer: `https://sts.windows.net/${azure.config.tenantId}/`, 
        activeDirectory: { clientId: adApp.applicationId } 
    }, 
    storageConnectionString: storageAccount.primaryConnectionString, 
    version: '~2', 
    appSettings: appSettings, 
}); 

// 3. 更新AD应用的回复URL,使用Function App实际的域名
const adAppWithCallbackUrl = new azuread.Application(`${adAppName}-update`, {
    id: adApp.id, // 引用已创建的AD应用ID
    replyUrls: appFunction.defaultHostname.apply(hostname => [
        `https://${hostname}/.auth/login/aad/callback`
    ])
});

优点:完全动态获取Function App的域名,支持自定义域名场景,不受默认域名限制。
缺点:多了一个AD应用的更新操作,不过Pulumi会自动处理资源依赖顺序,不会影响部署结果。

额外注意事项

  • 确保Azure AD应用的requiredResourceAccesses配置正确,你当前设置的是Microsoft Graph的User.Read权限(对应ID 311a71cc-e848-46a1-bdf8-97ff7156d8e6),如果需要其他权限可以按需调整。
  • 部署完成后,建议在Azure Portal中验证AD应用的回复URL和Function App的认证配置是否匹配,避免出现登录回调失败的问题。

内容的提问来源于stack exchange,提问作者JuChom

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 08:34:23