Azure/Terraform:将子网链接到NSG(ERROR-for_eachMap包括从资源属性派生的键,这些键在应用之前无法确定)

u91tlkcl  于 2023-02-19  发布在  其他
关注(0)|答案(1)|浏览(124)

已锁定4天。此问题的评论已被禁用,但仍接受新答案和其他交互。Learn more
目标:使用一个模块将环境中的多个子网链接到相应的NSG(NSG和子网是使用单独的模块创建的)
根模块:

1.main.tf

resource "azurerm_subnet_network_security_group_association" "root_subnet_nsg_association" {
  subnet_id                 = var.subnet_id
  network_security_group_id = var.nsg_id
}

2.variables.tf

variable "subnet_id"{
    type=number
    description="ID of the subnet which is to be attached to NSG"
    #default=""
}

variable "nsg_id"{
    type=number
    description="ID of the NSG which is to be associated with a subnet"
    #default=""
}

调用项目文件夹中的模块:
(for_each用于迭代模块)

1.nsg子网关联. tf

module "nsg_subnet_asosciation_module"{
source="../../Modules/network/nsg_subnet_association"

#Variable names to be passed into the root module:
#Use for_each to loop the module:

#for_each accepts a set or map but not list as a value

for_each          = local.nsg_subnet_association

subnet_id=each.key
nsg_id=each.value
}

2.局部变量阻止向调用模块传递值:

  • 注意:使用括号()* 可以在Map中具有动态键
locals{ //Key in subnet name and NSG name for each element of the LIST
        //Implicit dependence on Subnet and NSG being created before attempt to associate

     #It is possible to have dynamic keys using parenthesis () as seen on left below   
     nsg_subnet_association={
        (module.subnet_module["MGT-Subnet-1"].subnet_id)= module.nsg_module["HUB-NSG"].nsg_id
        (module.subnet_module["MGT-Subnet-1"].subnet_id) = module.nsg_module["MGT-NSG"].nsg_id
        (module.subnet_module["SEC-Subnet-1"].subnet_id) = module.nsg_module["SEC-NSG"].nsg_id
    }

}

这将导致以下错误

  • “for_each”Map包含从资源属性派生的键,这些属性在应用之前无法确定,因此Terraform无法确定标识此资源示例的完整键集。

在for_each中处理未知值时,最好在配置中静态定义map键,并将应用时结果仅放在map值中。
或者,您可以使用-target计划选项,首先仅应用for_each值所依赖的资源,然后再次应用以完全收敛。*

c0vxltue

c0vxltue1#

在Terraform中,当动态获取vnet或subnet的值时,可能需要花费时间来创建,并且其他依赖资源无法获取所需的值,因此发生此错误。

    • 错误:**
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.

使用静态定义值的代码来解决错误:
示例:
代码:

    • 变量. tf:**
variable "virtual_network_name" {
  type    = string
  default = "my-virtual-network"
}

variable "subnet_address_prefixes" {
  type    = list(string)
  default = ["10.0.1.0/24", "10.0.2.0/24"]
}

variable "subnet_names" {
  type    = set(string)
  default = ["subnet1", "subnet2"]
}

variable "nsg_names" {
  type    = set(string)
  default = ["nsg1", "nsg2"]
}

variable "subnet_nsg_mappings" {
  type    = map(string)
  default = {
    "subnet1" = "nsg1"
    "subnet2" = "nsg2"
  }
}
    • 主文件. tf**
resource "azurerm_virtual_network" "virtual_network" {
  name                = var.virtual_network_name
  address_space       = ["10.0.0.0/16"]
  location                    = data.azurerm_resource_group.example.location
   resource_group_name  = data.azurerm_resource_group.example.name
   
}

resource "azurerm_network_security_group" "nsg" {
  for_each = toset(var.nsg_names)

  name                = each.value
  location                    = data.azurerm_resource_group.example.location
   resource_group_name  = data.azurerm_resource_group.example.name

    security_rule {
    name                       = "allow_http"
    priority                   = 100
    direction                  = "Inbound"
    access                     = "Allow"
    protocol                   = "Tcp"
    source_port_range          = "*"
    destination_port_range     = "80"
    source_address_prefix      = "*"
    destination_address_prefix = "*"
  }
}

resource "azurerm_subnet" "subnet" {
  for_each = toset(var.subnet_names)

  name                 = each.value
  virtual_network_name = azurerm_virtual_network.virtual_network.name
  address_prefixes     = var.subnet_address_prefixes
  resource_group_name  = data.azurerm_resource_group.example.name
 // enable_multiple_address_prefixes = true
  
}

# Associate each subnet with its corresponding NSG
resource "azurerm_subnet_network_security_group_association" "subnet_nsg" {
 
 for_each = var.subnet_nsg_mappings

  subnet_id              = azurerm_subnet.subnet[each.key].id
  network_security_group_id = azurerm_network_security_group.nsg[each.value].id
  //subnet_id              = azurerm_subnet.subnet[each.key].id
 // network_security_group_id = azurerm_network_security_group.nsg[var.subnet_nsg_mappings[each.value]].id
}

或者

    • 为Map定义局部变量。**
locals {
  subnet_nsg_mappings = {
    "subnet1" = "nsg1",
    "subnet2" = "nsg2",
    "subnet3" = "nsg3"
  }
}

resource "azurerm_subnet_network_security_group_association" "subnet_nsg" {
  for_each = toset(var.subnet_names)

  subnet_id                = azurerm_subnet.subnet[each.value].id
  network_security_group_id = azurerm_network_security_group.nsg[local.subnet_nsg_mappings[each.value]].id
}

如果动态值必须用于_each,则在应用时不能确定密钥。在这种情况下,请使用-target选项首先应用vnet和子网值,即:for_each值所依赖并完全应用的资源。

terraform apply -target="azurerm_virtual_network.virtual_network" -target="azurerm_subnet.subnet"

相关问题