azureterraformazure-aksazure-virtual-network

Terraform - How to find Azure Kubernetes AKS vnet ID for network peering


I'm using a single Terraform script to deploy AKS and an Application Gateway. So far everything is working as expected, and the last thing I need is to configure vnet peering between AKS and the Application Gateway.

According to Terraform's docs, vnet peering requires the AKS vnet name and ID:

# AppGw to AKS
resource "azurerm_virtual_network_peering" "appgw_aks_peering" {
  name                      = "appgw-aks-peer"
  resource_group_name       = "my-appgw-rg"
  virtual_network_name      = azurerm_virtual_network.my_vnet.name
  remote_virtual_network_id = ???
}

# AKS to AppGw
resource "azurerm_virtual_network_peering" "aks_appgw_peering" {
  name                      = "aks-appgw-peer"
  resource_group_name       = "my-aksnode-rg"
  virtual_network_name      = ???
  remote_virtual_network_id = azurerm_virtual_network.my_vnet.id
}

resource "azurerm_kubernetes_cluster" "my_cluster" {
  name                = "my-aks"
  location            = "australiaeast"
  resource_group_name = "my-aks-rg"
  node_resource_group = "my-aksnode-rg"

  addon_profile {
    ingress_application_gateway {
      enabled    = true
      gateway_id = azurerm_application_gateway.my_appgw.id
    }
  }

  default_node_pool {
    name                 = "np01"
    node_count           = 1
    os_disk_size_gb      = 30
    vm_size              = var.aks_np_vm_sku
  }

  ...
}

The problem I have is the AKS vnet is automatically created when AKS is created, and neither the name or ID are exported anywhere. I can't find a way to get the AKS vnet name or ID with Terraform. Can someone point me in the right direction or suggest an alternate solution?


Solution

  • As it’s not possible to get the Vnet ID from the resource block of the AKS cluster, you can create a vnet and subnet for the AKS as well and use it while creating the cluster in default node pool block like below:

    default_node_pool {
        name                 = "np01"
        node_count           = 1
        os_disk_size_gb      = 30
        vm_size              = var.aks_np_vm_sku
        vnet_subnet_id = azurerm_subnet.aks.id
      }
    

    So, as per your requirement the .tf file will be something like below:

    provider "azurerm" {
        features{}
    }
    data "azurerm_resource_group" "name" {
      name = "resourcegroupname"
    }
    resource "azurerm_virtual_network" "aks" {
      name                = "aks-vnet"
      location            = data.azurerm_resource_group.name.location
      resource_group_name = data.azurerm_resource_group.name.name
      address_space       = ["10.0.0.0/16"]
    }
    resource "azurerm_subnet" "aks" {
      name                 = "aks-subnet"
      resource_group_name  = data.azurerm_resource_group.name.name
      virtual_network_name = data.azurerm_resource_group.name.location
      address_prefixes     = ["10.0.1.0/24"]
    }
    resource "azurerm_virtual_network" "appgw" {
      name                = "appgw-vnet"
      location            = data.azurerm_resource_group.name.location
      resource_group_name = data.azurerm_resource_group.name.name
      address_space       = ["10.254.0.0/16"]
    }
    resource "azurerm_subnet" "frontend" {
      name                 = "frontend"
      resource_group_name  = data.azurerm_resource_group.name.name
      virtual_network_name = azurerm_virtual_network.appgw.name
      address_prefixes     = ["10.254.0.0/24"]
    }
    resource "azurerm_subnet" "backend" {
      name                 = "backend"
      resource_group_name  = data.azurerm_resource_group.name.name
      virtual_network_name = azurerm_virtual_network.appgw.name
      address_prefixes     = ["10.254.2.0/24"]
    }
    resource "azurerm_public_ip" "example" {
      name                = "example-pip"
      resource_group_name = data.azurerm_resource_group.name.name
      location            = data.azurerm_resource_group.name.location
      allocation_method   = "Dynamic"
    }
    # since these variables are re-used - a locals block makes this more maintainable
    locals {
      backend_address_pool_name      = "${azurerm_virtual_network.appgw.name}-beap"
      frontend_port_name             = "${azurerm_virtual_network.appgw.name}-feport"
      frontend_ip_configuration_name = "${azurerm_virtual_network.appgw.name}-feip"
      http_setting_name              = "${azurerm_virtual_network.appgw.name}-be-htst"
      listener_name                  = "${azurerm_virtual_network.appgw.name}-httplstn"
      request_routing_rule_name      = "${azurerm_virtual_network.appgw.name}-rqrt"
      redirect_configuration_name    = "${azurerm_virtual_network.appgw.name}-rdrcfg"
    }
    resource "azurerm_application_gateway" "network" {
      name                = "example-appgateway"
      resource_group_name = data.azurerm_resource_group.name.name
      location            = data.azurerm_resource_group.name.location
      sku {
        name     = "Standard_Small"
        tier     = "Standard"
        capacity = 2
      }
      gateway_ip_configuration {
        name      = "my-gateway-ip-configuration"
        subnet_id = azurerm_subnet.frontend.id
      }
      frontend_port {
        name = local.frontend_port_name
        port = 80
      }
      frontend_ip_configuration {
        name                 = local.frontend_ip_configuration_name
        public_ip_address_id = azurerm_public_ip.example.id
      }
      backend_address_pool {
        name = local.backend_address_pool_name
      }
      backend_http_settings {
        name                  = local.http_setting_name
        cookie_based_affinity = "Disabled"
        path                  = "/path1/"
        port                  = 80
        protocol              = "Http"
        request_timeout       = 60
      }
      http_listener {
        name                           = local.listener_name
        frontend_ip_configuration_name = local.frontend_ip_configuration_name
        frontend_port_name             = local.frontend_port_name
        protocol                       = "Http"
      }
      request_routing_rule {
        name                       = local.request_routing_rule_name
        rule_type                  = "Basic"
        http_listener_name         = local.listener_name
        backend_address_pool_name  = local.backend_address_pool_name
        backend_http_settings_name = local.http_setting_name
      }
    }
    resource "azurerm_virtual_network_peering" "appgw_aks_peering" {
      name                      = "appgw-aks-peer"
      resource_group_name       = data.azurerm_resource_group.name.name
      virtual_network_name      = azurerm_virtual_network.appgw.id
      remote_virtual_network_id = azurerm_virtual_network.aks.id
    }
    # AKS to AppGw
    resource "azurerm_virtual_network_peering" "aks_appgw_peering" {
      name                      = "aks-appgw-peer"
      resource_group_name       = data.azurerm_resource_group.name.name
      virtual_network_name      = azurerm_virtual_network.aks.id
      remote_virtual_network_id = azurerm_virtual_network.appgw.id
    }
    resource "azurerm_kubernetes_cluster" "my_cluster" {
      name                = "my-aks"
      location            = data.azurerm_resource_group.name.location
      resource_group_name = data.azurerm_resource_group.name.name
       dns_prefix              = "dns-myaks"
      addon_profile {
        ingress_application_gateway {
          enabled    = true
          gateway_id = azurerm_application_gateway.network.id
        }
      }
      default_node_pool {
        name                 = "np01"
        node_count           = 1
        os_disk_size_gb      = 30
        vm_size              = "Standard_D2_v2"
        vnet_subnet_id = azurerm_subnet.aks.id
      }
        identity {
        type = "SystemAssigned"
      }
    }
    

    Output:

    Enter image description here

    Enter image description here