Inappropriate value for attribute "network_interface_id": string required for azurerm_network_interface_application_security_group_association

168 views Asked by At

I am trying to associated NIC addresses to the existing application security group using the id. However, I am getting " Inappropriate value for attribute "network_interface_id": string required for azurerm_network_interface_application_security_group_association"

Below is my azure terraform code.

main.tf ( root module )

module "virtualmachine" {
  source                  = "./virtualmachine"
  virtual_machines        = var.virtual_machines
}

vairable.tf ( root module )

variable "virtual_machines" {}

virtual machine module code

resource "azurerm_network_interface" "nic" {
    
  for_each = {
     for vm in flatten([
       for vm_name, vm in var.virtual_machines.nodes : [
         for nic_name, nic in vm.networks : {
           vm_number      = vm.vm_num,
           vm_name        = vm_name,
           nic_name       = nic_name,
           subnet_value   = nic.subnet
           nic_name_value = nic.nic_name
         }
       ]
     ]) : "${vm.vm_name}-${vm.nic_name}" => vm
   }
  name                = "${each.value.nic_name_value}-nic"
  location            = "eastus"
  resource_group_name = "test"
   
  ip_configuration {
    name                          = "${each.value.nic_name_value}-ipconfig"
    subnet_id                     = each.value.subnet_value
    private_ip_address_allocation = "Dynamic"
  }
}
    
resource "azurerm_linux_virtual_machine" "vm" {
  depends_on                      = [azurerm_network_interface.nic]
  for_each                        = var.virtual_machines.nodes
  name                            = "${each.value.vm_name}-${each.value.vm_num}"
  admin_username                  = "testadmin"
  admin_password                  = "test@1234522"
  disable_password_authentication = false
  location                        = "eastus"
  resource_group_name             = "test"
  network_interface_ids           = [for nic_key, nic in azurerm_network_interface.nic : nic.id if startswith(nic_key, "${each.key}-")]
  size                            = "Standard_B2ms"
   
  os_disk {
    name                 = "${each.value.vm_name}-${each.value.vm_num}-OSdisk"
    caching              = "ReadWrite"
    storage_account_type = "Standard_LRS"
  }
    
  source_image_reference {
    publisher = "RedHat"
    offer     = "RHEL"
    sku       = "82gen2"
    version   = "latest"
  }
}
    
resource "azurerm_network_interface_application_security_group_association" "asg_association" {
   for_each = {
     for vm in flatten([
       for vm_name, vm in var.virtual_machines.nodes : [
         for asg_name, asg in vm.ass_nic_asg : {
           asg_name = asg_name
           vm_name  = vm_name
           asg_id   = asg.asg_id
         }
       ]
     ]) : "${vm.vm_name}-${vm.asg_name}" => vm
  }
  network_interface_id          = [for nic_key, nic in azurerm_network_interface.nic : nic.id]
  application_security_group_id = each.value.asg_id
}

virtual machine variable.tf

variable "virtual_machines" {}

variable.tfvars

virtual_machines = {
  nodes = {
    app1_node1 = {
       "vm_name" = "app"
       "vm_num"  = "1"
       networks = {
         nic1 = {
           "nic_name" = "app-1"
           "subnet"   = "****/app-subnet"
         },
      }
      ass_nic_asg = {
        asg1 = {
          asg_id = "***/app-asg"
        }
        ags2 = {
          asg_id = "***/app-asg"
        }
      }
    }
  }
}

Error :

│ Error: Incorrect attribute value type
│
│   on virtualmachine\main.tf line 69, in resource "azurerm_network_interface_application_security_group_association" "asg_association":
│   69:   network_interface_id          = [for nic_key, nic in azurerm_network_interface.nic : nic.id]
│     ├────────────────
│     │ azurerm_network_interface.nic is object with 1 attribute "app1_node1-nic1"
│
│ Inappropriate value for attribute "network_interface_id": string required.
╵
╷
│ Error: Incorrect attribute value type
│
│   on virtualmachine\main.tf line 69, in resource "azurerm_network_interface_application_security_group_association" "asg_association":
│   69:   network_interface_id          = [for nic_key, nic in azurerm_network_interface.nic : nic.id]
│     ├────────────────
│     │ azurerm_network_interface.nic is object with 1 attribute "app1_node1-nic1"
│
│ Inappropriate value for attribute "network_interface_id": string required.
╵

can someone through a light where I am doing wrong in getting the network interface id ?

Expected - tfvars structure

virtual_machines = {
  nodes = {
    app1_node1 = {
      "vm_name" = "app"
      "vm_num"  = "1"
      networks = {
        nic1 = {
          "nic_name" = "app-1"
          "subnet"   = "**/app-subnet"
          "asg_ids"    = ["**/app-asg", "**/db-asg"]
        },
        nic2 = {
          "nic_name" = "app-2"
          "subnet"   = "**app-subnet"
          "asg_ids"    = ["**/app-asg", "**/db-asg"]
        },
      }
    }
  }
}
1

There are 1 answers

9
Vinay B On

I tried to associate the NIC addresses to the existing application security group using the ID and I was able to provision the requirement successfully.

