Intro

In this part of the blog series, I want to deploy my VPN connection to my on-premises environment and the log analytics workspace.

Azure key vault

Before I can start with my VPN connection I need to create an Azure key vault to store my VPN shared secret. The variables file for my key vault is shown below.

variable "Location" {
    type                        = string
    default                     = "WestEurope"  
}

variable "ResourceGroup" {
    type                        = string
    default                     = "rg-keyvault-001"   
}

The main.tf file used for key vault is shown below. I will give my GitHub Action service principal permissions to get and list secrets from my key vault and also make sure that the key vault is enabled for deployments and template deployments.

data "azurerm_client_config" "current" {}

resource "azurerm_resource_group" "resourcegroups" {
    name        = var.ResourceGroup
    location    = var.Location
}

resource "azurerm_key_vault" "keyvault" {
  name                            = "kv-cloudninja-vpn-001"
  location                        = azurerm_resource_group.resourcegroups.location
  resource_group_name             = azurerm_resource_group.resourcegroups.name
  enabled_for_disk_encryption     = true
  enabled_for_deployment          = true
  enabled_for_template_deployment = true
  tenant_id                       = data.azurerm_client_config.current.tenant_id
  soft_delete_retention_days      = 7
  purge_protection_enabled        = false

  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","List"
    ]

    secret_permissions = [
      "Get","List"
    ]

    storage_permissions = [
      "Get","List"
    ]
  }
}

After I created the key vault I added in my VPN shared secret.

VPN Connection

I need to provision a few Azure resources to create my VPN connection. I will need a public IP address, a Virtual Network Gateway, a Local Network Gateway, and a Connection. These resources are part of the combined VPN connection to my on-premises environment.

I will start with the public IP address I will need for my Virtual Network Gateway.

In my main.tf file for the resource group “rg-connectivity-001,” I will add the following code.

resource "azurerm_public_ip" "VPN-PublicIP" {
  name                = "pip-vgw-connectivity-001"
  location            = azurerm_resource_group.resourcegroup.location
  resource_group_name = azurerm_resource_group.resourcegroup.name

  allocation_method = "Dynamic"
  depends_on = [azurerm_virtual_network.vnet]
}

The above code will create a new public IP with a dynamic IP address. If you want to make a static, that is also possible.

Next, I will create the Virtual Network Gateway, the VPN endpoint in Azure that will route the traffic between my networks. I am using a route-based VPN without BGP enabled. I am also using the basic SKU for the environment, which is the cheapest and not recommended for production workloads where you rely on throughput for services.

In my main.tf file for the resource group “rg-connectivity-001,” I will add the following code.

resource "azurerm_virtual_network_gateway" "VPN-Gateway" {
  name                = "vgw-connectivity-001"
  location            = azurerm_resource_group.resourcegroup.location
  resource_group_name = azurerm_resource_group.resourcegroup.name

  type     = "Vpn"
  vpn_type = "RouteBased"

  active_active = false
  enable_bgp    = false
  sku           = "Basic"

  ip_configuration {
    name                          = "vgw-config"
    public_ip_address_id          = azurerm_public_ip.VPN-PublicIP.id
    private_ip_address_allocation = "Dynamic"
    subnet_id                     = azurerm_subnet.subnets["GatewaySubnet"].id
  }
  timeouts {
    create = "120m"
  }
}

The deployment of the Virtual Network Gateway can take quite some time. I have seen it vary between 15 minutes to 1 hour and 30 minutes.

The next part is the Local Network Gateway. The Local Network Gateway contains the definition of your on-premises resources. These resources include the public IP address Azure will connect to and which subnets you have on-premises that are allowed to communicate with Azure networks.

In my main.tf file for the resource group “rg-connectivity-001,” I will add the following code.

resource "azurerm_local_network_gateway" "LocalGateway" {
  name                = "lgw-onpremises-001"
  location            = azurerm_virtual_network.vnet.location
  resource_group_name = azurerm_resource_group.resourcegroup.name
  gateway_address     = var.LocalGateway.gateway_address
  address_space       = [var.LocalGateway.subnet2,var.LocalGateway.subnet1]
}

