Azure Infrastructure Automation with Terraform

Infrastructure as Code (IaC)

ยท

13 min read

Azure Infrastructure Automation with Terraform

We are going to create the following Azure Resources

  1. azurerm_resource_group

  2. azurerm_virtual_network

  3. azurerm_subnet

  4. azurerm_network_security_group

  5. azurerm_subnet_network_security_group_association

  6. azurerm_network_security_rule

  7. azurerm_public_ip

  8. azurerm_network_interface

  9. azurerm_network_security_group

  10. azurerm_network_interface_security_group_association

  11. Terraform Local Block for Security Rule Ports

  12. Terraform for_each Meta-argument

  13. azurerm_network_security_rule

  14. Terraform Local Block for defining custom data to Azure Linux Virtual Machine

  15. azurerm_linux_virtual_machine

  16. Terraform Outputs for the listed Azured Resources

  17. Terraform Functions

Azure Resources and Topology

Steps:

  1. Create folder Azure_Vnet_4-tier and inside it create a folder manifests; inside this manifests folder store all the configuration files.

  2. 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 {}
      }
    
  3. 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"
      }
    
  4. Now define terraform local values inside the 3_locals.tffile.

      # 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
        }
      }
    
  5. 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
      }
    
  6. 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.tffor 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.tffor 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"]
    

    Create SSH key for Azure Linux VM

     # Create Folder
     cd terraform-manifests/
     mkdir ssh-keys
    
     # Create SSH Key
     cd ssh-ekys
     ssh-keygen \
         -m PEM \
         -t rsa \
         -b 4096 \
         -C "azureuser@myserver" \
         -f terraform-azure.pem 
     Important Note: If you give passphrase during generation, during everytime you login to VM, you also need to provide passphrase.
    
     # List Files
     ls -lrt ssh-keys/
    
     # Files Generated after above command 
     Public Key: terraform-azure.pem.pub -> Rename as terraform-azure.pub
     Private Key: terraform-azure.pem
    
     # Permissions for Pem file
     chmod 400 terraform-azure.pem
    

    Keys were created here, one is terraform-azure.pem which is private key and the other one is terraform-azure.pem.pub which is public key associated with azure VM.

    Provide 400 permissions for terraform-azure.pem file.

  7. Create tf file for Web Linux-VM Input Variables. ( 7_01_web_linuxvm_input_variables.tf ) This file will be a placeholder for you to add input variables in production I am not going to variablize anything so we are going to hardcode and write directly.

  8. To access our VM via the internet we need a Public IP associated with that VM. (Create file: 7_02_web_linuxvm_publicip.tf)

     #Resorce 1: Public-IP
     resource "azurerm_public_ip" "web_linuxvm_publicip" {
       name = "${local.resource_name_prefix}-web_linuxvm_publicip"
       resource_group_name = azurerm_resource_group.rg.name
       location = azurerm_resource_group.rg.location
       allocation_method = "Static"
       sku = "Standard"
       domain_name_label = "app1-vm-${random_string.my-random.id}"
       tags = local.comman_tags
     }
    
  9. Now implement the network interface (NIC) for Web LinuxVM (7_03_web_linuxvm_network_interface.tf)

     #Resource:Network Interface {NIC}
     resource "azurerm_network_interface" "web_linuxvm_nic" {
       name = "${local.resource_name_prefix}-web_linuxvm_nic"
       location = azurerm_resource_group.rg.location
       resource_group_name = azurerm_resource_group.rg.name
    
       ip_configuration {
         name = "web-linuxvm-ip-1"
         subnet_id = azurerm_subnet.websubnet.id
         private_ip_address_allocation = "Dynamic"
         public_ip_address_id = azurerm_public_ip.web_linuxvm_publicip.id
       }
     }
    
  10. Create an NSG for Web LinuxVM and Associate the NSG with Web LinuxVM NIC.

    ( create file:7_04_web_linuxvm_network_security_group.tf )

    
    # Resource (Optional): Create Network Security Group and Associate to Linux VM Network Interface
    # Resource-1: Network Security Group (NSG)
    resource "azurerm_network_security_group" "web_vmnic_nsg" {
      name                = "${azurerm_network_interface.web_linuxvm_nic.name}-nsg"
      location            = azurerm_resource_group.rg.location
      resource_group_name = azurerm_resource_group.rg.name
    }
    
    # Resource-2: Associate NSG and Linux VM NIC
    resource "azurerm_network_interface_security_group_association" "web_vmnic_nsg_associate" {
      depends_on = [ azurerm_network_security_rule.web_vmnic_nsg_rule_inbound]
      network_interface_id      = azurerm_network_interface.web_linuxvm_nic.id
      network_security_group_id = azurerm_network_security_group.web_vmnic_nsg.id
    }
    
    # Resource-3: NSG Rules
    ## Locals Block for Security Rules
    locals {
      web_vmnic_inbound_ports_map = {
        "100" : "80", # If the key starts with a number, you must use the colon syntax ":" instead of "="
        "110" : "443",
        "120" : "22"
      } 
    }
    ## NSG Inbound Rule for WebTier Subnets
    resource "azurerm_network_security_rule" "web_vmnic_nsg_rule_inbound" {
      for_each = local.web_vmnic_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.web_vmnic_nsg.name
    }
    
  11. Create an Azure Linux VM and its resources.

    ( Create file: 7_05_web_linuxvm_resource.tf )

    # Locals Block for custom data
    locals {
      webvm_custom_data = <<CUSTOM_DATA
          #!/bin/sh
          #!/bin/sh
          #sudo yum update -y
          sudo yum install -y httpd
          sudo systemctl enable httpd
          sudo systemctl start httpd  
          sudo systemctl stop firewalld
          sudo systemctl disable firewalld
          sudo chmod -R 777 /var/www/html 
          sudo echo "Welcome to stacksimplify - WebVM App1 - VM Hostname: $(hostname)" > /var/www/html/index.html
          sudo mkdir /var/www/html/app1
          sudo echo "Welcome to stacksimplify - WebVM App1 - VM Hostname: $(hostname)" > /var/www/html/app1/hostname.html
          sudo echo "Welcome to stacksimplify - WebVM App1 - App Status Page" > /var/www/html/app1/status.html
          sudo echo '<!DOCTYPE html> <html> <body style="background-color:rgb(250, 210, 210);"> <h1>Welcome to Stack Simplify 
          - WebVM APP-1 </h1> <p>Terraform Demo</p> <p>Application Version: V1</p> </body></html>' | sudo tee /var/www/html/app1/index.html
          sudo curl -H "Metadata:true" --noproxy "*" "http://169.254.169.254/metadata/instance?api-version=2020-09-01" -o /var/www/html/app1/metadata.html
      CUSTOM_DATA
    }
    
    # Resource: Azure Linux Virtual Machine
    resource "azurerm_linux_virtual_machine" "web_linuxvm" {
      name = "${local.resource_name_prefix}-web-linuxvm"
      resource_group_name = azurerm_resource_group.rg.name
      location = azurerm_resource_group.rg.location
      size = "Standard_DS1_v2"
      admin_username = "azureuser"
      network_interface_ids = [
        azurerm_network_interface.web_linuxvm_nic.id
      ]
    
      admin_ssh_key {
        username = "azureuser"
        public_key = file("/home/rohit/Documents/terraform_with_azure/Project-TF-AZ/azure_tf_project/manifests/ssh-keys/terraform-azure.pub")
    
      }
    
      os_disk {
        caching = "ReadWrite"
        storage_account_type = "Standard_LRS"
      }
    
      source_image_reference {
        publisher = "RedHat"
        offer = "RHEL"
        sku = "83-gen2"
        version = "latest"
      }
      custom_data = base64encode(local.webvm_custom_data)
    }
    
  12. Output values for Linux VM (Create File: 7_06_web_linuxvm_outputs.tf)

    ```bash

    Public IP Outputs

    Public IP Address

    output "web_linuxvm_public_ip" { description = "Web Linux VM Public Address" value = azurerm_public_ip.web_linuxvm_publicip.ip_address }

Network Interface Outputs

Network Interface ID

output "web_linuxvm_network_interface_id" { description = "Web Linux VM Network Interface ID" value = azurerm_network_interface.web_linuxvm_nic.id }

Network Interface Private IP Addresses

output "web_linuxvm_network_interface_private_ip_addresses" { description = "Web Linux VM Private IP Addresses" value = [azurerm_network_interface.web_linuxvm_nic.private_ip_addresses] }

Linux VM Outputs

Virtual Machine Public IP

output "web_linuxvm_public_ip_address" { description = "Web Linux Virtual Machine Public IP" value = azurerm_linux_virtual_machine.web_linuxvm.public_ip_address }

Virtual Machine Private IP

output "web_linuxvm_private_ip_address" { description = "Web Linux Virtual Machine Private IP" value = azurerm_linux_virtual_machine.web_linuxvm.private_ip_address }

Virtual Machine 128-bit ID

output "web_linuxvm_virtual_machine_id_128bit" { description = "Web Linux Virtual Machine ID - 128-bit identifier" value = azurerm_linux_virtual_machine.web_linuxvm.virtual_machine_id }

Virtual Machine ID

output "web_linuxvm_virtual_machine_id" { description = "Web Linux Virtual Machine ID " value = azurerm_linux_virtual_machine.web_linuxvm.id }


13. Execute Terraform Commands

    ```bash
    # Terraform Initialize
    terraform init

    # Terraform Validate
    terraform validate

    # Terraform Plan
    terraform plan

    # Terraform Apply
    terraform apply -auto-approve

  1. Verify Resources

    1. Azure Resource Group
    2. Azure Virtual Network
    3. Azure Subnets (Web, App, DB, Bastion)
    4. Azure Network Security Groups (Web, App, DB, Bastion)
    5. View the topology
    6. Verify Terraform Outputs in Terraform CLI
    
    # Verify Resources - Web Linux VM 
    1. Verify Public IP created for Web Linux VM
    2. Verify Network Interface created for Web Linux VM
    3. Verify Web Linux VM
    4. Verify Network Security Groups associated with VM (web Subnet NSG and NIC NSG)
    5. View Topology at Web Linux VM -> Networking
    6. Connect to Web Linux VM
    ssh -i ssh-keys/terraform-azure.pem azureuser@<Web-LinuxVM-PublicIP>
    sudo su - 
    cd /var/log
    tail -100f cloud-init-output.log
    cd /var/www/html
    ls -lrt
    cd /var/www/html/app1
    ls -lrt
    exit
    exit
    
    7. Access Sample Application
    http://<PUBLIC-IP>/
    http://<PUBLIC-IP>/app1/index.html
    http://<PUBLIC-IP>/app1/hostname.html
    http://<PUBLIC-IP>/app1/status.html
    http://<PUBLIC-IP>/app1/metadata.html
    

    -- Azure Resource Group

    -- Azure Virtual Network

    -- Azure Subnets (Web, App, DB, Bastion)

    -- Azure Network Security Groups (Web, App, DB, Bastion)

    -- View the topology

    -- Verify Public IP created for Web Linux VM

    -- Verify Network Interface created for Web Linux VM

    -- Verify Web Linux VM

    -- Verify Network Security Groups associated with VM (web Subnet NSG and NIC NSG)

    -- View Topology at Web Linux VM -> Networking

    -- Verify Terraform Outputs in Terraform CLI

    -- Connect to Web Linux VM

  2. Comment NSG associated with VM

    (7_04_web_linuxvm_network_security_group.tf)

    # Comment code in c7-04-web-linuxvm-network-security-group.tf
    NSG associated with Web Linux VM NIC is commented
    
    # Terraform Validate
    terraform validate
    
    # Terraform Plan
    terraform plan
    
    # Terraform Apply
    terraform apply -auto-approve
    
    # Verify NSG associated with VM
    1. Verify Network Security Groups associated with VM (web Subnet NSG only)
    2. Access Application
    http://<PUBLIC-IP>/app1/metadata.html
    

    Here you can see only NSG is present at the subnet level.

  3. Delete Resources

    We have completed the VM setup. ๐ŸŽ‰
    In our next blog (Part 2), we will focus on setting up a bastion host and service, and then accessing this web subnet-related VM privately within the virtual network itself.

GitHub Repo Link:github.com/DeoreRohit4/Azure-Infrastructure..


Keep Exploring...

ย