Posts Tagged JSON Template

The myth of Azure Application Gateway – Part 2

5db46fc5-d9c1-44ae-a0f6-4ae1d2301395In part 1 of this article I have gone through creating Azure Applications Gateways (AGW) using Powershell which is a powerful way of deploying resources on Azure, using recursive functions and methods you could build a complex solution in few lines. Unlike Powershell, JSON is a static solution. It gives you a way of creating a baseline deployment, I still haven’t found a way of controlling sub-resources (which isn’t governed by the JSON Copy() function).

In this article I will go over the same deployment using a JSON template, this only serve as a reference point for your deployment. I will use the same Azure AGW configuration I used in part 1 to keep both deployments consistent.

When building Azure AGW, same prerequisites apply to the JSON method. There is a subtle difference which I will go over when I get to that point.

So this time I have prepared a Visio diagram to simplify our deployment and understand what we are trying to achieve – see below.

appgateway-blog

The diagram shows a Web server hosting four websites running a combination of HTTP HTTPS with authentication (using Basic authentication) or Anonymous access.

The only thing different in comparison to previous Powershell deployment is the steps we take to process SSL certificates and passing them over to the JSON template.

$pfxCert = Get-Content "pathToYourSSL.pfx" -Encoding Byte
$pfxCert = [System.Convert]::ToBase64String($pfxCert)
The above steps will ensure SSL cert is passed on based on Base 64 Binary which is what is expected by the JSON parameter.
As part of the deployment I have also created a custom probe that target an HTTPS site which accepts anonymous authentication, otherwise the default probe would fail causing the whole site to be unavailable. Custom probes are a good way in overcoming issues around sites that require NTLM or basic authentication (but not form based authentication).
Make sure your Application Gateway can talk to the backend server, if you have firewalls or even IIS Request Filtering could cause the connection to fail, ensure appropriate ports are allowed both ways.
So without further ado I have attached the full code below for your leisure ….
{
  "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "applicationGatewayName": {
      "type": "string",
      "minLength": 1
    },
    "location": {
      "type": "string",
      "minLength": 1,
      "metadata": {
        "description": "Region"
      }
    },
    "virtualNetworkName": {
      "type": "string",
      "minLength": 1,
      "metadata": {
        "description": "Application Gateway vnet name"
      }
    },
    "virtualNetworkResourceGroup": {
      "type": "string",
      "minLength": 1,
      "metadata": {
        "description": "Application Gateway vnet resource group name"
      }
    },
    "subnetName": {
      "type": "string",
      "minLength": 1,
      "metadata": {
        "description": "Application Gateway subnet name"
      }
    },
    "publicIPAddressName": {
      "type": "string",
      "minLength": 1,
      "metadata": {
        "description": "PIP resource name"
      }
    },
    "certData": {
      "type": "string",
      "minLength": 1,
      "metadata": {
        "description": "SSL data in binary Base64 format"
      }
    },
    "certPassword": {
      "type": "securestring",
      "minLength": 1,
      "metadata": {
        "description": "SSL certificate password"
      }
    },
    "authCert": {
      "type": "string",
      "minLength": 1,
      "metadata": {
        "description": "Public authentication certificate - in binary Base64 format"
      }
    },
    "Authhostname": {
      "type": "string",
      "minLength": 1,
      "metadata": {
        "description": "Backend hostheader/Host SNI names used as part of your HTTPS request"
      }
    },
    "Noauthhostname": {
      "type": "string",
      "minLength": 1,
      "metadata": {
        "description": "Backend hostheader/Host SNI names used as part of your HTTPS request"
      }
    },
    "backendIPAddress": {
      "type": "string",
      "minLength": 1,
      "metadata": {
        "description": "Backend web server IP address"
      }
    }
  },
  "variables": {
    "applicationGatewayID": "[resourceId('Microsoft.Network/applicationGateways',parameters('applicationGatewayName'))]",
    "capacity": 2,
    "skuName": "Standard_Medium",
    "subnetRef": "[concat(variables('vnetID'),'/subnets/',parameters('subnetName'))]",
    "vnetID": "[resourceId(parameters('virtualNetworkResourceGroup'),'Microsoft.Network/virtualNetworks',parameters('virtualNetworkName'))]"
  },
  "resources": [
    {
      "apiVersion": "2015-06-15",
      "type": "Microsoft.Network/publicIPAddresses",
      "name": "[parameters('publicIPAddressName')]",
      "location": "[parameters('location')]",
      "properties": {
        "publicIPAllocationMethod": "Dynamic"
      },
      "tags": {
        "displayName": "[parameters('publicIPAddressName')]"
      }
    },
    {
      "apiVersion": "2016-06-01",
      "name": "[parameters('applicationGatewayName')]",
      "type": "Microsoft.Network/applicationGateways",
      "location": "[resourceGroup().location]",
      "dependsOn": [
        "[concat('Microsoft.Network/publicIPAddresses/', parameters('publicIPAddressName'))]"
      ],
      "properties": {
        "sku": {
          "name": "[variables('skuName')]",
          "tier": "Standard",
          "capacity": "[variables('capacity')]"
        },
        "sslCertificates": [
          {
            "name": "appGatewaySslCert",
            "properties": {
              "data": "[parameters('certData')]",
              "password": "[parameters('certPassword')]",
              "publicCertData": "[parameters('authCert')]"
            }
          }
        ],
        "authenticationCertificates": [
          {
            "name": "PublicCert",
            "properties": {
               "data": "[parameters('authCert')]"
            }
          }

        ],
        "gatewayIPConfigurations": [
          {
            "name": "appGatewayIpConfig",
            "properties": {
              "subnet": {
                "id": "[variables('subnetRef')]"
              }
            }
          }
        ],
        "frontendIPConfigurations": [
          {
            "name": "appGatewayFrontendIP",
            "properties": {
              "PublicIPAddress": {
                "id": "[resourceId('Microsoft.Network/publicIPAddresses',parameters('publicIPAddressName'))]"
              }
            }
          }
        ],
        "frontendPorts": [
          {
            "name": "appGWFEHttps",
            "properties": {
              "Port": 443
            }
          },
          {
            "name": "appGWFEHttp",
            "properties": {
              "Port": 80
            }
          }
        ],
        "probes": [
          {
            "name": "CustomProbe",
            "properties": {
              "protocol": "Https",
              "host": "auth.simplesite.com:443",
              "path": "/noauth/iisstart.htm",
              "interval": 5,
              "timeout": 120,
              "unhealthyThreshold": 2
            }
          }
        ],
        "backendAddressPools": [
          {
            "name": "appGatewayBackendPool",
            "properties": {
              "BackendAddresses": [
                {
                  "IpAddress": "[parameters('backendIPAddress')]"
                }
              ]
            }
          }
        ],
        "backendHttpSettingsCollection": [
          {
            "name": "appGWBEHttpSettings",
            "properties": {
              "Port": 80,
              "Protocol": "Http",
              "CookieBasedAffinity": "Disabled"
            }
          },
          {
            "name": "appGWBEHttpsSettings",
            "properties": {
              "Port": 443,
              "Protocol": "Https",
              "CookieBasedAffinity": "Disabled",
              "probe": {
                "id": "[concat(variables('applicationGatewayID'), '/probes/CustomProbe')]"
              },
              "authenticationCertificates": [
                {
                  "id": "[concat(variables('applicationGatewayID'), '/authenticationCertificates/PublicCert')]"
                }
              ]
            }
          }
        ],
        "httpListeners": [
          {
            "name": "appGatewayHttpListener",
            "properties": {
              "FrontendIPConfiguration": {
                "Id": "[concat(variables('applicationGatewayID'), '/frontendIPConfigurations/appGatewayFrontendIP')]"
              },
              "FrontendPort": {
                "Id": "[concat(variables('applicationGatewayID'), '/frontendPorts/appGWFEHttp')]"
              },
              "Protocol": "Http",
              "SslCertificate": null
            }
          },
          {
            "name": "appGatewayHttpsListenerNoAuth",
            "properties": {
              "FrontendIPConfiguration": {
                "Id": "[concat(variables('applicationGatewayID'), '/frontendIPConfigurations/appGatewayFrontendIP')]"
              },
              "FrontendPort": {
                "Id": "[concat(variables('applicationGatewayID'), '/frontendPorts/appGWFEHttps')]"
              },
              "Protocol": "Https",
              "hostName": "[parameters('Noauthhostname')]",
              "SslCertificate": {
                "Id": "[concat(variables('applicationGatewayID'), '/sslCertificates/appGatewaySslCert')]"
              },
              "RequireServerNameIndication": "true"
            }
          },
          {
            "name": "appGatewayHttpsListenerAuth",
            "properties": {
              "FrontendIPConfiguration": {
                "Id": "[concat(variables('applicationGatewayID'), '/frontendIPConfigurations/appGatewayFrontendIP')]"
              },
              "FrontendPort": {
                "Id": "[concat(variables('applicationGatewayID'), '/frontendPorts/appGWFEHttps')]"
              },
              "Protocol": "Https",
              "hostName": "[parameters('Authhostname')]",
              "SslCertificate": {
                "Id": "[concat(variables('applicationGatewayID'), '/sslCertificates/appGatewaySslCert')]"
              },
              "RequireServerNameIndication": "true"
            }
          }
        ],
        "requestRoutingRules": [
          {
            "Name": "HTTPrule",
            "properties": {
              "RuleType": "Basic",
              "httpListener": {
                "id": "[concat(variables('applicationGatewayID'), '/httpListeners/appGatewayHttpListener')]"
              },
              "backendAddressPool": {
                "id": "[concat(variables('applicationGatewayID'), '/backendAddressPools/appGatewayBackendPool')]"
              },
              "backendHttpSettings": {
                "id": "[concat(variables('applicationGatewayID'), '/backendHttpSettingsCollection/appGWBEHttpSettings')]"
              }
            }
          },
          {
            "Name": "HTTPSruleNoAuth",
            "properties": {
              "RuleType": "Basic",
              "httpListener": {
                "id": "[concat(variables('applicationGatewayID'), '/httpListeners/appGatewayHttpsListenerNoAuth')]"
              },
              "backendAddressPool": {
                "id": "[concat(variables('applicationGatewayID'), '/backendAddressPools/appGatewayBackendPool')]"
              },
              "backendHttpSettings": {
                "id": "[concat(variables('applicationGatewayID'), '/backendHttpSettingsCollection/appGWBEHttpsSettings')]"
              }
            }
          },
          {
            "Name": "HTTPSruleAuth",
            "properties": {
              "RuleType": "Basic",
              "httpListener": {
                "id": "[concat(variables('applicationGatewayID'), '/httpListeners/appGatewayHttpsListenerAuth')]"
              },
              "backendAddressPool": {
                "id": "[concat(variables('applicationGatewayID'), '/backendAddressPools/appGatewayBackendPool')]"
              },
              "backendHttpSettings": {
                "id": "[concat(variables('applicationGatewayID'), '/backendHttpSettingsCollection/appGWBEHttpsSettings')]"
              }
            }
          }
        ]
      }
    }
  ]
}
I know I haven’t written a detailed article around how each section of the JSON template code work together. I have tested this code in my own environment and I know it works for the web server I have for the backend. If you require help using the above template, please hit me with a message and I will try to clear some of the information around the code and usage cases.
Advertisements

4 Comments