I am looking for the best way to implement load balancing (including redirection between multiple app services based on URL path) with App Services. This is what I have right now:
# App Service Plan
resource "azurerm_app_service_plan" "frontend" {
name = "${local.prefix}-frontend-asp"
location = azurerm_resource_group.frontend.location
resource_group_name = azurerm_resource_group.frontend.name
kind = "Linux"
reserved = true
app_service_environment_id = azurerm_app_service_environment_v3.frontend.id
sku {
tier = "Standard"
size = "S1"
}
}
# Environment
resource "azurerm_app_service_environment_v3" "frontend" {
name = "${local.prefix}-frontend-env"
resource_group_name = azurerm_resource_group.frontend.name
subnet_id = azurerm_subnet.frontend.id
cluster_setting {
name = "DisableTls1.0"
value = "1"
}
cluster_setting {
name = "InternalEncryption"
value = "true"
}
cluster_setting {
name = "FrontEndSSLCipherSuiteOrder"
value = "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256"
}
tags = {
env = "production"
terraformed = "true"
}
}
# Main App Service
resource "azurerm_app_service" "frontend" {
name = "${local.prefix}-frontend-app"
location = azurerm_resource_group.frontend.location
resource_group_name = azurerm_resource_group.frontend.name
app_service_plan_id = azurerm_app_service_plan.frontend.id
site_config {
linux_fx_version = "NODE|14"
app_command_line = "pm2 serve /home/site/wwwroot --no-daemon --spa"
}
app_settings = local.front_env_variables
}
[I am using app_service_environment_id = azurerm_app_service_environment_v3.frontend.id
as the best way of having App Service inside a Subnet controlled by me, to be able to control basic security via Network Security Group. I found out that azurerm_app_service_virtual_network_swift_connection
is not really what I need since it only allows App Service to talk to other resources inside a particular subnet, not necessairly does it place an App Service in the subnet per se. Correct me if I'm wrong.]
# Resource Group
resource "azurerm_resource_group" "networking" {
name = "${local.prefix}-networking-rg"
location = local.location
provider = azurerm.uat
}
# Virtual Network
resource "azurerm_virtual_network" "vnet" {
name = "${local.prefix}-vnet"
location = azurerm_resource_group.networking.location
resource_group_name = azurerm_resource_group.networking.name
address_space = ["10.1.0.0/16"]
tags = {
environment = local.prefix
}
}
# Subnets for App Service instances
resource "azurerm_subnet" "frontend" {
name = "frontend-app"
resource_group_name = azurerm_resource_group.networking.name
virtual_network_name = azurerm_virtual_network.vnet.name
address_prefixes = ["10.1.1.0/24"]
delegation {
name = "delegation"
service_delegation {
name = "Microsoft.Web/hostingEnvironments"
actions = ["Microsoft.Network/virtualNetworks/subnets/action"]
}
}
}
# Route tables
resource "azurerm_route_table" "local" {
name = "local"
location = azurerm_resource_group.networking.location
resource_group_name = azurerm_resource_group.networking.name
disable_bgp_route_propagation = false
route {
name = "route1"
address_prefix = "10.1.0.0/16"
next_hop_type = "vnetlocal"
}
tags = {
environment = "uat"
}
}
resource "azurerm_subnet_route_table_association" "frontend" {
subnet_id = azurerm_subnet.frontend.id
route_table_id = azurerm_route_table.local.id
}
# Frontend App Security
resource "azurerm_network_security_group" "frontend" {
name = "${local.prefix}-frontend-sg"
location = azurerm_resource_group.frontend.location
resource_group_name = azurerm_resource_group.frontend.name
security_rule {
name = "test123"
priority = 100
direction = "Inbound"
access = "Allow"
protocol = "Tcp"
source_port_range = "*"
destination_port_range = "*"
source_address_prefix = "*"
destination_address_prefix = "*"
}
}
resource "azurerm_subnet_network_security_group_association" "frontend" {
subnet_id = azurerm_subnet.frontend.id
network_security_group_id = azurerm_network_security_group.frontend.id
}
[So what I am trying to do above is to make sure that App Service is in the private subnet (with no access from internet) and controlled by Security Group rule. I am coming from AWS world and this is the most logical setup to achieve it for me. Please correct me if I'm wrong again.]
Now, I want to have internet-facing Load Balancer (or Application Gateway) to gather the traffic based on the URL path or port, and then to route it to the correct App Service (which itself is in the private subnet). And I have no idea what's the best practice there.
This is the piece of code I have at the moment:
# Public IP
resource "azurerm_public_ip" "agw" {
name = "${local.prefix}-agw-pip"
location = azurerm_resource_group.agw.location
resource_group_name = azurerm_resource_group.agw.name
allocation_method = "Static"
sku = "Standard"
tags = azurerm_resource_group.agw.tags
}
# Application Gateway
resource "azurerm_application_gateway" "agw" {
name = "${local.prefix}-agw"
location = azurerm_resource_group.agw.location
resource_group_name = azurerm_resource_group.agw.name
sku {
name = "WAF_Medium"
tier = "WAF"
capacity = 2
}
waf_configuration {
enabled = "true"
firewall_mode = "Detection"
rule_set_type = "OWASP"
rule_set_version = "3.0"
}
gateway_ip_configuration {
name = "subnet"
subnet_id = <to be created>
}
frontend_port {
name = "http"
port = 80
}
frontend_ip_configuration {
name = "frontend"
public_ip_address_id = "${azurerm_public_ip.agw.id}"
}
backend_address_pool {
name = "AppService"
"fqdn_list" = ["${azurerm_app_service.frontend.name}.azurewebsites.net"]
}
http_listener {
name = "http"
frontend_ip_configuration_name = "frontend"
frontend_port_name = "http"
protocol = "Http"
}
probe {
name = "probe"
protocol = "http"
path = "/"
host = "${azurerm_app_service.frontend.name}.azurewebsites.net"
interval = "30"
timeout = "30"
unhealthy_threshold = "3"
}
backend_http_settings {
name = "http"
cookie_based_affinity = "Disabled"
port = 80
protocol = "Http"
request_timeout = 1
probe_name = "probe"
}
request_routing_rule {
name = "http"
rule_type = "Basic"
http_listener_name = "http"
backend_address_pool_name = "AppService"
backend_http_settings_name = "http"
}
}
But I have no idea how to "connect" this Application Gateway with the App Services, and if it's all right to have it along with App Service Environment.