Terraform 推测计划中的循环错误

Cyclic Error in Speculative Plan in Terraform

如果我在我的代码中放入以下行,我会收到以下错误:

"MICROSOFT_PROVIDER_AUTHENTICATION_SECRET" = format("@Microsoft.KeyVault(VaultName=%s;SecretName=Webapp-FE-Secret)", module.key-vault.key_vault.self.name)

错误:

Error: Cycle: local.network_acls_ip_rules (expand), module.key-vault.var.key_vault_network_acls_ip_rules (expand), module.key-vault.azurerm_key_vault.default, module.key-vault.output.key_vault (expand), azurerm_app_service.fe, azurerm_app_service.api

如果我不输入上面的行,我不会得到这个错误

我的前端应用服务的完整代码是:

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

  app_service_plan_id = azurerm_app_service_plan.default.id
  name                = module.name_app_service_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"
    allowed_external_redirect_urls = module.application_webapp_fe.application.self.reply_urls
    additional_login_params = {
      "response_type" = "code id_token",
      "resource"      = module.application_webapp_fe.application.self.application_id
    }
    active_directory {
      client_id         = module.application_webapp_fe.application.self.application_id
      client_secret     = module.application_webapp_fe.service_principal.secret.value
      allowed_audiences = []
    }
  }

  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"
     "MICROSOFT_PROVIDER_AUTHENTICATION_SECRET" = format("@Microsoft.KeyVault(VaultName=%s;SecretName=Webapp-FE-Secret)", module.key-vault.key_vault.self.name)
  }

  lifecycle {
    ignore_changes = [
      "site_config",
      "auth_settings"
    ]
  }
}

Key Vault 已有秘密名称:

Webapp-FE-Secret

secret的值是我的前端应用注册的Service Principal

下面是我的 Key Vault 模块的代码:

module "key-vault" {
  version   = "~> 1.0"
  source    = " xxxxx  "
  providers = { azurerm = azurerm, random = random }

  tenant_id             = data.azurerm_client_config.default.tenant_id
  resource_group_name   = module.resourcegroup.resource_group.name
  key_vault_location    = module.resourcegroup.resource_group.location
  key_vault_environment = var.project.environment.name
  key_vault_tags        = module.resourcegroup.resource_group.tags

  key_vault_name = substr(replace(var.project.name, "-", ""), 0, 16)

  key_vault_network_acls_ip_rules                   = concat(local.network_acls_ip_rules, module.project.azure.cidrs.global.contoso_enterprise_egress.all.coreinf)
  key_vault_network_acls_virtual_network_subnet_ids = [local.tfe_vnet_id]
  key_vault_secrets = {
    CosmosDB-PrimaryKey                          = azurerm_cosmosdb_account.default.primary_key
    CosmosDB-PrimaryReadOnlykey                  = azurerm_cosmosdb_account.default.primary_readonly_key
    CosmosDB-PrimaryKey-ConnectionString         = azurerm_cosmosdb_account.default.connection_strings[0]
    CosmosDB-PrimaryReadOnlykey-ConnectionString = azurerm_cosmosdb_account.default.connection_strings[1]

    StorageAccount-PrimaryKey                    = module.storageaccount.storage_account.self.primary_access_key
    StorageAccount-SecondaryKey                  = module.storageaccount.storage_account.self.secondary_access_key
    StorageAccount-ConnectionString-PrimaryKey   = module.storageaccount.storage_account.self.primary_connection_string
    StorageAccount-ConnectionString-SecondaryKey = module.storageaccount.storage_account.self.secondary_connection_string

    StorageAccount-FunctionApp-PrimaryKey                    = module.storageaccount-func-app.storage_account.self.primary_access_key
    StorageAccount-FunctionApp-SecondaryKey                  = module.storageaccount-func-app.storage_account.self.secondary_access_key
    StorageAccount-FunctionApp-ConnectionString-PrimaryKey   = module.storageaccount-func-app.storage_account.self.primary_connection_string
    StorageAccount-FunctionApp-ConnectionString-SecondaryKey = module.storageaccount-func-app.storage_account.self.secondary_connection_string

    Webapp-FE-Secret    = module.application_webapp_fe.service_principal.secret.value
    Webapp-API-Secret   = module.application_webapp_api.service_principal.secret.value
    Function-App-Secret = module.application_func_01.service_principal.secret.value

    frontendappid  = module.application_webapp_fe.application.self.application_id
    frontendappurl = module.application_webapp_fe.application.self.homepage
    frontendhost   = format("https://%s", azurerm_app_service.fe.default_site_hostname)

    appi-default-instrumentation-key = azurerm_application_insights.default["api"].instrumentation_key
    appi-default-app-id              = azurerm_application_insights.default["api"].app_id

    appi-default-fe-instrumentation-key = azurerm_application_insights.default["fe"].instrumentation_key
    appi-default-fe-app-id              = azurerm_application_insights.default["fe"].app_id

    functionappid  = module.application_func_01.application.self.application_id
    functionappurl = module.application_func_01.application.self.homepage
    functionhost   = format("https://%s", azurerm_function_app.default.default_hostname)

    webapiappid  = module.application_webapp_api.application.self.application_id
    webapiappuri = module.application_webapp_api.application.self.homepage
    webapihost   = format("https://%s", azurerm_app_service.api.default_site_hostname)
  }
}

本地区块:

locals {
  network_acls_ip_rules = distinct(
    concat(
      formatlist("%s/32", split(",", azurerm_app_service.api.possible_outbound_ip_addresses)),
      formatlist("%s/32", split(",", azurerm_app_service.api.outbound_ip_addresses)),
      formatlist("%s/32", split(",", azurerm_app_service.fe.possible_outbound_ip_addresses)),
      formatlist("%s/32", split(",", azurerm_app_service.fe.outbound_ip_addresses)),
      formatlist("%s/32", split(",", azurerm_function_app.default.possible_outbound_ip_addresses)),
      formatlist("%s/32", split(",", azurerm_function_app.default.outbound_ip_addresses))
    )
  )
}

谁能帮我解决这个问题。 值:"MICROSOFT_PROVIDER_AUTHENTICATION_SECRET 已手动放入前端应用程序中,目前在 TF 状态下丢失。所以我想将它包含在我的代码中,这样 Terraform 就不会在我每次对我的代码进行迭代时消失

通过包括这一行:

"MICROSOFT_PROVIDER_AUTHENTICATION_SECRET" = format("@Microsoft.KeyVault(VaultName=%s;SecretName=Webapp-FE-Secret)", module.key-vault.key_vault.self.name)

您已经创建了一个循环引用,因为前端应用程序和 Keyvault 相互依赖(例如,一个不能先于另一个构建)

发生循环引用是因为 local.network_acl_ip_rules

中也有这些行
formatlist("%s/32", split(",", azurerm_app_service.fe.possible_outbound_ip_addresses)),
formatlist("%s/32", split(",", azurerm_app_service.fe.outbound_ip_addresses)),

因此需要创建前端应用程序服务以填充创建 Keyvault 所需的那些 IP 值。但是无法创建前端,因为它需要应用程序设置中的 Keyvault 名称。

快速解决方法是将 Keyvault 名称硬编码到应用程序设置中。

长期“修复”将是使用 az cli 或 powershell 脚本在 terraform 之外更新 appsettingsnetwork_acls 并从 terraform 调用脚本...