# Configure the Azure Provider terraform { required_providers { azurerm = { source = "hashicorp/azurerm" version = "~> 3.0" } } } provider "azurerm" { features {} } data "azurerm_client_config" "current" {} # ----------------------------------------------------------------------------- # Naming Conventions # ----------------------------------------------------------------------------- locals { vm_names = ["Quetzalcoatl", "Huitzilopochtli", "Pachamama", "Viracocha", "Inti"] network_names = ["Aztec", "Inca", "Maya", "Mississippian", "Anasazi"] resource_groups = { eastus2 = "muscogee-rg" westus2 = "sioux-rg" centralus = "cherokee-rg" } location_default = "eastus2" location_quetzalcoatl = "westus2" location_centralus = "centralus" admin_username = "lenape" key_vault_name_prefix = "kv-secure-creds" storage_account_name = "povertypoint" container_name = "tfstate" } # ----------------------------------------------------------------------------- # 1. Resource Groups # ----------------------------------------------------------------------------- resource "azurerm_resource_group" "rg" { for_each = local.resource_groups name = each.value location = local.location_default } # ----------------------------------------------------------------------------- # 2. Azure Key Vault for Secure Password Management # ----------------------------------------------------------------------------- resource "azurerm_key_vault" "kv" { name = "${local.key_vault_name_prefix}-${random_string.kv_suffix.result}" location = azurerm_resource_group.rg["eastus2"].location resource_group_name = azurerm_resource_group.rg["eastus2"].name tenant_id = data.azurerm_client_config.current.tenant_id sku_name = "standard" access_policy { tenant_id = data.azurerm_client_config.current.tenant_id object_id = data.azurerm_client_config.current.object_id key_permissions = ["Get"] secret_permissions = ["Get", "Set"] storage_permissions = ["Get"] } } resource "random_string" "kv_suffix" { length = 8 lower = true numeric = true special = false } resource "random_password" "admin_password" { length = 20 special = true override_special = "!#$%&*()-_=+[]{}<>:?" } resource "azurerm_key_vault_secret" "admin_password_secret" { name = "linux-admin-password" value = random_password.admin_password.result key_vault_id = azurerm_key_vault.kv.id } # ----------------------------------------------------------------------------- # 3. Virtual Networks, Subnets, and Network Security Groups # ----------------------------------------------------------------------------- resource "azurerm_virtual_network" "vnet" { for_each = toset([local.location_default, local.location_quetzalcoatl, local.location_centralus]) name = "${local.network_names[0]}-vnet-${each.key}" location = each.key resource_group_name = azurerm_resource_group.rg[each.key].name address_space = ["10.0.0.0/16"] } resource "azurerm_subnet" "subnet" { for_each = azurerm_virtual_network.vnet name = "default" resource_group_name = azurerm_resource_group.rg[each.key].name virtual_network_name = each.value.name address_prefixes = ["10.0.1.0/24"] } resource "azurerm_network_security_group" "nsg" { for_each = azurerm_virtual_network.vnet name = "${local.network_names[0]}-nsg-${each.key}" location = each.key resource_group_name = azurerm_resource_group.rg[each.key].name security_rule { name = "AllowSSH" priority = 100 direction = "Inbound" access = "Allow" protocol = "Tcp" source_port_range = "*" destination_port_range = "22" source_address_prefix = "*" destination_address_prefix = "*" } } # ----------------------------------------------------------------------------- # 4. Public IPs for VMs # ----------------------------------------------------------------------------- resource "azurerm_public_ip" "public_ip" { for_each = toset(local.vm_names) name = "${each.value}-pip" location = azurerm_resource_group.rg[local.location_default].location resource_group_name = azurerm_resource_group.rg[local.location_default].name allocation_method = "Dynamic" } # ----------------------------------------------------------------------------- # 5. Load Balancer Setup (Blue-Green with Frontend IPs and Backend Pools) # ----------------------------------------------------------------------------- resource "azurerm_lb" "load_balancer" { for_each = toset([local.location_default, local.location_centralus]) name = "lb-${each.key}" location = each.key resource_group_name = azurerm_resource_group.rg[each.key].name sku = "Basic" } resource "azurerm_lb_frontend_ip_configuration" "frontend_ip" { for_each = azurerm_lb.load_balancer name = "frontend-${each.key}" resource_group_name = each.value.resource_group_name loadbalancer_id = each.value.id private_ip_address = "10.0.0.4" private_ip_address_allocation = "Dynamic" } resource "azurerm_lb_backend_address_pool" "backend_pool" { for_each = azurerm_lb.load_balancer name = "backend-${each.key}" resource_group_name = each.value.resource_group_name loadbalancer_id = each.value.id } # ----------------------------------------------------------------------------- # 6. Network Interface and VM Configurations (Blue-Green) # ----------------------------------------------------------------------------- resource "azurerm_network_interface" "nic" { for_each = toset(local.vm_names) name = "${each.value}-nic" location = azurerm_resource_group.rg[local.location_default].location resource_group_name = azurerm_resource_group.rg[local.location_default].name ip_configuration { name = "internal" subnet_id = azurerm_subnet.subnet["eastus2"].id private_ip_address_allocation = "Dynamic" public_ip_address_id = azurerm_public_ip.public_ip[each.value].id } } resource "azurerm_linux_virtual_machine" "vm" { for_each = toset(local.vm_names) name = each.value location = azurerm_resource_group.rg[local.location_default].location resource_group_name = azurerm_resource_group.rg[local.location_default].name network_interface_ids = [azurerm_network_interface.nic[each.value].id] size = "Standard_B1ls" os_disk { caching = "ReadWrite" storage_account_type = "Standard_LRS" } source_image_reference { publisher = "Canonical" offer = "UbuntuServer" sku = "18.04-LTS" version = "latest" } computer_name = lower(each.value) admin_username = local.admin_username disable_password_authentication = false admin_password = azurerm_key_vault_secret.admin_password_secret.value } # ----------------------------------------------------------------------------- # 7. Load Balancer Backend Pool Associations (VMs to Backend) # ----------------------------------------------------------------------------- resource "azurerm_lb_backend_address_pool_association" "backend_pool_association" { for_each = toset(local.vm_names) network_interface_id = azurerm_network_interface.nic[each.value].id backend_address_pool_id = azurerm_lb_backend_address_pool.backend_pool["eastus2"].id } # ----------------------------------------------------------------------------- # 8. Storage Account and Blob Container for tfstate # ----------------------------------------------------------------------------- resource "azurerm_storage_account" "storage" { name = local.storage_account_name resource_group_name = azurerm_resource_group.rg["eastus2"].name location = azurerm_resource_group.rg["eastus2"].location account_tier = "Standard" account_replication_type = "LRS" } resource "azurerm_storage_container" "tfstate_container" { name = local.container_name storage_account_name = azurerm_storage_account.storage.name container_access_type = "private" } # ----------------------------------------------------------------------------- # 9. Output the Public IP Addresses and Key Vault Name # ----------------------------------------------------------------------------- output "public_ips" { value = azurerm_public_ip.public_ip[*].ip_address } output "key_vault_name" { value = azurerm_key_vault.kv.name } output "storage_account_name" { value = azurerm_storage_account.storage.name } output "storage_container_name" { value = azurerm_storage_container.tfstate_container.name }