It's lovely when you log in to the Azure portal, click a button and things magically happen.

It's lovelier when you can do the exact same things with an ARM template.

It's not so lovely when you stumble across a configuration that isn't actually a single resource, but a collection of hidden magical things that the Portal provisions for you when you click that button, and you have to reverse-engineer how the hell it came to be.

Can you tell which one of these scenarios I recently encountered? 😋

Successfully creating a Point-to-Site connection between a VNet and a WebApp is currently one of those things which happens magically via the portal, but once you try to automate it everything falls apart. I've spent the last week or so reverse-engineering how P2S works for WebApps, and have finally managed to automate its creation: albeit currently via PowerShell only, not via pure ARM templates.

Point-to-Site Connection - underlying components

There's a number of resources involved in a P2S connection. Here's the major ones you'd see in the Portal:

ComponentResource TypePurpose
Virtual Network (VNet)Microsoft.Network/virtualNetworksA bounded network environment within Azure, providing a barrier between internal traffic and the world outside
Network Security Group (NSG)Microsoft.Network/networkSecurityGroupsAccess control for your VNet, using allow/deny rules to determine traffic allowed In and Out
Virtual Network Gateway (VNG)Microsoft.Network/virtualNetworkGatewaysNetwork appliance on the edge of your VNet that enables tunnels to other networks, such as another VNet, or a WebApp's AppService
AppServiceMicrosoft.Web/serverfarmsHosting, billing & scaling container for WebApps
WebAppMicrosoft.Web/sitesA web application

Then, there's the hidden background ones. This is where the magic starts.

ComponentResource TypePurpose
Virtual Network ConnectionMicrosoft.Web/sites
An association between a WebApp and a VNet, required to create the P2S connection
Virtual Network Connection GatewayMicrosoft.Web/sites
The Point2Site connection within the WebApp
VPN Client Root CertificateMicrosoft.Network/virtualNetworkGateways
A reference to the public key of the WebApp's Service Certificate, implicitly created during AppService creation. Hidden AF.
VPN Client Package???An .exe generated by the Get-AzureRmVpnClientPackage cmdlet, which contains certificates generated using the VPN Client Root Certificate, to establish trust between the AppService and the VNG.

I think the above is about 85% accurate. It's how my mental model currently understands it.

So currently, I have a script that provisions a P2S connection given the WebApp, VNet, & VNG all already exist. It does the following:

  1. Create the Virtual Network Connection to associate the AppService to the VNet.
  2. Extract the CertBlob from returned resource, which is the WebApp Service Certificate's public key. This is the only way I've found so far to get access to this key, as it seems to all be created silently during AppService provisioning unless you specify your own Root Cert, which I don't imaging most people do when spinning up a WebApp.
  3. Call the Add-AzureRmVpnClientRootCertificate cmdlet against the VNG, setting the VpnClientRootCertificateName to "AppServiceCertificate.cer", and the PublicCertData to the CertBlob above.
  4. Get Azure to generate a VPN Client Package by calling the Get-AzureRmVpnClientPackage against the VNG, passing a ProcessorArchitecture of Amd64.
  5. Trim the stupid double-quote marks from the returned string, because they mess everything up if you don't.
  6. Create the Virtual Network Connection Gateway to finalise the P2S connection, passing in the name of the VNet and the location of the Vpn Package in the resource properties.

Here's the full PowerShell script, which allows you to create multiple P2S connections in one go by passing in multiple WebApp names.