Using Terraform to create VNET service endpoints

Recently, I got a question on how to setup VNET service endpoints using Terraform. This blog post is a quick show and tell on how to set that up. For reference, a full example is available on my GitHub. Given it’s HashiConf at the time of writing, this seems like a good time to publish this post.

What are VNET service endpoints

I wrote about VNET service endpoints a couple years ago (can’t believe it’s been 3 years!). They are a technology to connect public Azure PaaS service to your VNET. They are different from Private Link:

  • VNET service endpoints create a connection between your subnet and the Azure PaaS service using it’s public IP. VNET service endpoints will add routes to your route table to route traffic to that PaaS service via that backend connection. They are free or charge at the time of writing.
  • Private Link creates a private endpoint in your VNET for only that specific endpoint only. With Private Link you can easily connect on-prem resources to the PaaS service as well, since the private IP is routable over VPN/Expressroute. Private Link has a small cost associated with the endpoint itself and with the traffic over the endpoint.

How to setup VNET service endpoints in Terraform

In this short demo, I’ll show you how to connect a storage account to a VNET.

To start, you’ll need some base configuration for Terraform:

provider "azurerm" {
  version = "=2.31"
  features {}
}

resource "azurerm_resource_group" "main" {
  name     = "tf-endpoint"
  location = "West US 2"
}

This is the provider itself and a resource group. Next, you’ll need a VNET and a subnet. Notice that we enable the service endpoint on the subnet:

resource "azurerm_virtual_network" "main" {
  name                = "tf-network"
  address_space       = ["10.0.0.0/16"]
  location            = azurerm_resource_group.main.location
  resource_group_name = azurerm_resource_group.main.name
}

resource "azurerm_subnet" "internal" {
  name                 = "internal"
  resource_group_name  = azurerm_resource_group.main.name
  virtual_network_name = azurerm_virtual_network.main.name
  address_prefixes     = ["10.0.2.0/24"]
  service_endpoints = ["Microsoft.Storage"]
}

Next, we’ll create the storage account. Notice how on the storage account itself we link the storage account with the subnet in the network_rules section:

resource "azurerm_storage_account" "example" {
  name                     = "tfendpint"
  location                 = azurerm_resource_group.main.location
  resource_group_name      = azurerm_resource_group.main.name
  account_tier             = "Standard"
  account_replication_type = "LRS"

  tags = {
    environment = "staging"
  }
    network_rules {
    default_action             = "Deny"
    virtual_network_subnet_ids = [azurerm_subnet.internal.id]
  }
}

And that’s how you link a storage account to a subnet using service endpoints. You can create all of this in Terraform using the following commands:

terraform init
terraform plan -out plan.out
terraform apply plan.out

Once everything is spun up, you’ll see the service endpoint on the storage account and on the subnet in the portal (see below):

Service endpoint is enabled on storage itself.
Service endpoint enabled on the subnet as well.

And that’s just how you do it. If you want to test it out for yourself, the GitHub repo also contains a VM that will be deployed that you can use to verify the connection works (which it did for me)

Summary

This short post explains how to setup service endpoints for storage using Terraform.

Leave a Reply