How to use output of one module into another module

Dear Community Members,

I am new to terraform and need help to resolve one issue i am having with Terraform code.

I am using terraform to create few resources in Azure.

below is my module structure in terraform
.
├── ALZ-3
│ ├── README.md
│ ├── main.tf
│ ├── provider.tf
│ ├── variables.auto.tfvars
│ └── variables.tf
└── Modules
├── nat_gateway
│ ├── README
│ ├── nat_gateway.tf
│ ├── output.tf
│ ├── provider.tf
│ └── variables.tf
├── network
│ ├── README.md
│ ├── network.tf
│ ├── output.tf
│ ├── provider.tf
│ └── variables.tf
└── resource_group
├── README.md
├── output.tf
├── provider.tf
├── rg.tf
└── variables.tf

In network module creating one VNET with three different Subnets.

below is TF code for the VNET & subent creation.

This Code will create VNETs

resource “azurerm_virtual_network” “vnets” {
name = “vnet-{var.env}-{var.app}”
address_space = var.address_space
location = var.location
resource_group_name = var.resource_group_name
}

This code will create subnets

resource “azurerm_subnet” “subnets” {
for_each = var.subnets
name = “snet-{var.env}-{var.app}-${each.key}”
resource_group_name = var.resource_group_name
virtual_network_name = azurerm_virtual_network.vnets.name
address_prefixes = [each.value.address_prefix]
}

In nat_gateway module creating one nat gateway along with public IP.

Below is the TF Code to create nat_gateway

Create Public IP for NAT Gateway

resource “azurerm_public_ip” “ngw_pip” {
name = “{var.app}-{var.env}-ngw1-pip1”
resource_group_name = var.resource_group_name
location = var.location
ip_version = “IPv4”
sku = “Standard”
allocation_method = “Static”
sku_tier = “Regional”
zones = [“1”]
}

Crearte NAT Gateway

resource “azurerm_nat_gateway” “ngw” {
name = “{var.app}-{var.env}-vnet1-ngw1”
resource_group_name = var.resource_group_name
location = var.location
sku_name = “Standard”
idle_timeout_in_minutes = 10
zones = [“1”]
}

Associate Public IP with NAT Gateway

resource “azurerm_nat_gateway_public_ip_association” “ngw_ips” {
nat_gateway_id = azurerm_nat_gateway.ngw.id
public_ip_address_id = azurerm_public_ip.ngw_pip.id

}
Associate Subnets with NAT Gateway

resource “azurerm_subnet_nat_gateway_association” “sn_nat_gw_association” {
for_each = toset(var.ngw_subnet)
subnet_id = azurerm_subnet.subnets[each.key].id
nat_gateway_id = azurerm_nat_gateway.ngw.id
}

Below is the main.tf where calling all three modules to creat resources

Calling resource_group module to create the resource groups.

module “resource_group” {
source = “…/Modules/resource_group”
env = var.env
app = var.app
location = var.location
rg_name = var.rg_name
}

Calling network module to create the VNETs/Subnets and NSGs.

module “network” {
source = “…/Modules/network”
env = var.env[0]
app = var.app
location = var.location
resource_group_name = module.resource_group.resource_group_outputs[0].name
address_space = var.address_space
subnets = var.subnets
}

Calling NAT Gateway Module to create the NAT Gateway along with Public IP.

module “nat_gateway” {
source = “…/Modules/nat_gateway”
env = var.env[0]
app = var.app
location = var.location
resource_group_name = module.resource_group.resource_group_outputs[0].name
subnet_id = module.network.subnet_id_output
ngw_subnets = var.ngw_subnets
}

Below is the variables.auto.tfvars

location = “Central US”

env = [“dev”]

app = “zabbix”

rg_name = [“network”, “app”, “database”, “storage” ]

address_space = [“10.20.40.0/24”]

subnets = {
web = {
address_prefix = “10.20.40.0/28”
},
app = {
address_prefix = “10.20.40.16/28”
},
db = {
address_prefix = “10.20.40.32/28”
}

}

ngw_subnets = [“web”, “app”]

problem I am facing is nat_gateway module is not able to get the proper subnet ID base the variable ngw_subnets.

requirement is nat_gateway fatch the subnet IDs base the subnet name mention in variable ngw_subnets and associates only those subnet IDs.

when network and nat_gateway is under one module its working perfectly. when both are seprate modules, getting error.

tried many things without luck.

Can someone please have a look and let me what I am doing wrong here and how to correct this.

Thanks.

Hi @bhardwajajayblr,

Because your subnet is created with a foreach loop, it means that your state would look like the following,

 module.network.azurerm_subnet.subnets[web],
 module.network.azurerm_subnet.subnets[app],
 module.network.azurerm_subnet.subnets[db]

I would rather output the subnet as a map in the subnet child module. See below

output "subnet_id_output_maps" {
  value = {
    for key, val in azurerm_subnet.subnets = key => val.id
  }
}

# Output example below
subnet_id_output_maps = {
  "web" = "/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/xxxx/providers/Microsoft.Network/virtualNetworks/xxxx/subnets/web"
  "app" = "/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/xxxx/providers/Microsoft.Network/virtualNetworks/xxxx/subnets/app"
  "db" = "/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/xxxx/providers/Microsoft.Network/virtualNetworks/xxxx/subnets/db"
}

However, your NAT gateway parent module would like the one below and then do a lookup in the child module on the nat subnet association.

Note; Assuming that your azurerm_subnet_nat_gateway_association resource block is inside the nat gateway child module.

module “nat_gateway” {
  source                   = “…/Modules/nat_gateway”
  env                      = var.env[0]
  app                      = var.app
  location                 = var.location
  resource_group_name      = module.resource_group.resource_group_outputs[0].name
  subnet_id                = module.network.subnet_id_output_maps #Pay attention to the part
  ngw_subnets              = var.ngw_subnets
resource “azurerm_subnet_nat_gateway_association” “sn_nat_gw_association” {
  for_each          = toset(var.ngw_subnet)
  subnet_id         = lookup(var.subnet_id, each.key, null) # This is where the trick happens.
  nat_gateway_id    = azurerm_nat_gateway.ngw.id
}