In my variables.tf file for the resource group “rg-connectivity-001,” I will add the following code. The gateway address is the public IP address I have at home (I have removed my real public IP), and the two subnets are the ones I want to use together with Azure.

variable "LocalGateway" {
  type = map
  default = {
    "gateway_address"                 = "10.10.10.10"
    "subnet1"                         = "192.168.1.0/24"
    "subnet2"                         = "192.168.10.0/24"    
  }  
}

The last piece of the VPN puzzle is the VPN connection itself. The VPN connects all the resources to establish the connection between the sites.

In my main.tf file for the resource group “rg-connectivity-001,” I will add the following code. Notice the two data sections where I reference my vault vault and then the secret inside my key vault. When I have those I can use the pre-shared key in the resource for the VPN connection.

data "azurerm_key_vault" "kv-cloudninja-vpn-001" {
  name                = "kv-cloudninja-vpn-001"
  resource_group_name = "rg-keyvault-001"
}

data "azurerm_key_vault_secret" "VPNSharedSecret" {
  name         = "VPNSharedSecret"
  key_vault_id = data.azurerm_key_vault.kv-cloudninja-vpn-001.id
}

resource "azurerm_virtual_network_gateway_connection" "VPN-Connection" {
  name                = "vcn-onpremises-001"
  location            = azurerm_resource_group.resourcegroup.location
  resource_group_name = azurerm_resource_group.resourcegroup.name

  type                       = "IPsec"
  virtual_network_gateway_id = azurerm_virtual_network_gateway.VPN-Gateway.id
  local_network_gateway_id   = azurerm_local_network_gateway.LocalGateway.id

  shared_key = data.azurerm_key_vault_secret.VPNSharedSecret.value
}

With the above code, my VPN connection is complete, and I can now communicate from my on-premises servers to my Azure environment and vice versa.

Creating log analytics workspace

The log analytics workspace is a straightforward resource to create. I have a few decisions to make before starting it, which are regarding the SKU and the retention needed. For my small demo environment here, I will have the Per Gigabyte SKU (PerGB2018), and I will set my retention for just 30 days. It will often be 180 days in production environments, but it depends on the requirements of each company that will use log analytics.

In my variables.tf file for the resource group “rg-loganalytics-001,” I will add the following code.

resource "azurerm_log_analytics_workspace" "rg-loganalytics-001" {
  name                = var.LogAnalytics.Name
  location            = var.Location
  resource_group_name = var.ResourceGroup
  sku                 = var.LogAnalytics.SKU
  retention_in_days   = var.LogAnalytics.LogRentensionInDays
}

In my variables.tf file for the resource group “rg-loganalytics-001,” I will add the following code.

variable "LogAnalytics" {
    type                        = any
    default                     = {
        "Name"                  = "log-sharedservices-001"
        "SKU"                   = "PerGB2018"
        "LogRentensionInDays"   = 30
    }   
}

Deployment of network resources

As I told you in the previous post, I only need to commit my changes to the main branch in GitHub. While developing my code, I use branches, so the commit will be a pull request from the branch I was using for development.

Summary

I can now complete this third part of the blog series. I now have a VPN connection from my on-premises environment to Azure, enabling me to manage resources without publicly being available. I also deployed the log analytics workspace, which I will use for my AVD environment and VM insights later in this blog series.

Any feedback is welcome, so reach out on Twitter or LinkedIn, so I can fix any errors or optimize the code I am using.

Part 1: https://www.cloudninja.nu/post/2022/06/github-terraform-azure-part1/

Part 2: https://www.cloudninja.nu/post/2022/06/github-terraform-azure-part2/

Part 4: https://www.cloudninja.nu/post/2022/06/github-terraform-azure-part4/

Part 5: https://www.cloudninja.nu/post/2022/07/github-terraform-azure-part5/

Part 6: https://www.cloudninja.nu/post/2022/07/github-terraform-azure-part6/

Part 7: https://www.cloudninja.nu/post/2022/08/github-terraform-azure-part7/

Part 8: https://www.cloudninja.nu/post/2022/08/github-terraform-azure-part8/

Link for all the code in this post

I have put all the code used in this blog post on my GitHub repository so you can download or fork the repository if you want to.

https://github.com/mracket/GitHub-Terraform