terraformterraform-provider-azuresubnet

Extract Azure subnet IDs from inline definitions


If Azure subnets are created inline as part of the vnet definition, can the subnet ID be extracted directly? Or is some "massaging" required?

I have the following:

module "vnet" {
  source  = "Azure/avm-res-network-virtualnetwork/azurerm"
  version = "0.7.1"

  address_space       = ["10.10.0.0/16"]
  location            = uksouth
  name                = vnet01
  resource_group_name = rg-temp

  subnets = {
    one = {
      name             = "subnet01"
      address_prefixes = ["10.10.1.0/24"]
    }

    two = {
      name             = "subnet02"
      address_prefixes = ["10.10.2.0/24"]
    }

  }
}

I am then trying to create a private endpoint in the second subnet

resource "azurerm_private_endpoint" "acr" {
  name                = "endpoint-acr01"
  location            = uksouth
  resource_group_name = rg-temp
  subnet_id           = module.vnet.subnets["subnet02"].id

  private_service_connection {
    name                           = "psconn-acr01"
    private_connection_resource_id = module.acr.acr_id.id
    is_manual_connection           = false
    subresource_names              = ["registry"]
  }
}

But this throws the error:

module.vnet.subnets["subnet02"] is object with 4 attributes

This object does not have an attribute named "id".

Is the subnet id directly accessible in this way? Or do I need to do something "funky" to extract it?


Solution

  • You are using a module that wraps the provider's resource types, so this is really a question about that module rather than about Terraform or the hashicorp/azurerm provider.

    At the time of writing the module's subnets output value is defined like this:

    output "subnets" {
      description = <<DESCRIPTION
    Information about the subnets created in the module.
    
    Please refer to the subnet module documentation for details of the outputs.
    DESCRIPTION
      value       = module.subnet
    }
    

    ...and so it's really just passing on verbatim the value produce by a nested module call.

    That module call is, at the time of writing, a call into the ./modules/subnet directory using for_each, and so from that we can at least conclude that the top-level subnets output value is a mapping with the same keys as you passed in to the subnets input variable: subnet01 and subnet02.

    The elements of that mapping are also definitely objects because a module call always produces an object. But what attributes those objects have depends on how that nested module is defined.

    At the time of writing the nested module defines the following output values:

    output "application_gateway_ip_configuration_resource_id" {
      description = "The application gateway ip configurations resource id."
      value       = try(azapi_resource.subnet.body.properties.applicationGatewayIPConfigurations.id, null)
    }
    
    output "name" {
      description = "The resource name of the subnet."
      value       = azapi_resource.subnet.name
    }
    
    output "resource" {
      description = "All attributes of the subnet"
      value       = azapi_resource.subnet
    }
    
    output "resource_id" {
      description = "The resource ID of the subnet."
      value       = azapi_resource.subnet.id
    }
    

    Therefore those are the only valid attribute names that you can write after module.vnet.subnets["subnet02"] with the current version of this module.

    It seems like resource_id holds the value you want -- the subnet's ID -- so you can write that as module.vnet.subnets["subnet02"].resource_id.

    The module is also exporting the entire object representing the subnet as the resource attribute, and so you can access anything documented as a result of azapi_resource as a nested attribute under that attribute. That resource type's id attribute is exported as module.vnet.subnets["subnet02"].resource.id, for example, although of course that's redundant with the resource_id output value that I mentioned in the previous paragraph.