Online Course

How to Set Up a Point-to-Site VPN in Azure with DNS Private Resolver Using Terraform

azure dns network vpn Jan 24, 2025

Azure allows you to deploy private resources, meaning resources that are not directly accessible from the internet.

These resources remain inaccessible to the public internet but can be accessed by your workloads deployed within Azure.

For example, you might have a private storage account or a private database that only your solution can access.

Occasionally, you may need to connect to these resources directly from your laptop instead of using a virtual machine deployed in Azure.

In such cases, you can set up a Site-to-Site VPN, an ExpressRoute, or a Point-to-Site VPN.

In this article, we’ll focus on configuring the latter, enabling DNS resolution from the VPN client using Azure DNS Private Resolver, and deploying everything with Terraform.

The complete source code for this project is available on GitHub.

 

Why Use a Point-to-Site VPN

In large organizations, it's common to use an ExpressRoute or a Site-to-Site VPN to enable private access to Azure for a large group of computers.

However, for smaller companies or, as in our case, a lab project, where only a few computers need private access to Azure, a Point-to-Site VPN is a more practical and cost-effective solution.

Essentially, a Point-to-Site VPN connects a single device to Azure, whereas a Site-to-Site VPN connects an entire network or group of devices.

 

Cool, But Why Do We Need Azure DNS Private Resolver Here?

In Azure, we rely on the Azure-provided DNS to resolve DNS queries. Notice that we don’t use any custom DNS here—no virtual machines running a DNS server or anything like that. Personally, I prefer to avoid managing VMs whenever possible.

So, without a custom DNS, how can we resolve Azure-related DNS queries from our laptop when connected to the VPN?

For example, how can we resolve the private IP address of a storage account?

This is where Azure DNS Private Resolver becomes essential. It provides a way to route DNS queries to the Azure-provided DNS within a private network.

Think of it like having a private endpoint for Azure DNS—but instead of being called a private endpoint, it’s known as a DNS Inbound Endpoint. It’s called “inbound” because traffic flows in only one direction. If we needed to route traffic in the other direction, we would use a DNS Outbound Endpoint.

In our scenario, we need to access Azure DNS from our laptop, so we’ll use an inbound endpoint.

Alright, now that we understand the "why," let’s dive into what we’re actually going to create.

 

Infrastructure

 

We will deploy the following resources:

  • Virtual Network (vnet-vpn-01): Address space 10.0.0.0/16.
  • Subnet (GatewaySubnet): Address space 10.0.1.0/24.
  • Subnet (sub-inbounddns): Address space 10.0.3.0/24.
  • Subnet (sub-vpn-01): Address space 10.0.2.0/24.
  • Public IP (pip-vpn-01): To be used by the VPN gateway.
  • VPN Gateway (vgw-vpn-01): Client address space 10.100.0.0/24.
  • Storage Account (stvpn20250120): Secured with a private endpoint (pe-stvpn20250120).
  • DNS Private Resolver (dnspr-vpn-01): Includes a DNS inbound endpoint 10.0.3.4.

Now that we know what to build, let’s dive in and get started!

 

Create Root & Client Certificates

We will use certificate-based authentication, so we need to create a root certificate and a client certificate.

Run the following PowerShell script to generate them:

# root certificate
$cert = New-SelfSignedCertificate -Type Custom -KeySpec Signature -Subject "CN=VpnRootCertificate" -KeyExportPolicy Exportable -HashAlgorithm sha256 -KeyLength 2048 -CertStoreLocation "Cert:\CurrentUser\My" -KeyUsageProperty Sign -KeyUsage CertSign
# client certificate
New-SelfSignedCertificate -Type Custom -DnsName P2SChildCert -KeySpec Signature -Subject "CN=VpnClientCertificate" -KeyExportPolicy Exportable -HashAlgorithm sha256 -KeyLength 2048 -CertStoreLocation "Cert:\CurrentUser\My" -Signer $cert -TextExtension @("2.5.29.37={text}1.3.6.1.5.5.7.3.2")

Once the certificates are created, the next step is to export the root certificate's public key.

  1. Open Manage User Certificates.
  2. Navigate to Personal > Certificates.
  3. Locate the VpnRootCertificate.
  4. Right-click on it, select All Tasks, and then choose Export…
  5. Follow the instructions in the export wizard and ensure you do not export the private key.

 

Choose the base-64 encoded X.509 format. And save the file on your disk.