You are facing a typical problem that occurs when using for_each and complex object structures in Terraform. This problem is more evident when you want to link resources to each other.

`Inappropriate value for attribute "network_interface_id": string required.` 

indicates that Terraform is expecting a single string for network_interface_id, but your expression is generating a list of strings. This happens because you're using a list comprehension inside the assignment which generates a list.

Moreover, the new error you encountered after applying the suggested fix:Error: Invalid index is due to attempting to access a network interface that does not exist for the given key. This is because your for_each in the azurerm_network_interface_application_security_group_association resource attempts to loop over a set of VMs and their associated ASGs without directly correlating them with the specific NICs they should be associated with.

I tried a configuration and made some necessary corrections and I was able to achieve the requirement.

My Terraform configurations:

main.tf:

provider "azurerm" {
  features {}
}

variable "virtual_machines" {
  description = "A map of virtual machines to create"
  type = map(object({
    vm_name   = string
    vm_num    = number
    network = object({
      nic_name = string
      subnet_id   = string
      asg_ids = list(string)
    })
  }))
}

module "virtual_machine_setup" {
  source = "./modules/virtual_machine_setup"
  virtual_machines = var.virtual_machines
}

modules/virtual_machine_setup/main.tf

variable "virtual_machines" {
  description = "A map of virtual machines with their network interfaces and ASGs"
  type = map(object({
    vm_name  = string
    vm_num   = number
    networks = map(object({
      nic_name = string
      subnet   = string
      asg_ids  = list(string)
    }))
  }))
}


data "azurerm_resource_group" "example" {
  name = "demovk-resources"
}

locals {
  // Flatten NICs for easy access
  all_nics = flatten([
    for vm_name, vm in var.virtual_machines : [
      for nic_key, nic in vm.networks : {
        vm_name  = vm_name,
        nic_name = nic.nic_name,
        subnet   = nic.subnet,
        asg_ids  = nic.asg_ids
      }
    ]
  ])

  // Prepare NIC-ASG associations
  nic_asg_associations = flatten([
    for nic in local.all_nics : [
      for asg_id in nic.asg_ids : {
        nic_name = nic.nic_name,
        asg_id   = asg_id
      }
    ]
  ])
}





resource "azurerm_network_interface" "nic" {
  for_each = { for nic in local.all_nics : nic.nic_name => nic }

  name                = each.key
  location            = "eastus2" # Ensure this matches your actual resource group location
  resource_group_name = data.azurerm_resource_group.example.name

  ip_configuration {
    name                          = "internal"
    subnet_id                     = each.value.subnet
    private_ip_address_allocation = "Dynamic"
  }
}


resource "azurerm_linux_virtual_machine" "vm" {
  for_each = var.virtual_machines

  name                = each.value.vm_name
  resource_group_name = data.azurerm_resource_group.example.name
  location            = "eastus2" # Adjust as necessary
  size                = "Standard_B2s" # Adjust as necessary

  network_interface_ids = [for nic in local.all_nics : azurerm_network_interface.nic[nic.nic_name].id if nic.vm_name == each.key]

  os_disk {
    caching              = "ReadWrite"
    storage_account_type = "Standard_LRS"
  }

  source_image_reference {
    publisher = "Canonical"
    offer     = "UbuntuServer"
    sku       = "18.04-LTS"
    version   = "latest"
  }

  admin_username                  = "adminuser"
  admin_password                  = "Password1234!" # Ensure secure handling of credentials
  disable_password_authentication = false
}

resource "azurerm_network_interface_application_security_group_association" "nic_asg_association" {
  for_each = { for assoc in local.nic_asg_associations : "${assoc.nic_name}|${assoc.asg_id}" => assoc }

  network_interface_id          = azurerm_network_interface.nic[each.value.nic_name].id
  application_security_group_id = each.value.asg_id
}

terraform.tfvars:

 virtual_machines = {
  "app1_node1" = {
    vm_name = "appvm1"
    vm_num  = 1
    networks = {
      "nic1" = {
        nic_name = "appnic-1"
        subnet   = "/subscriptions/SubID/resourceGroups/demovk-resources/providers/Microsoft.Network/virtualNetworks/testvksb/subnets/testvk"
        asg_ids  = [
          "/subscriptions/SubID/resourceGroups/demovk-resources/providers/Microsoft.Network/applicationSecurityGroups/test1asg",
          "/subscriptions/SubID/resourceGroups/demovk-resources/providers/Microsoft.Network/applicationSecurityGroups/test2asg"
        ]
      },
      "nic2" = {
        nic_name = "appnic-2"
        subnet   = "/subscriptions/SubID/resourceGroups/demovk-resources/providers/Microsoft.Network/virtualNetworks/testvksb/subnets/testvk"
        asg_ids  = [
          "/subscriptions/SubID/resourceGroups/demovk-resources/providers/Microsoft.Network/applicationSecurityGroups/test3asg",
          "/subscriptions/SubID/resourceGroups/demovk-resources/providers/Microsoft.Network/applicationSecurityGroups/test4asg"
        ]
      }
    }
  }
}

Output:

enter image description here

enter image description here

enter image description here

enter image description here