Managing Azure Application Gateway with Terraform
Learn how to set up and manage Azure Application Gateway using Terraform, including WAF, SSL, and routing configurations
Managing Azure Application Gateway with Terraform
Azure Application Gateway is a web traffic load balancer that enables you to manage traffic to your web applications. This guide demonstrates how to set up and manage Application Gateway using Terraform.
Video Tutorial
Learn more about managing Azure Application Gateway with Terraform in this comprehensive video tutorial:
Prerequisites
- Azure CLI configured with appropriate permissions
- Terraform installed (version 1.0.0 or later)
- Resource group created
- Understanding of networking concepts
Project Structure
terraform-azure-appgateway/
├── main.tf
├── variables.tf
├── outputs.tf
├── modules/
│ └── appgateway/
│ ├── main.tf
│ ├── variables.tf
│ └── outputs.tf
└── policies/
└── waf.json
Application Gateway Configuration
Create modules/appgateway/main.tf
:
# Application Gateway
resource "azurerm_application_gateway" "main" {
name = "${var.project_name}-appgw"
resource_group_name = var.resource_group_name
location = var.location
sku {
name = "WAF_v2"
tier = "WAF_v2"
capacity = 2
}
gateway_ip_configuration {
name = "gateway-ip-config"
subnet_id = azurerm_subnet.frontend.id
}
frontend_port {
name = "https-port"
port = 443
}
frontend_ip_configuration {
name = "frontend-ip-config"
public_ip_address_id = azurerm_public_ip.appgw.id
private_ip_address_allocation = "Dynamic"
}
backend_address_pool {
name = "backend-pool"
fqdns = var.backend_fqdns
}
backend_http_settings {
name = "https-settings"
cookie_based_affinity = "Disabled"
port = 443
protocol = "Https"
request_timeout = 60
probe_name = "health-probe"
pick_host_name_from_backend_address = true
trusted_root_certificate_names = ["root-cert"]
}
http_listener {
name = "https-listener"
frontend_ip_configuration_name = "frontend-ip-config"
frontend_port_name = "https-port"
protocol = "Https"
ssl_certificate_name = "ssl-cert"
host_names = var.host_names
require_sni = true
}
ssl_certificate {
name = "ssl-cert"
key_vault_secret_id = azurerm_key_vault_certificate.appgw.secret_id
}
trusted_root_certificate {
name = "root-cert"
key_vault_secret_id = azurerm_key_vault_certificate.root.secret_id
}
ssl_policy {
policy_type = "Predefined"
policy_name = "AppGwSslPolicy20220101"
}
probe {
name = "health-probe"
protocol = "Https"
path = "/health"
interval = 30
timeout = 30
unhealthy_threshold = 3
pick_host_name_from_backend_http_settings = true
}
url_path_map {
name = "path-map"
default_backend_address_pool_name = "backend-pool"
default_backend_http_settings_name = "https-settings"
path_rule {
name = "api-rule"
paths = ["/api/*"]
backend_address_pool_name = "api-pool"
backend_http_settings_name = "api-settings"
}
}
request_routing_rule {
name = "routing-rule"
rule_type = "PathBasedRouting"
http_listener_name = "https-listener"
url_path_map_name = "path-map"
priority = 1
}
waf_configuration {
enabled = true
firewall_mode = "Prevention"
rule_set_type = "OWASP"
rule_set_version = "3.2"
file_upload_limit_mb = 100
max_request_body_size_kb = 128
disabled_rule_group {
rule_group_name = "REQUEST-931-APPLICATION-ATTACK-RFI"
rules = [931130]
}
exclusion {
match_variable = "RequestHeaderNames"
selector = "x-company-secret-header"
selector_match_operator = "Equals"
}
}
autoscale_configuration {
min_capacity = 2
max_capacity = 10
}
zones = ["1", "2", "3"]
identity {
type = "UserAssigned"
identity_ids = [azurerm_user_assigned_identity.appgw.id]
}
tags = var.tags
}
# Public IP
resource "azurerm_public_ip" "appgw" {
name = "${var.project_name}-pip"
resource_group_name = var.resource_group_name
location = var.location
allocation_method = "Static"
sku = "Standard"
zones = ["1", "2", "3"]
tags = var.tags
}
# User Assigned Identity
resource "azurerm_user_assigned_identity" "appgw" {
name = "${var.project_name}-identity"
resource_group_name = var.resource_group_name
location = var.location
tags = var.tags
}
Network Configuration
- Virtual Network Setup
resource "azurerm_virtual_network" "main" {
name = "${var.project_name}-vnet"
resource_group_name = var.resource_group_name
location = var.location
address_space = ["10.0.0.0/16"]
subnet {
name = "frontend"
address_prefix = "10.0.1.0/24"
}
subnet {
name = "backend"
address_prefix = "10.0.2.0/24"
}
tags = var.tags
}
resource "azurerm_subnet" "frontend" {
name = "frontend"
resource_group_name = var.resource_group_name
virtual_network_name = azurerm_virtual_network.main.name
address_prefixes = ["10.0.1.0/24"]
}
resource "azurerm_subnet" "backend" {
name = "backend"
resource_group_name = var.resource_group_name
virtual_network_name = azurerm_virtual_network.main.name
address_prefixes = ["10.0.2.0/24"]
}
resource "azurerm_network_security_group" "frontend" {
name = "${var.project_name}-frontend-nsg"
location = var.location
resource_group_name = var.resource_group_name
security_rule {
name = "allow-gateway-manager"
priority = 100
direction = "Inbound"
access = "Allow"
protocol = "Tcp"
source_port_range = "*"
destination_port_range = "65200-65535"
source_address_prefix = "GatewayManager"
destination_address_prefix = "*"
}
tags = var.tags
}
Security Configuration
- SSL Certificate Management
resource "azurerm_key_vault_certificate" "appgw" {
name = "${var.project_name}-cert"
key_vault_id = var.key_vault_id
certificate_policy {
issuer_parameters {
name = "Self"
}
key_properties {
exportable = true
key_size = 2048
key_type = "RSA"
reuse_key = true
}
lifetime_action {
action {
action_type = "AutoRenew"
}
trigger {
days_before_expiry = 30
}
}
secret_properties {
content_type = "application/x-pkcs12"
}
x509_certificate_properties {
key_usage = [
"cRLSign",
"dataEncipherment",
"digitalSignature",
"keyAgreement",
"keyCertSign",
"keyEncipherment",
]
subject = "CN=${var.domain_name}"
validity_in_months = 12
subject_alternative_names {
dns_names = var.dns_names
}
}
}
}
- WAF Policy
resource "azurerm_web_application_firewall_policy" "main" {
name = "${var.project_name}-waf-policy"
resource_group_name = var.resource_group_name
location = var.location
policy_settings {
enabled = true
mode = "Prevention"
request_body_check = true
file_upload_limit_in_mb = 100
max_request_body_size_in_kb = 128
}
managed_rules {
managed_rule_set {
type = "OWASP"
version = "3.2"
}
}
custom_rules {
name = "BlockCountry"
priority = 1
rule_type = "MatchRule"
action = "Block"
match_conditions {
match_variables {
variable_name = "RemoteAddr"
}
operator = "GeoMatch"
negation_condition = false
match_values = ["CN", "RU"]
}
}
tags = var.tags
}
Monitoring Configuration
- Diagnostic Settings
resource "azurerm_monitor_diagnostic_setting" "appgw" {
name = "${var.project_name}-diag"
target_resource_id = azurerm_application_gateway.main.id
log_analytics_workspace_id = var.log_analytics_workspace_id
log {
category = "ApplicationGatewayAccessLog"
enabled = true
retention_policy {
enabled = true
days = 30
}
}
log {
category = "ApplicationGatewayPerformanceLog"
enabled = true
retention_policy {
enabled = true
days = 30
}
}
metric {
category = "AllMetrics"
enabled = true
retention_policy {
enabled = true
days = 30
}
}
}
resource "azurerm_monitor_metric_alert" "appgw" {
name = "${var.project_name}-health-alert"
resource_group_name = var.resource_group_name
scopes = [azurerm_application_gateway.main.id]
description = "Alert when unhealthy host count is high"
criteria {
metric_namespace = "Microsoft.Network/applicationGateways"
metric_name = "UnhealthyHostCount"
aggregation = "Average"
operator = "GreaterThan"
threshold = 0
}
action {
action_group_id = var.action_group_id
}
}
Best Practices
-
Performance
- Enable autoscaling
- Configure zones
- Use health probes
- Optimize SSL policy
-
Security
- Enable WAF
- Use SSL everywhere
- Implement custom rules
- Configure network isolation
-
High Availability
- Use multiple zones
- Configure health probes
- Implement backup pools
- Monitor health metrics
-
Cost Optimization
- Monitor usage
- Optimize rules
Conclusion
You’ve learned how to set up and manage Azure Application Gateway using Terraform. This setup provides:
- Layer 7 load balancing
- SSL termination
- WAF protection
- URL-based routing
Remember to:
- Monitor performance
- Review security rules
- Update SSL certificates
- Maintain health probes