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

使用Terraform部署Azure前后端应用注册时出现循环依赖及配置报错

我需要注册两个应用,分别为前端应用与后端应用,二者也对应有各自的Web App资源。我使用Terraform部署所有应用及整套基础设施,但执行terraform plan命令时出现报错,相关代码如下:

前端Web App代码

resource "azurerm_app_service" "fe" {
  location            = module.resourcegroup.resource_group.location
  resource_group_name = module.resourcegroup.resource_group.name
  tags                = module.resourcegroup.resource_group.tags

  app_service_plan_id = azurerm_app_service_plan.default.id
  name                = module.names-web-app-fe.location.app_service.name_unique
  identity { type = "SystemAssigned" }

  auth_settings {
    enabled                       = true
    default_provider              = "AzureActiveDirectory"
    issuer                        = format("https://sts.windows.net/%s/", data.azurerm_client_config.default.tenant_id)
    runtime_version               = "~1"
    token_store_enabled           = true
    unauthenticated_client_action = "RedirectToLoginPage"
    additional_login_params = {
      "response_type" = "code id_token",
      "resource"      = azuread_application.app-fe.application_id
    }
    active_directory {
      client_id         = azuread_application.app-fe.object_id
      client_secret     = azuread_application_password.fe-app-sp-secret.application_object_id
      allowed_audiences = [format("https://%s.azurewebsites.net", module.names-web-app-fe.location.app_service.name_unique)]
    }
  }

  site_config {
    always_on                = true
    app_command_line         = ""
    default_documents        = []
    dotnet_framework_version = "v4.0"
    ftps_state               = "Disabled"
    health_check_path        = ""
    http2_enabled            = true
    linux_fx_version         = "STATICSITE|1.0"
    local_mysql_enabled      = false
    managed_pipeline_mode    = "Integrated"
    min_tls_version          = "1.2"
    #pre_warmed_instance_count = 0
    python_version            = "3.4"
    remote_debugging_enabled  = false
    remote_debugging_version  = "VS2019"
    use_32_bit_worker_process = false
    websockets_enabled        = false
    windows_fx_version        = ""
    cors {
      allowed_origins     = []
      support_credentials = false
    }
  }

  app_settings = {
    "WEBSITE_DNS_SERVER"     = "168.63.129.16"
    "WEBSITE_VNET_ROUTE_ALL" = "1"
  }
}

后端Web App代码

resource "azurerm_app_service" "be" {
  location            = module.resourcegroup.resource_group.location
  resource_group_name = module.resourcegroup.resource_group.name
  tags                = module.resourcegroup.resource_group.tags

  app_service_plan_id = azurerm_app_service_plan.default.id
  name                = module.names-web-app-be.location.app_service.name_unique
  identity { type = "SystemAssigned" }

  auth_settings {
    enabled                       = true
    default_provider              = "AzureActiveDirectory"
    issuer                        = format("https://sts.windows.net/%s/", data.azurerm_client_config.default.tenant_id)
    runtime_version               = "~1"
    token_store_enabled           = true
    unauthenticated_client_action = "RedirectToLoginPage"
    additional_login_params = {
      "response_type" = "code id_token",
      "resource"      = azuread_application.app-be.application_id
    }
    active_directory {
      client_id         = azuread_application.app-be.object_id
      client_secret     = azuread_application_password.be-app-sp-secret.application_object_id
      allowed_audiences = []
    }
  }

  site_config {
    always_on                 = true
    app_command_line          = ""
    default_documents         = []
    dotnet_framework_version  = "v4.0"
    ftps_state                = "AllAllowed"
    health_check_path         = ""
    http2_enabled             = true
    linux_fx_version          = "DOTNETCORE|3.1"
    local_mysql_enabled       = false
    managed_pipeline_mode     = "Integrated"
    min_tls_version           = "1.2"
    python_version            = "3.4"
    remote_debugging_enabled  = false
    remote_debugging_version  = "VS2019"
    use_32_bit_worker_process = false
    windows_fx_version        = ""
    websockets_enabled        = true
    cors {
      allowed_origins     = [format("https://%s", azurerm_app_service.fe.default_site_hostname)]
      support_credentials = true
    }
  }

  app_settings = {
    "WEBSITE_DNS_SERVER"     = "168.63.129.16"
    "WEBSITE_VNET_ROUTE_ALL" = "1"
  }
}

UUID生成代码

resource "random_uuid" "qb2-sal" {}

