I am trying to script the setup of a bunch of resource in Azure, as part of this I need a web app to be able to communicate with a service running on a VM via the vNet.
I have created a template that seems to do everything it should to create the connection but for some reason the connection is not made. Looking in the portal shows that the site is connected to the vNet and that the certificates are in sync, but the point-to-site configuration on the vNet gateway shows no active connections.
However if I disconnect the web app from the vNet and then use the setup button in the Azure portal to reconnect to the same vNet everything works perfectly.
There must be something I'm missing in my template, but having spent the last few hours looking I cannot work out what
Here is my ARM template
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
},
"variables": {
},
"resources": [
{
"type": "Microsoft.Network/networkSecurityGroups",
"name": "[variables('nsgName')]",
"apiVersion": "2016-03-30",
"location": "[parameters('location')]",
"properties": {
"securityRules": []
},
"resources": [ ],
"dependsOn": [ ]
},
{
"type": "Microsoft.Network/networkSecurityGroups",
"name": "[variables('infrastructureNsgName')]",
"apiVersion": "2016-03-30",
"location": "[parameters('location')]",
"properties": {
"securityRules": []
},
"resources": [ ],
"dependsOn": [ ]
},
{
"type": "Microsoft.Network/virtualNetworks",
"name": "[variables('vnetName')]",
"apiVersion": "2016-03-30",
"location": "[parameters('location')]",
"properties": {
"addressSpace": {
"addressPrefixes": [
"10.1.0.0/16"
]
},
"subnets": [
{
"name": "default",
"properties": {
"addressPrefix": "10.1.0.0/17",
"networkSecurityGroup": {
"id": "[resourceId('Microsoft.Network/networkSecurityGroups', variables('nsgName'))]"
}
}
},
{
"name": "infrastructure",
"properties": {
"addressPrefix": "10.1.254.0/24",
"networkSecurityGroup": {
"id": "[resourceId('Microsoft.Network/networkSecurityGroups', variables('infrastructureNsgName'))]"
}
}
},
{
"name": "GatewaySubnet",
"properties": {
"addressPrefix": "10.1.128.0/24"
}
}
]
},
"resources": [ ],
"dependsOn": [
"[resourceId('Microsoft.Network/networkSecurityGroups', variables('nsgName'))]",
"[resourceId('Microsoft.Network/networkSecurityGroups', variables('infrastructureNsgName'))]"
]
},
{
"type": "Microsoft.Web/sites",
"kind": "api",
"name": "[variables('gatewaySiteName')]",
"apiVersion": "2015-08-01",
"location": "[parameters('location')]",
"properties": {
"name": "[variables('gatewaySiteName')]",
"hostNames": [
"[concat(variables('gatewaySiteName'),'.azurewebsites.net')]"
],
"enabledHostNames": [
"[concat(variables('gatewaySiteName'),'.azurewebsites.net')]",
"[concat(variables('gatewaySiteName'),'.scm.azurewebsites.net')]"
],
"hostNameSslStates": [
{
"name": "[concat(variables('gatewaySiteName'),'.azurewebsites.net')]",
"sslState": 0,
"thumbprint": null,
"ipBasedSslState": 0
},
{
"name": "[concat(variables('gatewaySiteName'),'.scm.azurewebsites.net')]",
"sslState": 0,
"thumbprint": null,
"ipBasedSslState": 0
}
],
"serverFarmId": "[resourceId('Microsoft.Web/serverfarms', variables('gatewayServerFarmName'))]"
},
"resources": [],
"dependsOn": [
"[resourceId('Microsoft.Web/serverfarms', variables('gatewayServerFarmName'))]",
"[concat('Microsoft.Network/virtualNetworks/', variables('vnetName'))]"
]
},
{
"type": "Microsoft.Web/serverfarms",
"sku": {
"name": "S1",
"tier": "Standard",
"size": "S1",
"family": "S",
"capacity": 1
},
"kind": "",
"name": "[variables('gatewayServerFarmName')]",
"apiVersion": "2015-08-01",
"location": "[parameters('location')]",
"properties": {
"name": "[variables('gatewayServerFarmName')]",
"numberOfWorkers": 1
},
"resources": [ ],
"dependsOn": [ ]
},
{
"name": "[variables('vnetGatewayIpName')]",
"type": "Microsoft.Network/publicIPAddresses",
"location": "[parameters('location')]",
"apiVersion": "2015-06-15",
"properties": {
"publicIPAllocationMethod": "Dynamic"
}
},
{
"name": "[variables('vnetGatewayName')]",
"type": "Microsoft.Network/virtualNetworkGateways",
"location": "[parameters('location')]",
"apiVersion": "2015-06-15",
"dependsOn": [
"[concat('Microsoft.Network/publicIPAddresses/', variables('vnetGatewayIpName'))]",
"[concat('Microsoft.Network/virtualNetworks/', variables('vnetName'))]"
],
"properties": {
"ipConfigurations": [
{
"properties": {
"privateIPAllocationMethod": "Dynamic",
"subnet": {
"id": "[resourceId('Microsoft.Network/virtualNetworks/subnets',variables('vnetName'),'GatewaySubnet')]"
},
"publicIPAddress": {
"id": "[resourceId('Microsoft.Network/publicIPAddresses',variables('vnetGatewayIpName'))]"
}
},
"name": "vnetGatewayConfig"
}
],
"gatewayType": "Vpn",
"vpnType": "RouteBased",
"enableBgp": false,
"vpnClientConfiguration": {
"vpnClientAddressPool": {
"addressPrefixes": [
"172.16.201.0/24"
]
},
"vpnClientRootCertificates": [
{
"name": "AppServiceCertificate.cer",
"properties": {
"PublicCertData": "[reference(concat('Microsoft.Web/sites/', variables('gatewaySiteName'), '/virtualNetworkConnections/virtualNetworkConnections')).certBlob]"
}
}
]
}
}
},
{
"name": "[variables('gatewayVnetConnectionName')]",
"type": "Microsoft.Web/sites/virtualNetworkConnections",
"location": "[parameters('location')]",
"apiVersion": "2015-08-01",
"dependsOn": [
"[concat('Microsoft.Web/sites/', variables('gatewaySiteName'))]",
"[concat('Microsoft.Network/virtualNetworks/', variables('vnetName'))]"
],
"properties": {
"vnetResourceId": "[resourceId('Microsoft.Network/virtualNetworks', variables('vnetName'))]"
}
}
]
}
In a web browser, go to the Azure portal and sign in. From the Azure portal search bar, search for deploy a custom template and then select it from the available options. For Template source, notice that Quickstart template is selected by default. You can keep this selection.
I could never make that work just by the ARM template alone. However if you can spend one more PowerShell command post-creation, it works beautifully:
# Set VNET Integration for Web App
$ResourceGroup = "WeMadeThatInWestEuropeDidntWe"
$WebApp = "LearningMomentsInProduction"
$PropertiesObject = @{
vnetName = "JimAreYouSureThisIsTheStagingVNET";
}
Set-AzureRmResource -PropertyObject $PropertiesObject `
-ResourceGroupName $ResourceGroup `
-ResourceType Microsoft.Web/sites/config `
-ResourceName $WebApp/web `
-ApiVersion 2015-08-01 -Force -Verbose |
Select -expand Properties |
Select VnetName
# Expected output:
#
# VnetName
# --------
# JimAreYouSureThisIsTheStagingVNET
#
# At this point your Web App is hooked up to the VNET
This does not do what i thought it does.
To resync Point-to-site certificates:
$ResourceGroup = "WeMadeThatInWestEuropeDidntWe"
# VNET Name or Gateway name, try with gateway name!
$vnetName = "JimAreYouSureThisIsTheStagingVNET";
$PropertiesObject = @{
resyncRequired = "true"
}
Set-AzureRmResource -PropertyObject $PropertiesObject -ResourceGroupName $ResourceGroup `
-ResourceType Microsoft.Web/sites/virtualNetworkConnections `
-ResourceName $VnetName
-ApiVersion 2015-08-01 `
-Force -Verbose
A good way of finding the correct settings after you have configured it correct in the Azure Portal, is to take a look under the hood. This can be done by taking a look through https://resources.azure.com/ or the Resource Explorer in the Azure portal.
Here you will find the json in the state it is working and compare those to your ARM template. The settings can't be copied 1-on-1, but it comes close. Good luck with finding the difference.
You put it as a nested resource within the site:
(This assumes everything is under the same subscription and resource group, else, you will need to modify the parameters for resourceId()
)
"properties":[],
"resources": [
{
"name": "[concat(variables('webappSiteName'), '/', variables('webappSiteName'), '-vnetIntegration')]",
"type": "Microsoft.Web/sites/virtualNetworkConnections",
"apiVersion": "2018-02-01",
"properties": {
"vnetResourceId": "[resourceId('Microsoft.Network/virtualNetworks', 'vnetname')]"
},
"dependsOn": [
"[resourceId('Microsoft.Web/sites', variables('webappSiteName'))]"
]
}
]
At minimum, that what's required, however, the Microsoft.Web/sites/virtualNetworkConnections
resource must have the client certificate data provided (which must be configured in the P2S connection in your vnet gateway), which is the property certBlob
which according to the documentation it is:
A certificate file (.cer) blob containing the public key of the private key used to authenticate a Point-To-Site VPN connection.
Having that subnode worked for me, if you don't specify the certificate information, your web application(s) will show an error saying the certificates are not in sync.
Refer to the virtualNetworkConnections
documentation online
Hope this helps.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With