Azure Application Gateway using Azure Verified Modules

Creating an Azure Application Gateway Using Bicep Azure Verified Modules

As cloud solutions grow more complex, using infrastructure as code (IaC) has become crucial for managing, deploying, and maintaining resources smoothly. Bicep, Microsoft’s language for Azure, makes it much easier to create templates that simplify resource management. Azure Verified Modules take it a step further by providing reusable, pre-validated components that speed up your development process.

In this post, I’ll walk through creating an Azure Application Gateway using Azure Bicep, leveraging verified modules to keep things simple and efficient.

Why Use Azure Verified Modules?

Azure Verified Modules are prebuilt and tested components that help you create standardized, production-ready Azure infrastructure faster. By using verified modules:

  • You reduce the chances of introducing configuration errors.
  • You can leverage Azure best practices directly within your deployments.
  • Modules are reusable, which promotes consistency and speeds up development.

Getting Started with Bicep

Before diving into the Application Gateway setup, ensure you have the necessary tools:

  • Azure CLI: Install or update Azure CLI to the latest version.
  • Bicep CLI: You can install Bicep via Azure CLI with the command: az bicep install.
  • Visual Studio Code (VS Code): A good code editor will make writing Bicep files easier, especially with the Bicep VS Code extension.

Once your environment is ready, you can begin writing the Bicep code to deploy an Application Gateway.

Step-by-Step: Creating an Application Gateway

Step 1: Import the Azure Verified Module

To create an Azure Application Gateway, you first need to use the Azure Verified module. Microsoft provides verified modules that can be referenced directly in your Bicep file, making your infrastructure code easier to manage.

For example, to add an Application Gateway, you might use the following code:

module createcreateApplicationGatewayppGateway 'br/public:network/application-gateway:1.0.0' = {
  scope: resourceGroup(hubSubscriptionId, hubResourceGroupNameAppGateway)
  name: 'createAppGateway'
  params: {
    name: applicationGatewayName
    location: location
    sku: 'WAF_v2'
    tags: tags
    firewallPolicyResourceId: createApplicationGatewayWafPolicy.outputs.resourceId
    gatewayIPConfigurations: [
      {
        name: 'appGatewayIpConfig'
        properties: {
          subnet: {
            id: '/subscriptions/${hubSubscriptionId}/resourceGroups/${hubNetworkRG}/providers/Microsoft.Network/virtualNetworks/${hubVnetName}/subnets/AppGwSubnet'
          }
        }
      }
    ]
    frontendIPConfigurations: [
      {
        name: 'appGwPublicFrontendIp'
        properties: {
          privateIPAllocationMethod: 'Dynamic'
          publicIPAddress: {
            id: createPublicIPAddressForAppGateway.outputs.resourceId
          }
        }
      }
    ]
    frontendPorts: [
      {
        name: 'port_80'
        properties: {
          port: 80
        }
      }
    ]
    backendAddressPools: [
      {
        name: 'vm1BackendPool'
        properties: {
          backendAddresses: [
            {
              ipAddress: '10.0.1.4' <- dont hardcode like this use variables
            }
          ]
        }
      }
    ]
    backendHttpSettingsCollection: [
      {
        name: 'defaultHTTPSetting'
        properties: {
          port: 8080
          protocol: 'Http'
          cookieBasedAffinity: 'Disabled'
          pickHostNameFromBackendAddress: false
          requestTimeout: 20
          probe: {
            id: '/subscriptions/${hubSubscriptionId}/resourceGroups/${hubResourceGroupNameAppGateway}/providers/Microsoft.Network/applicationGateways/${applicationGatewayName}/probes/HttpProbe'
          }
        }
      }
    ]
    httpListeners: [
      {
        name: 'http'
        properties: {
          frontendIPConfiguration: {
            id: '/subscriptions/${hubSubscriptionId}/resourceGroups/${hubResourceGroupNameAppGateway}/providers/Microsoft.Network/applicationGateways/${applicationGatewayName}/frontendIPConfigurations/appGwPublicFrontendIp'
          }
          frontendPort: {
            id: '/subscriptions/${hubSubscriptionId}/resourceGroups/${hubResourceGroupNameAppGateway}/providers/Microsoft.Network/applicationGateways/${applicationGatewayName}/frontendPorts/port_80'
          }
          protocol: 'Http'
          requireServerNameIndication: false
          hostNames: []
          customErrorConfigurations: []
        }
      }
    ]
    requestRoutingRules: [
      {
        name: 'routingRule1'
        properties: {
          ruleType: 'Basic'
          priority: 100
          httpListener: {
            id: '/subscriptions/${hubSubscriptionId}/resourceGroups/${hubResourceGroupNameAppGateway}/providers/Microsoft.Network/applicationGateways/${applicationGatewayName}/httpListeners/http'
          }
          backendAddressPool: {
            id: '/subscriptions/${hubSubscriptionId}/resourceGroups/${hubResourceGroupNameAppGateway}/providers/Microsoft.Network/applicationGateways/${applicationGatewayName}/backendAddressPools/vm1BackendPool'
          }
          backendHttpSettings: {
            id: '/subscriptions/${hubSubscriptionId}/resourceGroups/${hubResourceGroupNameAppGateway}/providers/Microsoft.Network/applicationGateways/${applicationGatewayName}/backendHttpSettingsCollection/defaultHTTPSetting'
          }
        }
      }
    ]
    probes: [
      {
        name: 'HttpProbe'
        properties: {
          protocol: 'Http'
          host: '10.0.1.4' <- dont hardcode like this use variables
          path: '/api/doc/'
          interval: 30
          timeout: 30
          unhealthyThreshold: 3
          pickHostNameFromBackendHttpSettings: false
          minServers: 0
          match: {
            statusCodes: [
              '200-399'
            ]
          }
        }
      }
    ]
    enableHttp2: false
    urlPathMaps: []
    autoscaleMaxCapacity: 10
    autoscaleMinCapacity: 1
  }
  dependsOn: [
    createPublicIPAddressForAppGateway
  ]
}

This code snippet shows how you can use the verified module to create an Application Gateway, specifying various configurations such as frontend ports, IP configurations, and request routing rules.

Step 2: Define Dependencies

In the example above, you’ll need to ensure other dependent resources (like the Virtual Network, Subnet, and Public IP) are available before deploying the Application Gateway. You can define these resources in the same Bicep file to create a complete setup, or reference existing resources.

For example, adding a Virtual Network might look like this:

resource myVNet 'Microsoft.Network/virtualNetworks@2021-02-01' = {
  name: 'myVNet'
  location: resourceGroup().location
  properties: {
    addressSpace: {
      addressPrefixes: [
        '10.0.0.0/16'
      ]
    }
    subnets: [
      {
        name: 'appGatewaySubnet'
        properties: {
          addressPrefix: '10.0.1.0/24'
        }
      }
    ]
  }
}

Step 3: Deploy the Bicep Template

Once your Bicep template is complete, you can deploy it using the Azure CLI. Run the following command to deploy:

az deployment group create --resource-group <your-resource-group> --template-file main.bicep

This command will take care of provisioning the resources defined in your Bicep file.

Best Practices for Application Gateway Deployment

Summary

In summary, using Azure Bicep with verified modules simplifies the process of creating and managing Azure infrastructure. Application Gateway helps you efficiently manage incoming traffic, while Bicep makes deployment clean and straightforward. Explore other verified modules in Azure’s public registry to quickly build reliable infrastructure following best practices.

Have you tried using Bicep for your infrastructure projects? Share your experiences or questions in the comments below!