Once the certificate is exported, follow these steps:

  1. Open the exported certificate file with Notepad or Visual Studio Code.
  2. Copy the Base-64 encoded content from the certificate.

 

Terraform

Next, paste the certificate into the Terraform code:

  1. Locate the azurerm_virtual_network_gateway block in the main.tf file between lines 78 and 93.
  2. Paste the certificate content where it’s required in that section.
resource "azurerm_virtual_network_gateway" "vpn_01" {
  name                = "vgw-vpn-01"
  location            = azurerm_resource_group.vpn.location
  resource_group_name = azurerm_resource_group.vpn.name

  type     = "Vpn"
  vpn_type = "RouteBased"

  active_active = false
  enable_bgp    = false
  sku           = "VpnGw1"

  ip_configuration {
    name                          = "vnetGatewayConfig"
    public_ip_address_id          = azurerm_public_ip.vpn_01.id
    private_ip_address_allocation = "Dynamic"
    subnet_id                     = azurerm_subnet.gateway.id
  }

  vpn_client_configuration {
    address_space        = ["10.100.0.0/24"]
    vpn_client_protocols = ["OpenVPN"]

    root_certificate {
      name = "VpnRoot"

      public_cert_data = <<EOF
MIIC9TCCAd2gAwIBAgIQHAzVMIc/aY5JxYQjgH0iXTANBgkqhkiG9w0BAQsFADAd
MRswGQYDVQQDDBJWcG5Sb290Q2VydGlmaWNhdGUwHhcNMjUwMTIwMjExNDE4WhcN
MjYwMTIwMjEzNDE4WjAdMRswGQYDVQQDDBJWcG5Sb290Q2VydGlmaWNhdGUwggEi
MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC62jOML+5NCw7O+U6PMc/zNMDV
5F+7qaJK08SnKy4iiD1rPq8TI5HGXJg+6wrhmgFYTLLzY8VpRhfJblrXNs5vgc2m
v+H9LjFBRc0QtMI8+2j+gmpYiaaQk3KNESP1JNvz6uOvPhAjwjCWE7wzJzUiBzL+
JShAhwG6e2DKYt8zyYWsy51Myeqx7hMCqTb/NZRSxKKUTqC4qU/NlGW+7oIkbsl1
2YZ0stgWnxx21uK6flG29C6sxfDPyENoRiCrw8t+YH0iJPKm9i98GM6qu/gALA2G
6wRtKGjFf5ZDpDMycUO6LekggF+h8Ry/PAOILFypTQpfZ6ybHXukHh2SdVh9AgMB
AAGjMTAvMA4GA1UdDwEB/wQEAwICBDAdBgNVHQ4EFgQUlfJPhTGCjK4x3q4iAi0Y
naKJNMowDQYJKoZIhvcNAQELBQADggEBAJyjEwGTzv0/6+UtesgPg0G+YIvgP7vj
ZMKANqeaypTdru3acsTcChJCmjtSA7ufBlZOhIwCWnzxY5b8Ugiuqnqv7oPWkr1u
Wl937ZLR+lHhywVQRGBzGKOo7JFlB/SiGr4F90Oq6fgZvBU0DlwPb8jo//t576R/
pt+616/9TcmWNu5Hoptb208e5x8sjMpCzalimxFx6xicSzJ2IDwEW5aaVKwJGho/
x4EkA6x5CAmBNbzSM4Xcptijkc125DNPzD8tn1PGgqu4xknNCW8XNbDhyi9WGsV8
t2XTIPZtX8fjUMlxxt72/FWRdm7ErQnz186/P+5zwAcIqvQjBSDfyzs=
EOF
    }
  }
}

You can then deploy the code with the following commands.

terraform init
terraform apply -auto-approve

 

Client Setup

Once the infrastructure is deployed, follow these steps:

  1. Go to the Azure portal and search for the VPN gateway resource (vgw-vpn-01).
  2. Navigate to Point-to-site configuration and download the VPN client.

A zip file containing your VPN profile configuration will be downloaded.

Before loading the VPN profile with the Azure VPN client, we need to make some adjustments.

  1. Extract the zip file and open the azurevpnconfig.xml file from the AzureVPN folder.
  2. Replace the <clientconfig> tag with the one provided in the file below.
<AzVpnProfile xmlns:i="<http://www.w3.org/2001/XMLSchema-instance>"
  xmlns="<http://schemas.datacontract.org/2004/07/>">
  <any xmlns:d2p1="<http://schemas.datacontract.org/2004/07/System.Xml>" i:nil="true" />
  <clientauth>
    <aad i:nil="true" />
    <cert>
      <hash i:nil="true" />
      <issuer>7f49ea33565d9bbf08aeeb866de446fbb0f8d393</issuer>
    </cert>
    <type>cert</type>
    <usernamepass i:nil="true" />
  </clientauth>
  <clientconfig>
    <dnssuffixes>
      <dnssuffix>.blob.core.windows.net</dnssuffix>
    </dnssuffixes>
    <dnsservers>
      <dnsserver>10.0.3.4</dnsserver>
    </dnsservers>
    <excluderoutes i:nil="true" />
    <includeroutes i:nil="true" />
  </clientconfig>
  <name>vnet-hub-01</name>
  <protocolconfig>
    <sslprotocolConfig>
      <transportprotocol>tcp</transportprotocol>
    </sslprotocolConfig>
  </protocolconfig>
  <serverlist>
    <ServerEntry>
      <displayname i:nil="true" />
      <fqdn>azuregateway-b0280066-36fb-45f0-a70d-616eefb186c5-75c0ceb76fff.vpn.azure.com</fqdn>
    </ServerEntry>
  </serverlist>
  <servervalidation>
    <Cert>
      <hash>DF3C24F9BFD666761B268073FE06D1CC8D4F82A4</hash>
      <issuer i:nil="true" />
    </Cert>
    <serversecret>79e0d1fe5433a456ef38341e8c9af9c7bfdb3a33612febc082a87b3a89dbe624c5b1b0a431227bebc5a6f0f83c1da0e1a33da801f3ed6ffb5fbdf321eb494a499641a5733f2e881dd8a4e0e3c895339a9ca0fc72a1b9824d5bcb531161f871403a258954884b1291e0fa498df685b1aa75a7f99e745e293272168dda7589819dd3ada67be580f2664be7009838f7cabcad9cae3796a5cea5114f58e00578b52cced671fe69adbf3e802f38a33433782689136f5a30b9151e6a182d1d6c57150d5019a210cdefe50179d083c31b1c40cd022e09f7c0e26c35e1af2ad961579b18a4e77bd104b602f05e3c67a8169e07640b53578ebbf78cb24b7299f21538e100</serversecret>
    <type>cert</type>
  </servervalidation>
  <version>1</version>
</AzVpnProfile>

We are essentially configuring the DNS server (10.0.3.4) to resolve names that end with .blob.core.windows.net. This is the domain name suffix for a Blob Storage account.

Next, we need the Azure VPN client to load the profile.

  1. Open the Microsoft Store.
  2. Search for Azure VPN Client and install it.

Once the Azure VPN Client installed, open it and click on the Import button.

  • Choose the azurevpnconfig.xml file we just updated.
  • In the Certificate Information dropdown, select the VpnClientCertificate and click Save.

 

Connect & Test

Once the profile is loaded, you can click on the Connect button to connect to the VPN.

Now, let’s do a test to see if we can resolve DNS from Azure. Run the following command.

Resolve-DnsName -Name stvpn20250120.blob.core.windows.net

You should see the storage account private IP address as below.

Notice that I didn’t use the nslookup command. This is because nslookup ignores NRPT.

NRPT stands for Name Resolution Policy Table. It's a feature in Windows that helps manage how DNS queries are handled.

Think of it as a set of rules that Windows uses to decide which DNS server to ask based on the domain name you're trying to resolve. For example:

  • If you're trying to access something like *.blob.core.windows.net, NRPT can say, "Use the DNS server at 10.0.3.4 for these queries."
  • For everything else, it can use your default DNS settings.

It's especially useful when you're connected to a VPN, as it allows specific domain names to be resolved through the private DNS server configured by the VPN, without affecting how other domain names are resolved.

Run the following command to view the list of DNS NRPT entries. You'll notice that the entries align with the VPN profile configuration we updated earlier.

Get-DnsClientNrptPolicy

And that’s it! This concludes the project. Now, you know how to create a Point-to-Site VPN with Azure and enable DNS resolution for your private resources. I hope you enjoyed it. See you next time!

Work With Me

Ready to take your Azure solutions to the next level and streamline your DevOps processes? Let's work together! As an experienced Azure solutions architect and DevOps expert, I can help you achieve your goals. Click the button below to get in touch.

Get In Touch