Thanks to some help, I've now managed to modulise both vnet and subnet deployment using terraform.
I've added in a few items since, but at the moment I'm working on trying to deploy a bunch of Virtual Machine Scale Sets (One Linux + One Windows x 3 regions = 6 VMSS in total).
I've tried deploying one so far, but I can't seem to set the ipconfig_subnet. I could hardcode the entire subnet in, but I want several people to use this on difference subscriptions - so that won't help me. I wanted to try import the subnet into the module for VMSS, but I seem to be hitting a brick wall.
Here's what I have so far:
```
**main.tf**
```
module "azure_vnet" {
source = "./modules/vnet"
name = var.vnet_name
location = var.location
resource_group_name = var.vnet_rg
vnet_address_space = var.vnet_address_space
subnets = var.subnets
}
module "azure_subnets" {
source = "./modules/subnets"
subnets = var.subnets
resource_group_name = var.vnet_rg
virtual_network_name = module.azure_vnet.vnet_name
depends_on = [ module.azure_vnet ]
}
module "vmss_linux" {
source = "./modules/vmss-linux"
name = format("vmss-%s-lin-uks",var.vmss_lin_uks_name)
resource_group_name = var.vmss_lin_uks_rgs
location = var.vmss_lin_uks_location
network_interface_name = var.vmss_lin_uks_network_interface_name
network_interface_primary = true
ipconfig_name = var.vmss_lin_uks_ipconfig_name
ipconfig_primary = true
ipconfig_subnet = azurerm_subnet.subnet.name == "sm_uks_vms"
depends_on = [ module.azure_vnet, module.azure_subnets ]
}
```
```
**variable.tfvars**
```
```
#Virtual Networks and Subnets for UKS
location = "uksouth"
vnet_rg = "rg-uks-compute"
vnet_address_space = ["10.0.0.0/16", "10.1.0.0/24"]
vnet_name = "vnet-uks-01"
subnets = {
uks_vms = {
name = "sm_uks_vms",
address_prefix = ["10.0.2.0/24"],
service_endpoints = ["Microsoft.Containerinstance/containerGroups",
"Microsoft.KeyVault", "Microsoft.Sql", "Microsoft.Storage",
"Microsoft.Web"]
}
uks_storage = {
name = "snet_uks_storage",
address_prefix = ["10.1.2.0/24"],
service_endpoints = ["Microsoft.AzureActiveDirectory",
"Microsoft.Sql", "Microsoft.Storage", "Microsoft.Web"]
},
uks_db = {
name = "snet_uks_db",
address_prefix =["10.1.3.0/24"],
service_endpoints = ["Microsoft.Sql", "Microsoft.Storage"]
},
uks_functions = {
name = "snet_uks_functions",
address_prefix = ["10.1.4.0/24"],
service_endpoints = ["Microsoft.AzureActiveDirectory",
"Microsoft.Storage", "Microsoft.Web"]
},
uks_projects = {
name = "snet_uks_projects",
address_prefix = ["10.1.5.0/24"],
service_endpoints = ["Microsoft.AzureActiveDirectory",
"Microsoft.Storage", "Microsoft.Web"]
},
}
vmss_lin_uks_name = "projects"
vmss_lin_uks_rgs = "rg-uks-compute"
vmss_lin_uks_location = "uksouth"
vmss_lin_uks_network_interface_name = "vmss_lin_uks_ni_01"
vmss_lin_uks_ipconfig_name = "vmss_lin_ipconfig_uks_01"
#vmss_lin_uks_ipconfig_subnet = "snet_uks_projects"
```
```
**virtual network modules**
```
```
**vnet - main.tf**
```
```
resource "azurerm_virtual_network" "vnet" {
name = var.name
location = var.location
resource_group_name = var.resource_group_name
address_space = var.vnet_address_space
dynamic "subnet" {
for_each = var.subnets
content {
name = subnet.value.name
address_prefix = subnet.value.address_prefix[0]
#security_group = subnet.value.security_group
}
}
}
output "vnet_name" {
value = azurerm_virtual_network.vnet.name
}
output "snet_name" {
value = azurerm_virtual_network.subnet.name
}
```
```
**vnet - variables.tf**
```
```
variable "name" {
description = "The name of the virtual network."
type = string
}
variable "location" {
description = "The Azure Region in which the virtual network should exist."
type = string
}
variable "resource_group_name" {
description = "The name of the resource group in which the virtual network should be created."
type = string
}
variable "vnet_address_space" {
type = list(string)
}
variable "subnets" {
description = "The configurations for the subnets to be created within this virtual network."
type = map(any)
}
```
```
**vnet - output.tf**
```
```
output "name" {
value = azurerm_virtual_network.vnet.name
}
output "subnet" {
value = azurerm_virtual_network.subnet.name
}
output "id" {
value = azurerm_virtual_network.vnet.id
}
```
```
**subnet module**
```
```
**subnet - main.tf**
```
```
resource "azurerm_subnet" "subnet" {
for_each = var.subnets
name = each.value.name
resource_group_name = var.resource_group_name
virtual_network_name = var.virtual_network_name
address_prefixes = each.value.address_prefix
service_endpoints = each.value.service_endpoints
}
output "snet_name" {
value = azurerm_subnet.subnet.name
}
```
```
**subnet - variable.tf**
```
```
variable "subnets" {
description = "The configurations for the subnets to be created."
type = map(any)
}
variable "resource_group_name" {
description = "The name of the resource group in which the subnets should be created."
type = string
}
variable "virtual_network_name" {
description = "The name of the virtual network in which the subnets should be created."
type = string
}
```
```
**subnet - output.tf**
```
output "data" {
value = tomap({for s, id in azurerm_subnet.subnet: s =>id })
}
```
**VMSS module**
```
```
**main.tf**
```
```
resource "azurerm_linux_virtual_machine_scale_set" "vmss_linux" {
name = var.name
resource_group_name = var.resource_group_name
location = var.location
sku = var.sku
instances = var.instances
admin_username = "vmss_admin"
admin_password = "Pa55w0rd9g9g" #Bad practice - look to randomise or redact?
disable_password_authentication = false
source_image_reference {
publisher = "Canonical"
offer = "UbuntuServer"
sku = "22.04-LTS"
version = "latest"
}
network_interface {
name = var.network_interface_name
primary = var.network_interface_primary
ip_configuration {
name = var.ipconfig_name
primary = var.ipconfig_primary
subnet_id = var.ipconfig_subnet
}
}
os_disk {
storage_account_type = "Standard_LRS"
caching = "ReadWrite"
}
data_disk {
storage_account_type = "Standard_LRS"
caching = "ReadWrite"
disk_size_gb = 10
lun = 10
}
}
```
```
**variable.tf**
```
```
variable "name" {}
variable "resource_group_name" {}
variable "location" {}
variable "sku" {
default = "Standard_B1s"
}
variable "instances" {
default = 3
}
variable "network_interface_name" {}
variable "network_interface_primary" {}
variable "ipconfig_name" {}
variable "ipconfig_primary" {}
variable "ipconfig_subnet" {}
```
When I try to deploy it, I get the following error message:
```
Error: Reference to undeclared resource
on modules\vnet\main.tf line 20, in output "snet_name":
20: value = azurerm_virtual_network.subnet.name
A managed resource "azurerm_virtual_network" "subnet" has not been declared in module.azure_vnet.
Error: Reference to undeclared resource
on modules\vnet\output.tf line 6, in output "subnet":
6: value = azurerm_virtual_network.subnet.name
A managed resource "azurerm_virtual_network" "subnet" has not been declared in module.azure_vnet.
```
I have tried changing the main.tf to:
```
module.azure_subnets.subnets.name - returns "azure_subnets is an object"
module.azure_vnet.subnets.name - returns "azure_vnet is an object"
azurerm_virtual_network.vnet.subnet - returns "azurerm_virtual_network is an object"
azurerm_subnet.subnet.name - returns "azurerm_subnet is an object"
```
Any help would be greatly appreciated. Thanks!
I've managed to get this working for now - message as it may be.
I've changed the main.tf where it calls on module "vmss_linux" to the following:
Where it's called on a variable, they're set in the variables.tfvar file, and currently provide the subnetID that matches the 10 segement's it's looking for. It also allows other users to re-use my TF code, which is what I'm aiming for.
If anyone has a cleaner way, feel free to comment with it and I'll give it a go later on.