Deploy a Hub-Spoke network using Terraform

Hello and welcome to my next blog in my Terraform series. In this blog I’ll show you how you can deploy a hub-spoke virtual network with the following components:

  • Hub vnet
  • 3 spoke vnets (Prod, Dev and Test)
  • Hub subnets for Firewall, Vpn and Bastion
  • Peerings between the Hub and Spokes
  • Nsg’s for all vnets
  • Diagnostic settings enabled for all resources to Log Analytics Workspace in the hub

Import Log Analytics Workspace

Because I want to send the logs to the Log Analytics Workspace I need to start with importing the resource in my Terraform file.

data "azurerm_log_analytics_workspace" "law" {
  name = "law-hub-jvn-01"
  resource_group_name = "rg-hub-jvn-law-01"
}

Deploy the Vnet Resource groups

First we need the resource groups for the vnets Hub, Prod, Dev and Test. The below example is for the hub resource groups. the rest of the examples will also be for the Hub vnet. The rest of the code will be available on my github repo.

resource "azurerm_resource_group" "vnet-hub-rg" {
  name     = "rg-hub-${var.prefix}-vnet-01"
  location = var.location
  tags = {
    "Critical"    = "Yes"
    "Solution"    = "Vnet"
    "Costcenter"  = "It"
    "Environment" = "Hub"
    "Location"    = "Weu"
  }
}

Deploy the Hub Vnet

Now that we have the resource groups it’s time to create the vnets. The example below is for the Hub vnet.

resource "azurerm_virtual_network" "hub-vnet" {
  name                = "vnet-hub-${var.prefix}-weu-01"
  location            = var.location
  resource_group_name = azurerm_resource_group.vnet-hub-rg.name
  address_space       = ["10.0.0.0/20"]
  dns_servers         = ["10.5.0.4","168.63.129.16"]
  tags = {
    "Critical"    = "Yes"
    "Solution"    = "Vnet"
    "Costcenter"  = "It"
    "Environment" = "Hub"
    "Location"    = "Weu"
  }
}

Deploy the NSG’s

The next piece of code that we need if for the nsg. In this example rule I put a “deny” on port 3389.

resource "azurerm_network_security_group" "nsg-hub" {
  name                = "nsg-hub-${var.prefix}-01"
  location            = azurerm_resource_group.vnet-hub-rg.location
  resource_group_name = azurerm_resource_group.vnet-hub-rg.name
  security_rule {
    name                       = "allow-rdp"
    priority                   = 100
    direction                  = "Inbound"
    access                     = "Deny"
    protocol                   = "Tcp"
    source_port_range          = "*"
    destination_port_range     = 3389
    source_address_prefix      = "*"
    destination_address_prefix = "*"
  }
}

Deploy the Network Watcher

The next resource that I will deploy is the Network Watcher. Azure Network Watcher provides tools to monitor, diagnose, view metrics, and enable or disable logs for resources in an Azure virtual network. 

resource "azurerm_network_watcher" "network-watcher-hub" {
  name = "nw-${var.prefix}-vnet-we-01"
  location = azurerm_resource_group.vnet-hub-rg.location
  resource_group_name = azurerm_resource_group.vnet-hub-rg.name
  tags = {
    "Critical"    = "Yes"
    "Solution"    = "Vnet"
    "Costcenter"  = "It"
    "Location"    = "Weu"
  }
}

Deploy the Hub subnets

Now that we have the Hub vnet we can deploy some of the subnets that belong in there. I’ll give 1 example below, the rest is on my Github page.

resource "azurerm_subnet" "firewall-subnet" {
  name                 = "AzureFirewallSubnet" ##can also be AzureFirewallManagementSubnet
  resource_group_name  = azurerm_resource_group.vnet-hub-rg.name
  virtual_network_name = azurerm_virtual_network.hub-vnet.name
  address_prefixes     = ["10.0.5.0/26"]
}

Deploy the Spoke Vnets

Now that we have the Hub vnet and the Hub subnets it’s time to create the Spoke Vnets. Again I’ll give 1 example and the rest is on Github.

resource "azurerm_virtual_network" "prod-vnet" {
  name                = "vnet-prod-${var.prefix}-weu-01"
  location            = var.location
  resource_group_name = azurerm_resource_group.vnet-prod-rg.name
  address_space       = ["10.1.0.0/20"]
  dns_servers         = ["10.5.0.4","168.63.129.16"]
 tags = {
    "Critical"    = "Yes"
    "Solution"    = "Vnet"
    "Costcenter"  = "It"
    "Environment" = "Prod"
    "Location"    = "Weu"
  }
}

Vnet peering between hub and spoke

When deploying a hub and spoke network topology you also need to deploy vnet peering. The below example is the peering between the Hub and Prod spoke.

resource "azurerm_virtual_network_peering" "peer-hub-2-prod" {
  name                      = "peer-hub-2-prod"
  resource_group_name       = azurerm_resource_group.vnet-hub-rg.name
  virtual_network_name      = azurerm_virtual_network.hub-vnet.name
  remote_virtual_network_id = azurerm_virtual_network.prod-vnet.id 
}
resource "azurerm_virtual_network_peering" "peer-prod-2-hub" {
  name                      = "peer-prod-2-hub"
  resource_group_name       = azurerm_resource_group.vnet-prod-rg.name
  virtual_network_name      = azurerm_virtual_network.prod-vnet.name
  remote_virtual_network_id = azurerm_virtual_network.hub-vnet.id 
}

Diagnostic settings on vnet and nsg

Each resource in Azure has it’s own set of diagnostic settings that you can configure. In this example I configure the diagnostic settings for the hub vnet and nsg. I enable them to be sent to the central log analytics workspace.

resource "azurerm_monitor_diagnostic_setting" "nsg-Hub" {
  name               = "diag-hub-${var.prefix}-nsg"
  target_resource_id = azurerm_network_security_group.nsg-hub.id
  log_analytics_workspace_id = data.azurerm_log_analytics_workspace.law.id
  depends_on = [azurerm_network_security_group.nsg-hub]
  

log {
    category = "NetworkSecurityGroupEvent"
    enabled  = true

    retention_policy {
      enabled = true
    }
  }
  log {
    category = "NetworkSecurityGroupRuleCounter"
    enabled = true

    retention_policy {
      enabled =true
    }
  }
}
--------------------------------------------------

resource "azurerm_monitor_diagnostic_setting" "vnet-hub-diag" {
  name               = "diag-hub-${var.prefix}-vnet"
  target_resource_id = azurerm_virtual_network.hub-vnet.id
  log_analytics_workspace_id = data.azurerm_log_analytics_workspace.law.id
  depends_on = [azurerm_virtual_network.hub-vnet]
  

log {
  category = "VMProtectionAlerts"
}

  metric {
    category = "AllMetrics"

    retention_policy {
      enabled = true
    }
  }
}

I hope this code can be useful for you to deploy your Hub-Spoke virtual network in Azure. If you have any questions about this feel free to contact me on Linkedin or via my Twitter handle.

Leave a Reply

Your email address will not be published. Required fields are marked *