Application Gateway v2 + WAF
Regional L7 load balancer with WAF v2 policy, TLS termination from Key Vault, autoscaling and health probes.
Verification
Static-verifiedPassed: 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
| Name | Type | Default | Description |
|---|---|---|---|
name | string | — | Gateway name; prefixes PIP/WAF/identity (required) |
resource_group_name | string | — | Existing resource group (required) |
location | string | — | Azure region (required) |
subnet_id | string | — | Dedicated gateway subnet (required) |
sku | string | "WAF_v2" | WAF_v2 or Standard_v2 |
autoscale | object | {min 1, max 3} | Capacity-unit bounds |
zones | list(string) | null | Availability zones |
ssl_policy_name | string | AppGwSslPolicy20220101 | Predefined TLS policy |
waf | object | OWASP 3.2 / Prevention | Mode, rule set, body limits |
ssl_certificates | map(object) | {} | Key Vault secret IDs keyed by cert name |
backend_address_pools | map(object) | — | FQDNs / IPs keyed by pool name (required) |
backend_http_settings | map(object) | — | Port/protocol/probe per settings name (required) |
probes | map(object) | {} | Custom health probes |
http_listeners | map(object) | — | Port, protocol, host(s), certificate (required) |
request_routing_rules | map(object) | — | Priority + listener → backend or redirect (required) |
redirect_configurations | map(object) | {} | e.g. HTTP→HTTPS permanent redirect |
tags | map(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).