From 4f28830733bbe8128f19c786debeb12b1781e069 Mon Sep 17 00:00:00 2001 From: Johannes Meixner Date: Tue, 30 Aug 2022 06:50:11 +0200 Subject: [PATCH] Refactor hub & spoke into separate modules - Use the fact that modules can be called with count arguments to simplify the layout a little. Signed-off-by: Johannes Meixner Sponsored-by: Meixner GmbH --- .gitignore | 8 +- terraform/example.auto.tfvars | 2 + terraform/hub/dns.tf | 17 ++ terraform/hub/gateway.tf | 50 ++++ terraform/hub/outputs.tf | 11 + terraform/hub/rg.tf | 13 + terraform/hub/variables.tf | 54 ++++ terraform/hub/vm.tf | 39 +++ terraform/hub/vnet.tf | 95 +++++++ terraform/main.tf | 393 +++-------------------------- terraform/spoke/dns.tf | 18 ++ terraform/spoke/peering.tf | 37 +++ terraform/spoke/rg.tf | 13 + terraform/spoke/variables.tf | 61 +++++ terraform/spoke/vm.tf | 40 +++ terraform/spoke/vnet.tf | 45 ++++ terraform/terraform.example.tfvars | 2 - terraform/variables.tf | 22 +- 18 files changed, 549 insertions(+), 371 deletions(-) create mode 100644 terraform/example.auto.tfvars create mode 100644 terraform/hub/dns.tf create mode 100644 terraform/hub/gateway.tf create mode 100644 terraform/hub/outputs.tf create mode 100644 terraform/hub/rg.tf create mode 100644 terraform/hub/variables.tf create mode 100644 terraform/hub/vm.tf create mode 100644 terraform/hub/vnet.tf create mode 100644 terraform/spoke/dns.tf create mode 100644 terraform/spoke/peering.tf create mode 100644 terraform/spoke/rg.tf create mode 100644 terraform/spoke/variables.tf create mode 100644 terraform/spoke/vm.tf create mode 100644 terraform/spoke/vnet.tf delete mode 100644 terraform/terraform.example.tfvars diff --git a/.gitignore b/.gitignore index fc8da44..fdae38b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,10 @@ +# ignore lock and tf subdirs everywhere +.terraform.lock.hcl +.terraform/ + /terraform/azure.conf /terraform/out.plan -/terraform/.terraform.lock.hcl -/terraform/.terraform/ /terraform/terraform.tfvars .talismanrc +.*.sw? + diff --git a/terraform/example.auto.tfvars b/terraform/example.auto.tfvars new file mode 100644 index 0000000..f635ce7 --- /dev/null +++ b/terraform/example.auto.tfvars @@ -0,0 +1,2 @@ +vm_user_ssh = "ssh-rsa ....." +allowed_ip_address = "1.2.3.4" diff --git a/terraform/hub/dns.tf b/terraform/hub/dns.tf new file mode 100644 index 0000000..06615a9 --- /dev/null +++ b/terraform/hub/dns.tf @@ -0,0 +1,17 @@ + +resource "azurerm_private_dns_zone_virtual_network_link" "hub_vnet_dns" { + name = "hub-vnet-dns" + resource_group_name = azurerm_resource_group.hub_rg.name + private_dns_zone_name = var.dns_zone_name + virtual_network_id = azurerm_virtual_network.hub_vnet.id +} + +resource "azurerm_private_dns_a_record" "hub-vm-dns" { + name = "hub-vm" + zone_name = var.dns_zone_name + resource_group_name = azurerm_resource_group.hub_rg.name + ttl = 300 + records = [azurerm_linux_virtual_machine.hub-vm.private_ip_address] +} + + diff --git a/terraform/hub/gateway.tf b/terraform/hub/gateway.tf new file mode 100644 index 0000000..23ea8ab --- /dev/null +++ b/terraform/hub/gateway.tf @@ -0,0 +1,50 @@ +## Please be aware that provisioning a Virtual Network Gateway takes a long time (between 30 minutes and 1 hour) +# +#resource "azurerm_virtual_network_gateway" "hub-vnet-gateway" { +# name = "hub-vpn-gateway1" +# location = azurerm_resource_group.hub_rg.location +# resource_group_name = azurerm_resource_group.hub_rg.name +# +# type = "Vpn" +# vpn_type = "RouteBased" +# +# active_active = false +# enable_bgp = false +# sku = "VpnGw1" +# +# ip_configuration { +# name = "vnetGatewayConfig" +# public_ip_address_id = azurerm_public_ip.hub_pip.id +# private_ip_address_allocation = "Dynamic" +# subnet_id = azurerm_subnet.hub-vnet-subnet.id +# } +# depends_on = [azurerm_public_ip.hub_pip] +#} +# +#resource "azurerm_virtual_network_gateway_connection" "hub-onprem-conn" { +# name = "hub-onprem-conn" +# location = azurerm_resource_group.hub_rg.location +# resource_group_name = azurerm_resource_group.hub_rg.name +# +# type = "Vnet2Vnet" +# routing_weight = 1 +# +# virtual_network_gateway_id = azurerm_virtual_network_gateway.hub-vnet-gateway.id +# peer_virtual_network_gateway_id = azurerm_virtual_network_gateway.onprem-vpn-gateway.id +# +# shared_key = local.shared-key +#} +# +#resource "azurerm_virtual_network_gateway_connection" "onprem-hub-conn" { +# name = "onprem-hub-conn" +# location = azurerm_resource_group.onprem-vnet-rg.location +# resource_group_name = azurerm_resource_group.onprem-vnet-rg.name +# type = "Vnet2Vnet" +# routing_weight = 1 +# virtual_network_gateway_id = azurerm_virtual_network_gateway.onprem-vpn-gateway.id +# peer_virtual_network_gateway_id = azurerm_virtual_network_gateway.hub-vnet-gateway.id +# +# shared_key = local.shared-key +#} + + diff --git a/terraform/hub/outputs.tf b/terraform/hub/outputs.tf new file mode 100644 index 0000000..af03250 --- /dev/null +++ b/terraform/hub/outputs.tf @@ -0,0 +1,11 @@ +output "rg_name" { + value = azurerm_resource_group.hub_rg.name + } +# hub_vnet_id = module.hub.vnet_id + +output "vnet_id" { + value = azurerm_virtual_network.hub_vnet.id +} +output "vnet_name" { + value = azurerm_virtual_network.hub_vnet.name +} diff --git a/terraform/hub/rg.tf b/terraform/hub/rg.tf new file mode 100644 index 0000000..8fd2933 --- /dev/null +++ b/terraform/hub/rg.tf @@ -0,0 +1,13 @@ +resource "azurerm_resource_group" "hub_rg" { + name = join("-", [local.full_rg_name, "hub"]) + location = var.location + + tags = { + Environment = terraform.workspace + Owner = var.tag_owner + ApplicationName = var.tag_application_name + CostCenter = var.tag_costcenter + DR = var.tag_dr + } +} + diff --git a/terraform/hub/variables.tf b/terraform/hub/variables.tf new file mode 100644 index 0000000..14cf66a --- /dev/null +++ b/terraform/hub/variables.tf @@ -0,0 +1,54 @@ +############################################################################# +# GENERAL VARIABLES +############################################################################# + +variable "location" { + type = string + default = "West Europe" +} + +variable "resource_group_name" { + type = string + default = "rg-vnetdemo-kstjj-001" +} +locals { + full_rg_name = join("-", [terraform.workspace, var.resource_group_name]) +} + +############################################################################# +# SPECIFIC VARIABLES +############################################################################# + +variable "spoke_count" { + default = 2 +} + +variable "dns_zone_name" {} + +variable "vm_user_ssh" {} + +variable "allowed_ip_address" {} + +############################################################################# +# TAGS +# +# tag_environment = terraform.workspace +# +############################################################################# + +variable "tag_owner" { + default = "jan.jambor@xwr.ch" +} + +variable "tag_application_name" { + default = "vnetdemo" +} + +variable "tag_costcenter" { + default = "jj" +} +variable "tag_dr" { + default = "essential" +} + + diff --git a/terraform/hub/vm.tf b/terraform/hub/vm.tf new file mode 100644 index 0000000..335b9b5 --- /dev/null +++ b/terraform/hub/vm.tf @@ -0,0 +1,39 @@ +resource "azurerm_linux_virtual_machine" "hub-vm" { + name = "hub-vm" + location = azurerm_resource_group.hub_rg.location + resource_group_name = azurerm_resource_group.hub_rg.name + network_interface_ids = [azurerm_network_interface.hub-nic.id] + size = "Standard_B1ls" # smallest you can get, linux only: https://docs.microsoft.com/en-us/azure/virtual-machines/sizes-b-series-burstable + + os_disk { + name = "myOsDisk" + caching = "ReadWrite" + storage_account_type = "Standard_LRS" + } + + source_image_reference { + publisher = "Canonical" + offer = "UbuntuServer" + sku = "18.04-LTS" + version = "latest" + } + + computer_name = "hub-vm" + admin_username = "azureuser" + disable_password_authentication = true + + admin_ssh_key { + username = "azureuser" + public_key = var.vm_user_ssh + } + + tags = { + Environment = terraform.workspace + Owner = var.tag_owner + ApplicationName = var.tag_application_name + CostCenter = var.tag_costcenter + DR = var.tag_dr + } + +} + diff --git a/terraform/hub/vnet.tf b/terraform/hub/vnet.tf new file mode 100644 index 0000000..b10cf72 --- /dev/null +++ b/terraform/hub/vnet.tf @@ -0,0 +1,95 @@ +resource "azurerm_public_ip" "hub_pip" { + name = "hub-pip" + location = azurerm_resource_group.hub_rg.location + resource_group_name = azurerm_resource_group.hub_rg.name + allocation_method = "Dynamic" + + tags = { + Environment = terraform.workspace + Owner = var.tag_owner + ApplicationName = var.tag_application_name + CostCenter = var.tag_costcenter + DR = var.tag_dr + } +} + + +resource "azurerm_network_security_group" "hub_nsg" { + name = "hub-nsg" + location = azurerm_resource_group.hub_rg.location + resource_group_name = azurerm_resource_group.hub_rg.name + + security_rule { + name = "ssh" + priority = 100 + direction = "Inbound" + access = "Allow" + protocol = "Tcp" + source_port_range = "*" + destination_port_range = "22" + source_address_prefix = var.allowed_ip_address + destination_address_prefix = "*" + } + + tags = { + Environment = terraform.workspace + Owner = var.tag_owner + ApplicationName = var.tag_application_name + CostCenter = var.tag_costcenter + DR = var.tag_dr + } +} + + +resource "azurerm_virtual_network" "hub_vnet" { + name = join("-", [local.full_rg_name, "hub"]) + location = azurerm_resource_group.hub_rg.location + resource_group_name = azurerm_resource_group.hub_rg.name + address_space = ["10.0.0.0/16"] + + tags = { + Environment = terraform.workspace + Owner = var.tag_owner + ApplicationName = var.tag_application_name + CostCenter = var.tag_costcenter + DR = var.tag_dr + } +} + + +resource "azurerm_subnet" "hub_vnet_subnet" { + name = join("-", [local.full_rg_name, "hub", "subnet"]) + resource_group_name = azurerm_resource_group.hub_rg.name + virtual_network_name = azurerm_virtual_network.hub_vnet.name + address_prefixes = ["10.0.1.0/24"] +} + +resource "azurerm_subnet_network_security_group_association" "subnet1internal" { + subnet_id = azurerm_subnet.hub_vnet_subnet.id + network_security_group_id = azurerm_network_security_group.hub_nsg.id + depends_on = [azurerm_subnet.hub_vnet_subnet, azurerm_network_security_group.hub_nsg] +} + +resource "azurerm_network_interface" "hub-nic" { + name = join("-", [local.full_rg_name, "hub", "nic"]) + location = azurerm_resource_group.hub_rg.location + resource_group_name = azurerm_resource_group.hub_rg.name + enable_ip_forwarding = true + + ip_configuration { + name = "hub-ip" + subnet_id = azurerm_subnet.hub_vnet_subnet.id + private_ip_address_allocation = "Dynamic" + public_ip_address_id = azurerm_public_ip.hub_pip.id + } + + tags = { + Environment = terraform.workspace + Owner = var.tag_owner + ApplicationName = var.tag_application_name + CostCenter = var.tag_costcenter + DR = var.tag_dr + } +} + + diff --git a/terraform/main.tf b/terraform/main.tf index f1c2261..375b3b9 100644 --- a/terraform/main.tf +++ b/terraform/main.tf @@ -1,381 +1,62 @@ ############################################################################# -# RESOURCES Hub Zone +# RESOURCES Global Zone ############################################################################# -resource "azurerm_resource_group" "hub-rg" { - name = join("-", [local.full_rg_name, "hub"]) - location = var.location - - tags = { - Environment = terraform.workspace - Owner = var.tag_owner - ApplicationName = var.tag_application_name - CostCenter = var.tag_costcenter - DR = var.tag_dr - } -} - -resource "azurerm_public_ip" "hub-pip" { - name = "hub-pip" - location = azurerm_resource_group.hub-rg.location - resource_group_name = azurerm_resource_group.hub-rg.name - allocation_method = "Dynamic" - - tags = { - Environment = terraform.workspace - Owner = var.tag_owner - ApplicationName = var.tag_application_name - CostCenter = var.tag_costcenter - DR = var.tag_dr - } -} - -resource "azurerm_network_security_group" "hub-nsg" { - name = "hub-nsg" - location = azurerm_resource_group.hub-rg.location - resource_group_name = azurerm_resource_group.hub-rg.name - - security_rule { - name = "ssh" - priority = 100 - direction = "Inbound" - access = "Allow" - protocol = "Tcp" - source_port_range = "*" - destination_port_range = "22" - source_address_prefix = var.allowed_ip_address - destination_address_prefix = "*" - } - - tags = { - Environment = terraform.workspace - Owner = var.tag_owner - ApplicationName = var.tag_application_name - CostCenter = var.tag_costcenter - DR = var.tag_dr - } -} - -resource "azurerm_private_dns_zone" "dns-zone" { +resource "azurerm_private_dns_zone" "dns_zone" { name = "vnetdemo.loc" - resource_group_name = azurerm_resource_group.hub-rg.name - - tags = { - Environment = terraform.workspace - Owner = var.tag_owner - ApplicationName = var.tag_application_name - CostCenter = var.tag_costcenter - DR = var.tag_dr - } -} - -## Please be aware that provisioning a Virtual Network Gateway takes a long time (between 30 minutes and 1 hour) -# -#resource "azurerm_virtual_network_gateway" "hub-vnet-gateway" { -# name = "hub-vpn-gateway1" -# location = azurerm_resource_group.hub-rg.location -# resource_group_name = azurerm_resource_group.hub-rg.name -# -# type = "Vpn" -# vpn_type = "RouteBased" -# -# active_active = false -# enable_bgp = false -# sku = "VpnGw1" -# -# ip_configuration { -# name = "vnetGatewayConfig" -# public_ip_address_id = azurerm_public_ip.hub-pip.id -# private_ip_address_allocation = "Dynamic" -# subnet_id = azurerm_subnet.hub-vnet-subnet.id -# } -# depends_on = [azurerm_public_ip.hub-pip] -#} -# -#resource "azurerm_virtual_network_gateway_connection" "hub-onprem-conn" { -# name = "hub-onprem-conn" -# location = azurerm_resource_group.hub-rg.location -# resource_group_name = azurerm_resource_group.hub-rg.name -# -# type = "Vnet2Vnet" -# routing_weight = 1 -# -# virtual_network_gateway_id = azurerm_virtual_network_gateway.hub-vnet-gateway.id -# peer_virtual_network_gateway_id = azurerm_virtual_network_gateway.onprem-vpn-gateway.id -# -# shared_key = local.shared-key -#} -# -#resource "azurerm_virtual_network_gateway_connection" "onprem-hub-conn" { -# name = "onprem-hub-conn" -# location = azurerm_resource_group.onprem-vnet-rg.location -# resource_group_name = azurerm_resource_group.onprem-vnet-rg.name -# type = "Vnet2Vnet" -# routing_weight = 1 -# virtual_network_gateway_id = azurerm_virtual_network_gateway.onprem-vpn-gateway.id -# peer_virtual_network_gateway_id = azurerm_virtual_network_gateway.hub-vnet-gateway.id -# -# shared_key = local.shared-key -#} - -resource "azurerm_virtual_network" "hub-vnet" { - name = join("-", [local.full_rg_name, "hub"]) - location = azurerm_resource_group.hub-rg.location - resource_group_name = azurerm_resource_group.hub-rg.name - address_space = ["10.0.0.0/16"] - - tags = { - Environment = terraform.workspace - Owner = var.tag_owner - ApplicationName = var.tag_application_name - CostCenter = var.tag_costcenter - DR = var.tag_dr - } -} - -resource "azurerm_private_dns_zone_virtual_network_link" "hub-vnet-dns" { - name = "hub-vnet-dns" - resource_group_name = azurerm_resource_group.hub-rg.name - private_dns_zone_name = azurerm_private_dns_zone.dns-zone.name - virtual_network_id = azurerm_virtual_network.hub-vnet.id -} - -resource "azurerm_subnet" "hub-vnet-subnet" { - name = join("-", [local.full_rg_name, "hub", "subnet"]) - resource_group_name = azurerm_resource_group.hub-rg.name - virtual_network_name = azurerm_virtual_network.hub-vnet.name - address_prefixes = ["10.0.1.0/24"] -} - -resource "azurerm_subnet_network_security_group_association" "subnet1internal" { - subnet_id = azurerm_subnet.hub-vnet-subnet.id - network_security_group_id = azurerm_network_security_group.hub-nsg.id - depends_on = [azurerm_subnet.hub-vnet-subnet, azurerm_network_security_group.hub-nsg] -} - -resource "azurerm_network_interface" "hub-nic" { - name = join("-", [local.full_rg_name, "hub", "nic"]) - location = azurerm_resource_group.hub-rg.location - resource_group_name = azurerm_resource_group.hub-rg.name - enable_ip_forwarding = true - - ip_configuration { - name = "hub-ip" - subnet_id = azurerm_subnet.hub-vnet-subnet.id - private_ip_address_allocation = "Dynamic" - public_ip_address_id = azurerm_public_ip.hub-pip.id - } + resource_group_name = module.hub.rg_name tags = { - Environment = terraform.workspace - Owner = var.tag_owner + Environment = terraform.workspace + Owner = var.tag_owner ApplicationName = var.tag_application_name - CostCenter = var.tag_costcenter - DR = var.tag_dr + CostCenter = var.tag_costcenter + DR = var.tag_dr } } -resource "azurerm_linux_virtual_machine" "hub-vm" { - name = "hub-vm" - location = azurerm_resource_group.hub-rg.location - resource_group_name = azurerm_resource_group.hub-rg.name - network_interface_ids = [azurerm_network_interface.hub-nic.id] - size = "Standard_B1ls" # smallest you can get, linux only: https://docs.microsoft.com/en-us/azure/virtual-machines/sizes-b-series-burstable - - os_disk { - name = "myOsDisk" - caching = "ReadWrite" - storage_account_type = "Standard_LRS" - } - - source_image_reference { - publisher = "Canonical" - offer = "UbuntuServer" - sku = "18.04-LTS" - version = "latest" - } +############################################################################# +# RESOURCES Hub Zone +############################################################################# - computer_name = "hub-vm" - admin_username = "azureuser" - disable_password_authentication = true +module "hub" { + source = "./hub" - admin_ssh_key { - username = "azureuser" - public_key = var.vm_user_ssh - } + location = var.location + resource_group_name = var.resource_group_name + vm_user_ssh = var.vm_user_ssh + allowed_ip_address = var.allowed_ip_address - tags = { - Environment = terraform.workspace - Owner = var.tag_owner - ApplicationName = var.tag_application_name - CostCenter = var.tag_costcenter - DR = var.tag_dr - } - -} + dns_zone_name = azurerm_private_dns_zone.dns_zone.name -resource "azurerm_private_dns_a_record" "hub-vm-dns" { - name = "hub-vm" - zone_name = azurerm_private_dns_zone.dns-zone.name - resource_group_name = azurerm_resource_group.hub-rg.name - ttl = 300 - records = [azurerm_linux_virtual_machine.hub-vm.private_ip_address] + tag_owner = var.tag_owner + tag_application_name = var.tag_application_name + tag_costcenter = var.tag_costcenter + tag_dr = var.tag_dr } ############################################################################# # RESOURCES Spoke Zones ############################################################################# -resource "azurerm_resource_group" "spoke-rgs" { - count = var.spoke_count - name = join("-", [local.full_rg_name, "spoke", count.index+1]) - location = var.location - - tags = { - Environment = terraform.workspace - Owner = var.tag_owner - ApplicationName = var.tag_application_name - CostCenter = var.tag_costcenter - DR = var.tag_dr - } -} - -resource "azurerm_virtual_network" "spoke-vnets" { - count = var.spoke_count - name = join("-", [local.full_rg_name, "spoke", count.index+1]) - location = azurerm_resource_group.spoke-rgs[count.index].location - resource_group_name = azurerm_resource_group.spoke-rgs[count.index].name - address_space = ["10.${count.index+1}.0.0/16"] +module "spoke" { + source = "./spoke" + count = var.spoke_count - tags = { - Environment = terraform.workspace - Owner = var.tag_owner - ApplicationName = var.tag_application_name - CostCenter = var.tag_costcenter - DR = var.tag_dr - } -} + location = var.location + resource_group_name = var.resource_group_name + vm_user_ssh = var.vm_user_ssh + allowed_ip_address = var.allowed_ip_address -resource "azurerm_private_dns_zone_virtual_network_link" "spoke-vnet-dns" { - count = var.spoke_count - name = join("-", ["spoke-vnet-dns", count.index+1]) - resource_group_name = azurerm_resource_group.hub-rg.name - private_dns_zone_name = azurerm_private_dns_zone.dns-zone.name - virtual_network_id = azurerm_virtual_network.spoke-vnets[count.index].id -} + spoke_index = count.index + 1 + hub_rg_name = module.hub.rg_name + hub_vnet_id = module.hub.vnet_id + hub_vnet_name = module.hub.vnet_name + dns_zone_name = azurerm_private_dns_zone.dns_zone.name -resource "azurerm_subnet" "spoke-vnets-subnet" { - count = var.spoke_count - name = join("-", [local.full_rg_name, "spoke", count.index+1,"subnet"]) - resource_group_name = azurerm_resource_group.spoke-rgs[count.index].name - virtual_network_name = azurerm_virtual_network.spoke-vnets[count.index].name - address_prefixes = ["10.${count.index+1}.1.0/24"] + tag_owner = var.tag_owner + tag_application_name = var.tag_application_name + tag_costcenter = var.tag_costcenter + tag_dr = var.tag_dr } -resource "azurerm_network_interface" "spoke-nics" { - count = var.spoke_count - name = join("-", [local.full_rg_name, "spoke", count.index+1, "nic"]) - location = azurerm_resource_group.spoke-rgs[count.index].location - resource_group_name = azurerm_resource_group.spoke-rgs[count.index].name - enable_ip_forwarding = true - - ip_configuration { - name = join("-", ["spoke", count.index+1, "ip"]) - subnet_id = azurerm_subnet.spoke-vnets-subnet[count.index].id - private_ip_address_allocation = "Dynamic" - } - - tags = { - Environment = terraform.workspace - Owner = var.tag_owner - ApplicationName = var.tag_application_name - CostCenter = var.tag_costcenter - DR = var.tag_dr - } -} - -resource "azurerm_linux_virtual_machine" "spoke-vms" { - count = var.spoke_count - name = join("-", [local.full_rg_name, "spoke", count.index+1, "vm"]) - location = azurerm_resource_group.spoke-rgs[count.index].location - resource_group_name = azurerm_resource_group.spoke-rgs[count.index].name - network_interface_ids = [azurerm_network_interface.spoke-nics[count.index].id] - size = "Standard_B1ls" # smallest you can get, linux only: https://docs.microsoft.com/en-us/azure/virtual-machines/sizes-b-series-burstable - - os_disk { - name = "myOsDisk" - caching = "ReadWrite" - storage_account_type = "Standard_LRS" - } - - source_image_reference { - publisher = "Canonical" - offer = "UbuntuServer" - sku = "18.04-LTS" - version = "latest" - } - - computer_name = join("-", ["spoke-vm", count.index+1]) - admin_username = "azureuser" - disable_password_authentication = true - - admin_ssh_key { - username = "azureuser" - public_key = var.vm_user_ssh - } - - tags = { - Environment = terraform.workspace - Owner = var.tag_owner - ApplicationName = var.tag_application_name - CostCenter = var.tag_costcenter - DR = var.tag_dr - } - -} - -resource "azurerm_private_dns_a_record" "spoke-vms-dns" { - count = var.spoke_count - name = join("-", ["spoke", count.index+1, "vm"]) - zone_name = azurerm_private_dns_zone.dns-zone.name - resource_group_name = azurerm_resource_group.hub-rg.name - ttl = 300 - records = [azurerm_linux_virtual_machine.spoke-vms[count.index].private_ip_address] -} - -############################################################################# -# Peerings (always hub to spoke, never spoke to spoke in this example) -# If one spoke needs to communicate to another one, it must go through hub -############################################################################# - -resource "azurerm_virtual_network_peering" "hub-spoke-peers" { - count = var.spoke_count - name = join("-", [local.full_rg_name, "hub", "spoke-peer", count.index+1]) - resource_group_name = azurerm_resource_group.hub-rg.name - virtual_network_name = azurerm_virtual_network.hub-vnet.name - remote_virtual_network_id = azurerm_virtual_network.spoke-vnets[count.index].id - - allow_virtual_network_access = true - allow_forwarded_traffic = true - #allow_gateway_transit = false - #use_remote_gateways = true - # removed the gateway for demo - #depends_on = [azurerm_virtual_network.spoke-vnets[count.index+1], azurerm_virtual_network.hub-vnet , azurerm_virtual_network_gateway.hub-vnet-gateway] - depends_on = [azurerm_virtual_network.hub-vnet] # we cannot depend on the spoke vnets here as we don't know how many are created and calculations / expressions like "azurerm_virtual_network.spoke-vnets[count.index+1]" are not allowed -} - -resource "azurerm_virtual_network_peering" "spoke-hub-peers" { - count = var.spoke_count - name = join("-", [local.full_rg_name, "spoke", count.index+1,"hub-peer"]) - resource_group_name = azurerm_resource_group.spoke-rgs[count.index].name - virtual_network_name = azurerm_virtual_network.spoke-vnets[count.index].name - remote_virtual_network_id = azurerm_virtual_network.hub-vnet.id - - allow_virtual_network_access = true - allow_forwarded_traffic = true - #allow_gateway_transit = false - #use_remote_gateways = true - # removed the gateway for demo - #depends_on = [azurerm_virtual_network.spoke-vnets[count.index+1], azurerm_virtual_network.hub-vnet , azurerm_virtual_network_gateway.hub-vnet-gateway] - depends_on = [azurerm_virtual_network.hub-vnet] # we cannot depend on the spoke vnets here as we don't know how many are created and calculations / expressions like "azurerm_virtual_network.spoke-vnets[count.index+1]" are not allowed -} diff --git a/terraform/spoke/dns.tf b/terraform/spoke/dns.tf new file mode 100644 index 0000000..e4cf58e --- /dev/null +++ b/terraform/spoke/dns.tf @@ -0,0 +1,18 @@ +resource "azurerm_private_dns_zone_virtual_network_link" "spoke-vnet-dns" { + count = var.spoke_count + name = join("-", ["spoke-vnet-dns", var.spoke_index]) + resource_group_name = var.hub_rg_name + private_dns_zone_name = var.dns_zone_name + virtual_network_id = azurerm_virtual_network.spoke_vnet.id +} + +resource "azurerm_private_dns_a_record" "spoke-vms-dns" { + count = var.spoke_count + name = join("-", ["spoke", var.spoke_index, "vm"]) + zone_name = var.dns_zone_name + resource_group_name = var.hub_rg_name + ttl = 300 + records = [azurerm_linux_virtual_machine.spoke-vms[count.index].private_ip_address] +} + + diff --git a/terraform/spoke/peering.tf b/terraform/spoke/peering.tf new file mode 100644 index 0000000..ba0e524 --- /dev/null +++ b/terraform/spoke/peering.tf @@ -0,0 +1,37 @@ +############################################################################# +# Peerings (always hub to spoke, never spoke to spoke in this example) +# If one spoke needs to communicate to another one, it must go through hub +############################################################################# + +resource "azurerm_virtual_network_peering" "hub-spoke-peers" { + name = join("-", [local.full_rg_name, "hub", "spoke-peer", var.spoke_index]) + resource_group_name = var.hub_rg_name + virtual_network_name = var.hub_vnet_name + remote_virtual_network_id = azurerm_virtual_network.spoke_vnet.id + + allow_virtual_network_access = true + allow_forwarded_traffic = true + #allow_gateway_transit = false + #use_remote_gateways = true + # removed the gateway for demo + #depends_on = [azurerm_virtual_network.spoke_vnet, azurerm_virtual_network.hub-vnet , azurerm_virtual_network_gateway.hub-vnet-gateway] + #depends_on = [azurerm_virtual_network.hub-vnet] # we cannot depend on the spoke vnets here as we don't know how many are created and calculations / expressions like "azurerm_virtual_network.spoke-vnets[count.index+1]" are not allowed +} + +resource "azurerm_virtual_network_peering" "spoke-hub-peers" { + count = var.spoke_count + name = join("-", [local.full_rg_name, "spoke", var.spoke_index, "hub-peer"]) + resource_group_name = azurerm_resource_group.spoke_rg.name + virtual_network_name = azurerm_virtual_network.spoke_vnet.name + remote_virtual_network_id = var.hub_vnet_id + + allow_virtual_network_access = true + allow_forwarded_traffic = true + #allow_gateway_transit = false + #use_remote_gateways = true + # removed the gateway for demo + #depends_on = [azurerm_virtual_network.spoke-vnets[count.index+1], azurerm_virtual_network.hub-vnet , azurerm_virtual_network_gateway.hub-vnet-gateway] + #depends_on = [azurerm_virtual_network.hub-vnet] # we cannot depend on the spoke vnets here as we don't know how many are created and calculations / expressions like "azurerm_virtual_network.spoke-vnets[count.index+1]" are not allowed +} + + diff --git a/terraform/spoke/rg.tf b/terraform/spoke/rg.tf new file mode 100644 index 0000000..624524f --- /dev/null +++ b/terraform/spoke/rg.tf @@ -0,0 +1,13 @@ +resource "azurerm_resource_group" "spoke_rg" { + name = join("-", [local.full_rg_name, "spoke", var.spoke_index]) + location = var.location + + tags = { + Environment = terraform.workspace + Owner = var.tag_owner + ApplicationName = var.tag_application_name + CostCenter = var.tag_costcenter + DR = var.tag_dr + } +} + diff --git a/terraform/spoke/variables.tf b/terraform/spoke/variables.tf new file mode 100644 index 0000000..4f197aa --- /dev/null +++ b/terraform/spoke/variables.tf @@ -0,0 +1,61 @@ +############################################################################# +# GENERAL VARIABLES +############################################################################# + +variable "location" { + type = string + default = "West Europe" +} + +variable "resource_group_name" { + type = string + default = "rg-vnetdemo-kstjj-001" +} +locals { + full_rg_name = join("-", [terraform.workspace, var.resource_group_name]) +} + +############################################################################# +# SPECIFIC VARIABLES +############################################################################# + +variable "spoke_count" { + default = 2 +} + +variable "dns_zone_name" {} + +variable "vm_user_ssh" {} + +variable "spoke_index" {} + + +variable "hub_vnet_id" {} +variable "hub_vnet_name" {} + +variable "hub_rg_name" {} + +variable "allowed_ip_address" {} + +############################################################################# +# TAGS +# +# tag_environment = terraform.workspace +# +############################################################################# + +variable "tag_owner" { + default = "jan.jambor@xwr.ch" +} + +variable "tag_application_name" { + default = "vnetdemo" +} + +variable "tag_costcenter" { + default = "jj" +} +variable "tag_dr" { + default = "essential" +} + diff --git a/terraform/spoke/vm.tf b/terraform/spoke/vm.tf new file mode 100644 index 0000000..f8d71c2 --- /dev/null +++ b/terraform/spoke/vm.tf @@ -0,0 +1,40 @@ +resource "azurerm_linux_virtual_machine" "spoke-vms" { + count = var.spoke_count + name = join("-", [local.full_rg_name, "spoke", var.spoke_index, "vm"]) + location = azurerm_resource_group.spoke_rg.location + resource_group_name = azurerm_resource_group.spoke_rg.name + network_interface_ids = [azurerm_network_interface.spoke_nic.id] + size = "Standard_B1ls" # smallest you can get, linux only: https://docs.microsoft.com/en-us/azure/virtual-machines/sizes-b-series-burstable + + os_disk { + name = "myOsDisk" + caching = "ReadWrite" + storage_account_type = "Standard_LRS" + } + + source_image_reference { + publisher = "Canonical" + offer = "UbuntuServer" + sku = "18.04-LTS" + version = "latest" + } + + computer_name = join("-", ["spoke-vm", count.index + 1]) + admin_username = "azureuser" + disable_password_authentication = true + + admin_ssh_key { + username = "azureuser" + public_key = var.vm_user_ssh + } + + tags = { + Environment = terraform.workspace + Owner = var.tag_owner + ApplicationName = var.tag_application_name + CostCenter = var.tag_costcenter + DR = var.tag_dr + } + +} + diff --git a/terraform/spoke/vnet.tf b/terraform/spoke/vnet.tf new file mode 100644 index 0000000..2441835 --- /dev/null +++ b/terraform/spoke/vnet.tf @@ -0,0 +1,45 @@ +resource "azurerm_virtual_network" "spoke_vnet" { + name = join("-", [local.full_rg_name, "spoke", var.spoke_index]) + location = azurerm_resource_group.spoke_rg.location + resource_group_name = azurerm_resource_group.spoke_rg.name + address_space = ["10.${var.spoke_index}.0.0/16"] + + tags = { + Environment = terraform.workspace + Owner = var.tag_owner + ApplicationName = var.tag_application_name + CostCenter = var.tag_costcenter + DR = var.tag_dr + } +} + + +resource "azurerm_subnet" "spoke_vnet_subnet" { + name = join("-", [local.full_rg_name, "spoke", var.spoke_index, "subnet"]) + resource_group_name = azurerm_resource_group.spoke_rg.name + virtual_network_name = azurerm_virtual_network.spoke_vnet.name + address_prefixes = ["10.${var.spoke_index}.1.0/24"] +} + +resource "azurerm_network_interface" "spoke_nic" { + name = join("-", [local.full_rg_name, "spoke", var.spoke_index, "nic"]) + location = azurerm_resource_group.spoke_rg.location + resource_group_name = azurerm_resource_group.spoke_rg.name + enable_ip_forwarding = true + + ip_configuration { + name = join("-", ["spoke", var.spoke_index, "ip"]) + subnet_id = azurerm_subnet.spoke_vnet_subnet.id + private_ip_address_allocation = "Dynamic" + } + + tags = { + Environment = terraform.workspace + Owner = var.tag_owner + ApplicationName = var.tag_application_name + CostCenter = var.tag_costcenter + DR = var.tag_dr + } +} + + diff --git a/terraform/terraform.example.tfvars b/terraform/terraform.example.tfvars deleted file mode 100644 index f197b9f..0000000 --- a/terraform/terraform.example.tfvars +++ /dev/null @@ -1,2 +0,0 @@ -vm_user_ssh="ssh-rsa ....." -allowed_ip_address="1.2.3.4" diff --git a/terraform/variables.tf b/terraform/variables.tf index 1eed0ff..7782584 100644 --- a/terraform/variables.tf +++ b/terraform/variables.tf @@ -2,17 +2,17 @@ # GENERAL VARIABLES ############################################################################# -variable location { +variable "location" { type = string default = "West Europe" } -variable resource_group_name { - type = string +variable "resource_group_name" { + type = string default = "rg-vnetdemo-kstjj-001" } locals { - full_rg_name = join("-", [terraform.workspace, var.resource_group_name]) + full_rg_name = join("-", [terraform.workspace, var.resource_group_name]) } ############################################################################# @@ -20,12 +20,12 @@ locals { ############################################################################# variable "spoke_count" { - default = 2 + default = 2 } -variable vm_user_ssh {} +variable "vm_user_ssh" {} -variable allowed_ip_address {} +variable "allowed_ip_address" {} ############################################################################# # TAGS @@ -35,16 +35,16 @@ variable allowed_ip_address {} ############################################################################# variable "tag_owner" { - default = "jan.jambor@xwr.ch" + default = "jan.jambor@xwr.ch" } variable "tag_application_name" { - default = "vnetdemo" + default = "vnetdemo" } variable "tag_costcenter" { - default = "jj" + default = "jj" } variable "tag_dr" { - default = "essential" + default = "essential" }