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

使用Terraform创建Azure AD B2C用户流时遇应用查找失败问题

问题解决:Terraform创建Azure AD B2C应用后无法找到应用导致管理员授权失败

问题现象

使用Terraform创建Azure AD B2C应用及登录/注册用户流时,执行null_resource.admin_consent中的本地脚本时,始终无法通过az ad app show找到已创建的应用(ID:d4be9c7c-acf4-4cc8-b27a-b18759d40034),导致后续管理员授权步骤终止,错误输出显示循环语法未被正确解析:

Attempt {1..80}: Checking if application is available...
Application not found. Retrying in 15 seconds...
Error: Application d4be9c7c-acf4-4cc8-b27a-b18759d40034 still not found after waiting. Exiting...

问题根源

  1. Shell语法兼容性问题:脚本中的for i in {1..80}是Bash专属语法,如果Terraform的local-exec默认使用Windows CMD/PowerShell,该语法不会被解析,导致循环仅执行一次而非80次。
  2. 租户上下文错误:az ad app show默认查询当前CLI上下文的Azure AD租户,若未切换到B2C租户,会在错误的租户中查找应用,自然无法找到。
  3. 依赖关系不严谨:当前admin_consent的依赖未包含权限配置步骤,可能在权限未完成注册时就尝试授权。

解决方案

1. 修复Shell循环语法

根据运行环境选择兼容的循环语法,或强制local-exec使用Bash:

  • 若使用Windows,确保安装Git Bash并指定interpreter = ["bash", "-c"];
  • 若使用PowerShell,改用for ($i=1; $i -le 80; $i++)语法。

2. 指定B2C租户ID

在所有az命令中添加--tenant <B2C_TENANT_ID>参数,确保查询和操作的是正确的B2C租户。

3. 优化依赖关系

将admin_consent的依赖添加azuread_service_principal_delegated_permission_grant.b2c_permission,确保权限配置完成后再执行授权。

4. 移除冗余的应用ID提取

直接使用azuread_application.b2c_app.client_id作为应用ID,无需通过regex从id属性提取(id属性是Terraform资源路径,client_id才是Azure AD应用的实际ID)。

修改后的完整代码

# Microsoft Graph Service Principal
data "azuread_application_published_app_ids" "well_known" {}

resource "azuread_service_principal" "msgraph" {
  client_id    = data.azuread_application_published_app_ids.well_known.result.MicrosoftGraph
  use_existing = true
}

# Create Azure AD B2C Application
resource "azuread_application" "b2c_app" {
  display_name = "Terraform-B2C-App"

  required_resource_access {
    resource_app_id = data.azuread_application_published_app_ids.well_known.result.MicrosoftGraph

    resource_access {
      id   = azuread_service_principal.msgraph.app_role_ids["User.Read.All"]
      type = "Role"
    }

    resource_access {
      id   = azuread_service_principal.msgraph.oauth2_permission_scope_ids["User.ReadWrite"]
      type = "Scope"
    }
  }
}

# Ensure App Creation Is Recognized in Azure
resource "time_sleep" "wait_for_app" {
  depends_on      = [azuread_application.b2c_app]
  create_duration = "120s"  # Increased to allow Azure API propagation
}

# Create Service Principal for the B2C App
resource "azuread_service_principal" "b2c_sp" {
  client_id  = azuread_application.b2c_app.client_id
  depends_on = [time_sleep.wait_for_app]
}

# Assign Delegated Permissions to Service Principal
resource "azuread_service_principal_delegated_permission_grant" "b2c_permission" {
  service_principal_object_id          = azuread_service_principal.b2c_sp.object_id
  resource_service_principal_object_id = azuread_service_principal.msgraph.object_id

  claim_values = [
    "openid",
    "offline_access",
    "User.Read",
    "User.ReadWrite",
    "email",
    "profile"
  ]

  depends_on = [azuread_service_principal.b2c_sp]
}

# Grant Admin Consent with Fixed Wait & Verification
resource "null_resource" "admin_consent" {
  provisioner "local-exec" {
    interpreter = ["bash", "-c"] # 强制使用Bash,Windows需安装Git Bash/WSL
    command = <<EOT
      APP_ID="${azuread_application.b2c_app.client_id}"
      B2C_TENANT_ID="<你的B2C租户ID>" # 替换为实际的B2C租户ID
      echo "Waiting for the application ($APP_ID) to be fully available in Azure AD B2C..."

      # 修复后的Bash循环
      for ((i=1; i<=80; i++)); do
        echo "Attempt $i: Checking if application is available..."
        if az ad app show --id $APP_ID --tenant $B2C_TENANT_ID > /dev/null 2>&1; then
          echo "Application is now available."
          break
        fi
        echo "Application not found. Retrying in 15 seconds..."
        sleep 15
      done

      # 验证应用存在
      if ! az ad app show --id $APP_ID --tenant $B2C_TENANT_ID > /dev/null 2>&1; then
        echo "Error: Application $APP_ID still not found after waiting. Exiting..."
        exit 1
      fi

      echo "Granting admin consent..."
      for ((attempt=1; attempt<=3; attempt++)); do
        if az ad app permission admin-consent --id $APP_ID --tenant $B2C_TENANT_ID; then
          echo "Admin consent granted successfully."
          exit 0
        fi
        echo "Admin consent failed. Retrying in $((attempt * 15)) seconds..."
        sleep $((attempt * 15))
      done

      echo "Admin consent failed after multiple attempts. Exiting."
      exit 1
    EOT
  }

  depends_on = [azuread_service_principal_delegated_permission_grant.b2c_permission]
}

# Create Sign-In User Flow
resource "null_resource" "create_signin_userflow" {
  provisioner "local-exec" {
    interpreter = ["bash", "-c"]
    command = <<EOT
      B2C_TENANT_ID="<你的B2C租户ID>" # 替换为实际的B2C租户ID
      az rest --method POST \
      --url "https://graph.microsoft.com/beta/identity/b2cUserFlows" \
      --headers "Content-Type=application/json" \
      --body '{
        "id": "B2C_1A_SignIn",
        "userFlowType": "signIn",
        "userFlowTypeVersion": 1
      }' \
      --tenant $B2C_TENANT_ID
    EOT
  }

  depends_on = [null_resource.admin_consent]
}

# Create Sign-Up User Flow
resource "null_resource" "create_signup_userflow" {
  provisioner "local-exec" {
    interpreter = ["bash", "-c"]
    command = <<EOT
      B2C_TENANT_ID="<你的B2C租户ID>" # 替换为实际的B2C租户ID
      az rest --method POST \
      --url "https://graph.microsoft.com/beta/identity/b2cUserFlows" \
      --headers "Content-Type=application/json" \
      --body '{
        "id": "B2C_1A_SignUp",
        "userFlowType": "signUp",
        "userFlowTypeVersion": 1
      }' \
      --tenant $B2C_TENANT_ID
    EOT
  }

  depends_on = [null_resource.create_signin_userflow]
}

额外注意事项

  • 若使用Windows环境,需确保已安装Git Bash或WSL,并配置Terraform能找到bash路径;
  • 替换代码中的<你的B2C租户ID>为实际的B2C租户ID(格式如xxx.onmicrosoft.com或租户GUID);
  • 确保当前az cli已登录且具备B2C租户的管理员权限。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 21:34:53