Azure Virtual Network Design
- We are going to design the 4-Tier Azure Virtual Network here
Azure Virtual Network
WebTier Subnet + WebTier Network Security Group (Ports 80, 443)
AppTier Subnet + AppTier Network Security Group (Ports 8080, 80, 443)
DBTier Subnet + DBTier Network Security Group (Ports 3306, 1433, 5432)
Bastion Subnet + Bastion Network Security Group (Ports 80, 3389)
Terraform
for_each
Meta-Argument
Azure Resources created
azurerm_resource_group
azurerm_virtual_network
azurerm_subnet
azurerm_network_security_group
azurerm_subnet_network_security_group_association
azurerm_network_security_rule
Steps:
Create folder Azure_Vnet_4-tier and inside it create a folder manifests; inside this manifests folder store all the configuration files.
Create a 1_versions.tf file.
In the 1_versions.tf file we have to implement "Terraform settings and providers block"
# Terraform Settings Block terraform { required_providers { azurerm = { source = "hashicorp/azurerm" version = "3.110.0" } } } # Providers Block provider "azurerm" { features {} }
In this step define generic input variables in 2_generic_input_variables.tf file.
# --- Generic Input Variables --- # Business Division variable "business_division" { description = "Business Division is the large organization this Ifrastructure belongs" type = string default = "sap" } # Environment Variables variable "environment" { description = "Environment Variable used as a prefix" default = "dev" } # Azure Resource Group Name variable "resource_group_name" { description = "Resource Group Name" default = "rg_default" } # Azure Resource Location variable "resource_group_location" { description = "Region in which azure resources to be created" default = "eastus2" }
Now define terraform local values inside the 3_locals.tf file.
# Define Local Values locals { owners = var.business_division environment = var.environment resource_name_prefix = "${var.business_division}-${var.environment}" comman_tags = { owners = local.owners environment = local.environment } }
In this step create a 4_random_resource.tf file for creating Random Strings and 5_resource_group.tf for resources group also add Random provider in 1_versions.tf file.
# Terraform Settings Block terraform { required_providers { azurerm = { source = "hashicorp/azurerm" version = "3.110.0" } random = { source = "hashicorp/random" version = "3.6.2" } } } # Providers block provider "azurerm" { features {} }
# Random string resource resource "random_string" "my-random" { length = 6 upper = false special = false }
# Resource-1 : Azure Resource Group resource "azurerm_resource_group" "rg" { name = "${local.resource_name_prefix}-${var.resource_group_name}-${random_string.my-random.id}" location = var.resource_group_location tags = local.comman_tags }
Create VNET Input Variables and VNET Resources.
Create File: 6_01_vnet_input_variables.tf
# Virtual Network Name vnet_name variable "vnet_name" { description = "Virtual Network Name" type = string default = "vnet-default" } # Vnet Address space variable "vnet_address_space" { description = "Virtual Network Address Space" type = list(string) default = [ "10.0.0.0/16" ] } # Web Subnet Name web_subnet_name variable "web_subnet_name" { description = "Vnet web subnet name" type = string default = "websubnet" } # Web subnet address space variable "web_subnet_address" { description = "Vnet web subnet address space" type = list(string) default = ["10.0.11.0/24"] } # Database Subnet Name variable "db_subnet_name" { description = "Vnet Database subnet name" type = string default = "dbsubnet" } # Database Subnet Address space variable "db_subnet_address" { description = "Virtual Network Database subnet address space" type = list(string) default = [ "10.0.21.0/24" ] } # Bastion / Management Subnet Name variable "bastion_subnet_name" { description = "Virtual Network Bastion Subnet Name" type = string default = "bastionsubnet" } # Bastion / Management Subnet Address Space variable "bastion_subnet_address" { description = "Virtual Network Bastion Subnet Address" type = list(string) default = [ "10.0.100.0/24" ] }
Create File: 6_02_virtual_network.tf
# Create Virtual Netwok resource "azurerm_virtual_network" "vnet" { name = "${local.resource_name_prefix}-${var.vnet_name}" address_space = var.vnet_address_space location = azurerm_resource_group.rg.location resource_group_name = azurerm_resource_group.rg.name tags = local.comman_tags }
This completes the creation of virtual network related input variables and the virtual network resource itself.
Now we will create the web tier related subnet and its equivalent associated network security group and rules.
Create File: 6_03_web_subnet_and_nsg.tf
# Resource 1: Web-Tier subnet resource "azurerm_subnet" "websubnet" { name = "${azurerm_virtual_network.vnet.name}-${var.web_subnet_name}" resource_group_name = azurerm_resource_group.rg.name virtual_network_name = azurerm_virtual_network.vnet.name address_prefixes = var.web_subnet_address } # Resource 2: Network Security Group (NSG) resource "azurerm_network_security_group" "web_subnet_nsg" { name = "${azurerm_subnet.websubnet.name}-nsg" location = azurerm_resource_group.rg.location resource_group_name = azurerm_resource_group.rg.name } # Resource 3: Associate NSG and Subnet resource "azurerm_subnet_network_security_group_association" "web_subnet_nsg_association" { depends_on = [ azurerm_network_security_rule.web_nsg_rule_inbound ] subnet_id = azurerm_subnet.websubnet.id network_security_group_id = azurerm_network_security_group.web_subnet_nsg.id } # Resource 4: NSG rules ## Locals Block for security rules locals { web_inbound_ports_map = { "100" : "80", "110" : "443", "120" : "22" # if the ley start with number you must use the colon syntax (:) instead of equal (=). } } # NSG rules resource "azurerm_network_security_rule" "web_nsg_rule_inbound" { for_each = local.web_inbound_ports_map name = "RulePort${each.value}" priority = each.key direction = "Inbound" access = "Allow" protocol = "Tcp" source_port_range = "*" destination_port_range = each.value source_address_prefix = "*" destination_address_prefix = "*" resource_group_name = azurerm_resource_group.rg.name network_security_group_name = azurerm_network_security_group.web_subnet_nsg.name }
Create file: 6_04_app_subnet_and_nsg.tf for creating the app tier related subnet and it's equivalent associated network security group and rules.
# Resource-1: Create AppTier Subnet resource "azurerm_subnet" "appsubnet" { name = "${azurerm_virtual_network.vnet.name}-${var.app_subnet_name}" resource_group_name = azurerm_resource_group.rg.name virtual_network_name = azurerm_virtual_network.vnet.name address_prefixes = var.app_subnet_address } # Resource-2: Create Network Security Group (NSG) resource "azurerm_network_security_group" "app_subnet_nsg" { name = "${azurerm_subnet.appsubnet.name}-nsg" location = azurerm_resource_group.rg.location resource_group_name = azurerm_resource_group.rg.name } # Resource-3: Associate NSG and Subnet resource "azurerm_subnet_network_security_group_association" "app_subnet_nsg_associate" { depends_on = [ azurerm_network_security_rule.app_nsg_rule_inbound] subnet_id = azurerm_subnet.appsubnet.id network_security_group_id = azurerm_network_security_group.app_subnet_nsg.id } # Resource-4: Create NSG Rules ## Locals Block for Security Rules locals { app_inbound_ports_map = { "100" : "80", # If the key starts with a number, you must use the colon syntax ":" instead of "=" "110" : "443", "120" : "8080", "130" : "22" } } ## NSG Inbound Rule for AppTier Subnets resource "azurerm_network_security_rule" "app_nsg_rule_inbound" { for_each = local.app_inbound_ports_map name = "Rule-Port-${each.value}" priority = each.key direction = "Inbound" access = "Allow" protocol = "Tcp" source_port_range = "*" destination_port_range = each.value source_address_prefix = "*" destination_address_prefix = "*" resource_group_name = azurerm_resource_group.rg.name network_security_group_name = azurerm_network_security_group.app_subnet_nsg.name }
Create file: 6_05_db_subnet_and_nsg.tf for creating the database tier related subnet and its equivalent associated network security group and rules.
# Resource-1: Create DBTier Subnet resource "azurerm_subnet" "dbsubnet" { name = "${azurerm_virtual_network.vnet.name}-${var.db_subnet_name}" resource_group_name = azurerm_resource_group.rg.name virtual_network_name = azurerm_virtual_network.vnet.name address_prefixes = var.db_subnet_address } # Resource-2: Create Network Security Group (NSG) resource "azurerm_network_security_group" "db_subnet_nsg" { name = "${azurerm_subnet.dbsubnet.name}-nsg" location = azurerm_resource_group.rg.location resource_group_name = azurerm_resource_group.rg.name } # Resource-3: Associate NSG and Subnet resource "azurerm_subnet_network_security_group_association" "db_subnet_nsg_associate" { depends_on = [ azurerm_network_security_rule.db_nsg_rule_inbound] subnet_id = azurerm_subnet.dbsubnet.id network_security_group_id = azurerm_network_security_group.db_subnet_nsg.id } # Resource-4: Create NSG Rules ## Locals Block for Security Rules locals { db_inbound_ports_map = { "100" : "3306", # If the key starts with a number, you must use the colon syntax ":" instead of "=" "110" : "1433", "120" : "5432" } } ## NSG Inbound Rule for DBTier Subnets resource "azurerm_network_security_rule" "db_nsg_rule_inbound" { for_each = local.db_inbound_ports_map name = "Rule-Port-${each.value}" priority = each.key direction = "Inbound" access = "Allow" protocol = "Tcp" source_port_range = "*" destination_port_range = each.value source_address_prefix = "*" destination_address_prefix = "*" resource_group_name = azurerm_resource_group.rg.name network_security_group_name = azurerm_network_security_group.db_subnet_nsg.name }
Create file: 6_06_bastion_subnet_and_nsg.tf for creating the bastion subnet and its equivalent associated network security group and rules.
# Resource-1: Create Bastion / Management Subnet resource "azurerm_subnet" "bastionsubnet" { name = "${azurerm_virtual_network.vnet.name}-${var.bastion_subnet_name}" resource_group_name = azurerm_resource_group.rg.name virtual_network_name = azurerm_virtual_network.vnet.name address_prefixes = var.bastion_subnet_address } # Resource-2: Create Network Security Group (NSG) resource "azurerm_network_security_group" "bastion_subnet_nsg" { name = "${azurerm_subnet.bastionsubnet.name}-nsg" location = azurerm_resource_group.rg.location resource_group_name = azurerm_resource_group.rg.name } # Resource-3: Associate NSG and Subnet resource "azurerm_subnet_network_security_group_association" "bastion_subnet_nsg_associate" { depends_on = [ azurerm_network_security_rule.bastion_nsg_rule_inbound] subnet_id = azurerm_subnet.bastionsubnet.id network_security_group_id = azurerm_network_security_group.bastion_subnet_nsg.id } # Resource-4: Create NSG Rules ## Locals Block for Security Rules locals { bastion_inbound_ports_map = { "100" : "22", # If the key starts with a number, you must use the colon syntax ":" instead of "=" "110" : "3389" } } ## NSG Inbound Rule for Bastion / Management Subnets resource "azurerm_network_security_rule" "bastion_nsg_rule_inbound" { for_each = local.bastion_inbound_ports_map name = "Rule-Port-${each.value}" priority = each.key direction = "Inbound" access = "Allow" protocol = "Tcp" source_port_range = "*" destination_port_range = each.value source_address_prefix = "*" destination_address_prefix = "*" resource_group_name = azurerm_resource_group.rg.name network_security_group_name = azurerm_network_security_group.bastion_subnet_nsg.name }
Create File: 6_07_vnet_outputs.tf for Virtual Network Outputs.
# Virtual Network Outputs ## Vnet name - output "virtual_network_name" { description = "Virtual network name" value = azurerm_virtual_network.vnet.name } ## Vnet id - output "virtual_network_id" { description = "virtual network ID" value = azurerm_virtual_network.vnet.id } /* Subnet Outputs (We will write for one web subnet and rest all we will ignore for now) */ ## Subnet Name output "web_subnet_name" { description = "WebTier Subnet Name" value = azurerm_subnet.websubnet.name } ## Subnet ID output "web_subnet_id" { description = "WebTier Subnet ID" value = azurerm_subnet.websubnet.id } # Network Security Outputs ## Web Subnet NSG Name output "web_subnet_nsg_name" { description = "WebTier Subnet NSG Name" value = azurerm_network_security_group.web_subnet_nsg.name } ## Web Subnet NSG ID output "web_subnet_nsg_id" { description = "WebTier Subnet NSG ID" value = azurerm_network_security_group.web_subnet_nsg.id }
Create File: terraform.tfvars
business_division = "hr" environment = "dev" resource_group_name = "rg" resource_group_location = "eastus" vnet_name = "vnet" vnet_address_space = ["10.1.0.0/16"] web_subnet_name = "websubnet" web_subnet_address = ["10.1.1.0/24"] app_subnet_name = "appsubnet" app_subnet_address = ["10.1.11.0/24"] db_subnet_name = "dbsubnet" db_subnet_address = ["10.1.21.0/24"] bastion_subnet_name = "bastionsubnet" bastion_subnet_address = ["10.1.100.0/24"]
We are done with all our configuration files and its time to execute terrafrom commands and verify all resources.
Execution
-- terraform init command
-- terraform validate command
-- terrafrom plan command
-- terrafrom apply command
Enter yes.
Go to Azure portal, check for resource group and verify that all the resources are get created or not.
Here you can see vnet and all 4 subnets are created.
Now lets go inside hr-dev-vnet.
Go to Address space and verify that you have 10.1.0.0/16 which took it from terraform.tfvars file.
Go to Subnets and verify subnets (Web, App, DB, Bastion).
Next is to verify Azure Network Security Groups (Web, App, DB, Bastion)
Now in Virtual Network View the topology.
Now once you verified that all the resources are created you can go for destroying the resources.
Delete Resources
# Delete Resources terraform destroy terraform apply -destroy # Clean-Up Files rm -rf .terraform* rm -rf terraform.tfstate*
-- terraform destroy command
The deletion of security rules from Azure NSGs failed due to connection issues, suggesting a reset or lost connection to the Azure management API;
-- rm -rf .terraform*
-- rm -rf terraform.tfstate*
We have completed the implementation of a 4-Tier Azure Virtual Network using Terraform. If you have any further questions, please drop them in the comments.
Github: github.com/DeoreRohit4/Azure-Virtual-Networ..
Linkedin: linkedin.com/in/rohitdeore
Keep Exploring...