简体   繁体   中英

Terraform referencing output from another module with for_each

I am having trouble referencing an output from a module in another module. The resources in the first module was deployed using for_each. The resources in the second module is trying to reference the resources from first module

There are 2 modules created

  1. Security Group
  2. VM

The intention is to assign the Security Group to the VM

The following is the module for the Security Group


variable "configserver" {
  type = map(object({
    name              = string
    location          = string
    subnet            = string
    availability_zone = string
    vm_size           = string
    hdd_size          = string
  }))
}


module "configserver_nsg" {
  for_each = var.configserver

  source              = "../../../terraform/modules/azure-network-security-group"
  resource_group_name = var.resource_group_name
  tags                = var.tags
  location = each.value.location
  nsg_name = "${each.value.name}-nsg"

  security_rules = [
    {
      name              = "Office",
      priority          = "100"
      direction         = "Inbound"
      access            = "Allow"
      protocol          = "TCP"
      source_port_range = "*"
      destination_port_ranges = [
        "22"]
      source_address_prefix = "192.168.1.100"
      destination_address_prefixes = [
        module.configserver_vm[each.key].private_ip
      ]
    },
    

    {
      name                       = "Deny-All-Others"
      priority                   = 4096
      direction                  = "Inbound"
      access                     = "Deny"
      protocol                   = "*"
      source_port_range          = "*"
      destination_port_range     = "*"
      source_address_prefix      = "*"
      destination_address_prefix = "*"
    }

  ]
}

// Value


configserver = {
  config1 = {
    name              = "config1"
    location          = "eastus"
    subnet            = "services"
    availability_zone = 1
    vm_size           = "Standard_F2s_v2"
    hdd_size          = 30
  }
}

The security group module source has an output file which outputs the id of the nsg

output "nsg_id" {
  description = "The ID of the newly created Network Security Group"
  value       = azurerm_network_security_group.nsg.id
}

Generally, if there isn't a for_each, I could access the nsg_id like this

module.configserver_nsg.id

So far this is good, now the issue is that I am not able to access the nsg_id from another module

module "configserver_vm" {
  for_each = var.configserver

  source         = "../../../terraform/modules/azure-linux-vm"
  resource_group = module.resource_group.name
  ssh_public_key = var.ssh_public_key
  tags           = var.tags
  vm_name            = each.value.name
  location           = each.value.location
  subnet_id          = each.value.subnet
  availability-zones = each.value.availability_zone
  vm_size            = each.value.vm_size
  hdd-size           = each.value.hdd_size
  nsg_id             = module.configserver_nsg[each.key].nsg_id
}

Based on my research these, a number of posts ( here , here , here say I should be able to loop through the map using each.key however

nsg_id             = module.configserver_nsg[each.key].nsg_id

this produces the error

Error: Cycle: module.configserver_nsg (close), module.configserver_vm.var.nsg_id (expand), module.configserver_vm.azurerm_network_interface_security_group_association.this, module.configserver_vm (close), module.configserver_nsg.var.security_rules (expand), module.configserver_nsg.azurerm_network_security_group.nsg, module.configserver_nsg.output.nsg_id (expand)

Is there any other way to reference the value?

As I see the first problem is that you use the wrong way to quote the things from the module configserver_nsg for the NSG id, it should be like this:

nsg_id             = module.configserver_nsg[each.value.name].nsg_id

And the second problem has been said by @Matt. It's a cyclical dependency between the two modules. The thing that makes the cyclical dependency is the NSG rule, it seems the NSG rule needs the VM private IP address. According to my knowledge, you cannot solve the cyclical dependency if you do not make a change. So I recommend you make a change that separates the NSG rule from the module configserver_nsg and use the resource azurerm_network_security_rule instead after the two modules.

And finally, it seems like this:

variable "configserver" {
  type = map(object({
    name              = string
    location          = string
    subnet            = string
    availability_zone = string
    vm_size           = string
    hdd_size          = string
  }))
}


module "configserver_nsg" {
  for_each = var.configserver

  source              = "../../../terraform/modules/azure-network-security-group"
  resource_group_name = var.resource_group_name
  tags                = var.tags
  location = each.value.location
  nsg_name = "${each.value.name}-nsg"

  security_rules = [
    {
      
    },
    

    {
      name                       = "Deny-All-Others"
      priority                   = 4096
      direction                  = "Inbound"
      access                     = "Deny"
      protocol                   = "*"
      source_port_range          = "*"
      destination_port_range     = "*"
      source_address_prefix      = "*"
      destination_address_prefix = "*"
    }

  ]
}

// Value


configserver = {
  config1 = {
    name              = "config1"
    location          = "eastus"
    subnet            = "services"
    availability_zone = 1
    vm_size           = "Standard_F2s_v2"
    hdd_size          = 30
  }
}

module "configserver_vm" {
  for_each = var.configserver

  source         = "../../../terraform/modules/azure-linux-vm"
  resource_group = module.resource_group.name
  ssh_public_key = var.ssh_public_key
  tags           = var.tags
  vm_name            = each.value.name
  location           = each.value.location
  subnet_id          = each.value.subnet
  availability-zones = each.value.availability_zone
  vm_size            = each.value.vm_size
  hdd-size           = each.value.hdd_size
  nsg_id             = module.configserver_nsg[each.value.name].nsg_id
}

resource "azurerm_network_security_rule" "configserver_nsg" {
  for_each = var.configserver
  name              = "Office",
  priority          = "100"
  direction         = "Inbound"
  access            = "Allow"
  protocol          = "TCP"
  source_port_range = "*"
  destination_port_ranges = ["22"]
  source_address_prefix = "192.168.1.100"
  destination_address_prefixes = [
    module.configserver_vm[each.key].private_ip
  ]
  resource_group_name         = var.resource_group_name
  network_security_group_name = "${each.value.name}-nsg"
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM