For your first question, the answer is to declare in the child module an input variable that accepts the parts of the vnet object you need. I’m assuming that when you say “vnet” you mean azurerm_virtual_network
, in which case I expect that the attributes you need will be the id, the name, the location, the resource group name, and the id and name of each of the subnets, which suggests a variable declaration like this:
variable "virtual_network" {
type = object({
id = string
name = string
location = string
resource_group_name = string
subnet = set(object({
id = string
name = string
}))
})
}
The type
argument gives a type constraint, which in this case is an object type constraint, specifying that this variable expects to be given an object with at least the attributes listed in the constraint. Here I made the constraint compatible with objects produced by the azurerm_virtual_network
resource type.
You can then use the attributes from this variable to populate your firewall resource:
resource "azurerm_firewall" "example" {
for_each = {
for subnet in var.virtual_network.subnet : subnet.name => subnet
}
name = "example"
location = var.virtual_network.location
resource_group_name = var.virtual_network.resource_group_name
ip_configuration {
name = "example"
subnet_id = each.value.id
public_ip_address_id = azurerm_public_ip.example.id
}
}
The above is using some more advanced Terraform features: resource for_each
and for
expressions. When writing a reusable module it’s often necessary to use these more advanced features to map from the user’s input onto what the underlying provider actually needs, and in this case the idea is to create one firewall per subnet declared in the virtual network. (I’m not an Azure expert by any means, so I’m not sure that one firewall per subnet is a normal thing to do, but my intent here is only to show how to use these Terraform language features; please do adapt it if you have a different goal in mind!)
With all of that in place, you can then call this module and pass in the virtual network object that the root module declared:
resource "azurerm_virtual_network" "example" {
# (insert network configuration here)
}
module "nva" {
source = "./nva"
virtual_network = azurerm_virtual_network.example
}
Because the type constraint for this virtual_network
variable was designed to match the azurerm_virtual_network
resource type, we should be able to pass in the network object directly to the variable, avoiding the need to pass all of those separate arguments individually.
I think the above may have indirectly answered your second question too: .tfvars
files are only for setting variables in the root module. If you want to pass values into variables of child modules, you do that inside the module
block that called the module, as in my most recent example above.
There’s some broader background information on this sort of design in the Terraform guide Module Composition.