Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Connect Azure Web App to vNet using ARM template

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'))]"
      }
    }
  ]
}
like image 849
Mike Norgate Avatar asked Sep 08 '16 12:09

Mike Norgate


People also ask

How do I use Azure ARM template?

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.


3 Answers

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

EDIT:

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

like image 75
evilSnobu Avatar answered Oct 20 '22 05:10

evilSnobu


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.

like image 40
Pascal Naber Avatar answered Oct 20 '22 04:10

Pascal Naber


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.

like image 1
user11880534 Avatar answered Oct 20 '22 04:10

user11880534