IaC Bazaar
AzureStatic-verified

Application Gateway v2 + WAF

Regional L7 load balancer with WAF v2 policy, TLS termination from Key Vault, autoscaling and health probes.

terraformAzure#azure

Compare Load Balancer across clouds →

azure-application-gatewayterraform v1.7

Verification

Static-verified

Passed: validated and lint-clean (provider-schema-validated for AWS/Azure/GCP; Terraform-language lint elsewhere).

Conformance

  • Static validation (fmt · validate · tflint)
  • Security scan: findings disclosed (Checkov)
  • Plan tests (mocked: validation rules · outputs)

Provenance

  • SHA-256 checksum
  • Signature (pending)

Functional

  • Live test pending (no cloud run yet)

Last verified 2026-06-28 · how we verify

Documentation

azure-application-gateway

Regional L7 load balancer with WAF v2 policy, TLS termination from Key Vault, autoscaling and health probes. Works with Terraform and OpenTofu (>= 1.6), azurerm provider >= 4.0, < 5.0.

azurerm_application_gateway is a monolithic resource with a dozen nested block types that must cross-reference each other by name. This module flattens that into plain maps keyed by name, generates frontend ports from your listeners, and enforces the cross-block invariants (redirect XOR backend per rule, certificate required on HTTPS listeners) at plan time.

Secure defaults:

  • WAF_v2 SKU with OWASP 3.2 managed rules in Prevention mode
  • Predefined TLS policy AppGwSslPolicy20220101 (TLS 1.2+)
  • Key Vault TLS certificates via a dedicated user-assigned identity (no certificate blobs in state) — pass versionless secret IDs for auto-rotation
  • HTTP/2 enabled, autoscaling 1-3 capacity units, zone-deployable

Usage

module "gateway" {
  source              = "./azure-application-gateway"
  name                = "myapp-prod-agw"
  resource_group_name = "rg-myapp-prod"
  location            = "westeurope"
  subnet_id           = azurerm_subnet.appgw.id
  zones               = ["1", "2", "3"]

  ssl_certificates = {
    main = { key_vault_secret_id = azurerm_key_vault_certificate.main.versionless_secret_id }
  }

  backend_address_pools = {
    web = { fqdns = ["myapp-prod-web.azurewebsites.net"] }
  }

  backend_http_settings = {
    web = { pick_host_name_from_backend_address = true }
  }

  http_listeners = {
    https = { frontend_port = 443, ssl_certificate_name = "main" }
    http  = { frontend_port = 80, protocol = "Http" }
  }

  redirect_configurations = {
    to-https = { target_listener_name = "https" }
  }

  request_routing_rules = {
    https = { priority = 100, http_listener_name = "https", backend_address_pool_name = "web", backend_http_settings_name = "web" }
    http  = { priority = 200, http_listener_name = "http", redirect_configuration_name = "to-https" }
  }

  tags = { Environment = "prod" }
}

Grant the gateway identity access to your vault before apply: module.gateway.identity_principal_id → role Key Vault Secrets User.

Inputs

NameTypeDefaultDescription
namestringGateway name; prefixes PIP/WAF/identity (required)
resource_group_namestringExisting resource group (required)
locationstringAzure region (required)
subnet_idstringDedicated gateway subnet (required)
skustring"WAF_v2"WAF_v2 or Standard_v2
autoscaleobject{min 1, max 3}Capacity-unit bounds
zoneslist(string)nullAvailability zones
ssl_policy_namestringAppGwSslPolicy20220101Predefined TLS policy
wafobjectOWASP 3.2 / PreventionMode, rule set, body limits
ssl_certificatesmap(object){}Key Vault secret IDs keyed by cert name
backend_address_poolsmap(object)FQDNs / IPs keyed by pool name (required)
backend_http_settingsmap(object)Port/protocol/probe per settings name (required)
probesmap(object){}Custom health probes
http_listenersmap(object)Port, protocol, host(s), certificate (required)
request_routing_rulesmap(object)Priority + listener → backend or redirect (required)
redirect_configurationsmap(object){}e.g. HTTP→HTTPS permanent redirect
tagsmap(string){}Tags applied to all resources

Outputs

application_gateway_id, application_gateway_name, public_ip_address, public_ip_id, identity_principal_id, identity_id, waf_policy_id, backend_address_pool_ids.

Requirements

  • Terraform or OpenTofu >= 1.6
  • hashicorp/azurerm >= 4.0, < 5.0 (built against 4.76)
  • A dedicated subnet (nothing but Application Gateways in it)
  • Running cost is roughly $0.45/hr for WAF_v2 — destroy test stacks promptly

Verification

Static-validated (fmt, validate, tflint). Live apply/destroy testing pending cloud sandbox availability — see catalog status.

License

Commercial — IaC Bazaar EULA. © IaC Bazaar. Original work (not derived from a third-party module).