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

绕过Terraform的"known after apply"问题:如何检测未知变量?

解决Terraform "known after apply" 导致的for_each参数无效问题

问题场景

在部署Azure存储账户对应的Defender防护资源时,使用for_each遍历存储账户ID,若部分存储账户为首次创建(其ID属于"known after apply"的未知值),会触发如下报错:

╷
│ Error: Invalid for_each argument
│ 
│   on storage.tf line 291, in resource "azurerm_security_center_storage_defender" "defender_for_storage":
│  291:   for_each = {
│  292:     for id in [
│  293:       azurerm_storage_account.backups.id,
│  294:       azurerm_storage_account.media_blobs.id,
│  295:     ] : id => id
│  296:   }
│     ├────────────────
│     │ azurerm_storage_account.backups.id is "***"
│     │ azurerm_storage_account.media_blobs.id is a string, known only after apply
│ 
│ The "for_each" map includes keys derived from resource attributes that
│ cannot be determined until apply, and so Terraform cannot determine the
│ full set of keys that will identify the instances of this resource.
│ 
│ When working with unknown values in for_each, it's better to define the map
│ keys statically in your configuration and place apply-time results only in
│ the map values.
│ 
│ Alternatively, you could use the -target planning option to first apply
│ only the resources that the for_each value depends on, and then apply a
│ second time to fully converge.
╵

原代码如下:

resource "azurerm_security_center_storage_defender" "defender_for_storage" {
  for_each = {
    for id in [
      azurerm_storage_account.backups.id,
      azurerm_storage_account.media_blobs.id,
    ] : id => id
  }
  storage_account_id                          = each.value
  malware_scanning_on_upload_enabled          = true
  malware_scanning_on_upload_cap_gb_per_month = 10
  sensitive_data_discovery_enabled            = true
}

解决方案

使用Terraform的isunknown函数过滤未知ID,动态调整for_each的遍历集合,代码如下:

resource "azurerm_security_center_storage_defender" "defender_for_storage" {
  for_each = {
    for id in [
      isunknown(azurerm_storage_account.backups.id) ? "" : azurerm_storage_account.backups.id,
      isunknown(azurerm_storage_account.media_blobs.id) ? "" : azurerm_storage_account.media_blobs.id,
    ] : id => id if id != ""
  }
  storage_account_id                          = each.value
  malware_scanning_on_upload_enabled          = true
  malware_scanning_on_upload_cap_gb_per_month = 10
  sensitive_data_discovery_enabled            = true
}

方案原理

  1. 过滤未知值:通过isunknown判断存储账户ID是否为部署后可知的未知值,将未知ID转为空字符串
  2. 动态生成集合:使用if id != ""过滤掉空值,确保for_each的键集合在部署前完全确定
  3. 分阶段部署适配:第一次部署时,仅为已存在(ID已知)的存储账户创建Defender资源;第二次部署时,所有存储账户ID已确定,自动创建剩余的防护资源

优势

  • 无需修改代码(适配多环境共用场景,避免打乱Git历史)
  • 无需使用-target参数,减少额外部署步骤,提升部署确定性和效率
  • 一键部署即可适配不同环境的资源状态

内容的提问来源于stack exchange,提问作者Simao Gomes Viana

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 04:44:54