前端应用注册代码

resource "azuread_application" "app-fe" {
  display_name = format("%s-fe", var.project.name)

  api {
    oauth2_permission_scope {
      admin_consent_description  = "Allows the app to read and write data"
      admin_consent_display_name = local.oauth2_permissions.read-and-write.admin_consent_display_name
      enabled                    = true
      id                         = random_uuid.qb2-sal.results
      type                       = "User"
      value                      = "read-and-write"
    }
  }

  app_role {
    allowed_member_types = ["User", "Application"]
    description          = "Application administrators have the ability to administer the application."
    display_name         = local.app_roles.application-administrator.display_name
    enabled              = true
    id                   = "02c4e591-d667-51db-5597-e2c446ec246b"
    value                = "application-administrator"
  }

  web {
    logout_url    = format("https://%s.azurewebsites.net/.auth/logout", module.names-web-app-fe.location.app_service.name_unique)
    redirect_uris = [format("https://%s.azurewebsites.net/.auth/login/aad/callback", module.names-web-app-fe.location.app_service.name_unique)]

    implicit_grant {
      access_token_issuance_enabled = true
      id_token_issuance_enabled     = true
    }
  }

  required_resource_access {
    resource_app_id = azuread_application.app-be.application_id # Microsoft Graph

    resource_access {
      id   = "02c4e591-d667-51db-5597-e2c446ec246b" # User.Read.All
      type = "Role"
    }
  }
}

前端服务主体密码代码

resource "azuread_application_password" "fe-app-sp-secret" {
  application_object_id = azuread_application.app-fe.object_id
}

后端应用注册代码

resource "azuread_application" "app-be" {
  display_name = format("%s-be", var.project.name)

  api {
    oauth2_permission_scope {
      admin_consent_description  = "Allows the app to read and write data"
      admin_consent_display_name = local.oauth2_permissions.read-and-write.admin_consent_display_name
      enabled                    = true
      id                         = random_uuid.qb2-sal.result
      type                       = "User"
      value                      = "read-and-write"
    }
  }

  app_role {
    allowed_member_types = ["User", "Application"]
    description          = "Application administrators have the ability to administer the application."
    display_name         = local.app_roles.application-administrator.display_name
    enabled              = true
    id                   = "02c4e591-d667-51db-5597-e2c446ec246b"
    value                = "application-administrator"
  }

  web {
    logout_url    = format("https://%s.azurewebsites.net/.auth/logout", module.names-web-app-be.location.app_service.name_unique)
    redirect_uris = [format("https://%s.azurewebsites.net/.auth/login/aad/callback", module.names-web-app-be.location.app_service.name_unique)]

    implicit_grant {
      access_token_issuance_enabled = true
      id_token_issuance_enabled     = true
    }
  }
}

后端服务主体密码代码

resource "azuread_application_password" "be-app-sp-secret" {
  application_object_id = azuread_application.app-be.object_id
}

执行terraform plan时的报错信息

Error: .group_membership_claims: missing expected [

问题排查与修复方案

报错原因

  1. 你使用的Azure AD Terraform Provider版本要求azuread_application资源必须显式声明group_membership_claims参数,该参数为数组类型,未声明就会触发缺少[的报错。
  2. 代码存在笔误:前端应用注册的oauth2_permission_scope块中,UUID引用写的是random_uuid.qb2-sal.results,多了末尾的s,正确属性名是result。
  3. 你提到的循环依赖问题来自前端应用注册的required_resource_access块直接引用后端应用注册的application_id,如果后续有反向依赖就会形成死循环。

修复步骤

  1. 给前后端两个azuread_application资源都添加group_membership_claims参数,可根据实际需求赋值,不需要该配置可以设为空数组,示例:
resource "azuread_application" "app-fe" {
  display_name = format("%s-fe", var.project.name)
  group_membership_claims = [] # 新增该行,可根据需求替换为["SecurityGroup"]、["All"]等值

  api {
    oauth2_permission_scope {
      # 其他配置不变
      id = random_uuid.qb2-sal.result # 修正这里的笔误,去掉末尾的s
      # 其他配置不变
    }
  }
  # 其余原有配置保持不变
}

后端应用注册资源同理添加group_membership_claims参数即可。
2. 若要消除循环依赖,可调整架构将后端应用注册的创建与前端应用注册的依赖拆分,或者提前预定义后端应用的客户端ID作为变量传入,避免运行时互相引用。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.29 20:09:01