Reputation: 1569
I have implemented a application gateway in azure using terraform.
My terraform code builds up a vent,application gateway, subnet,app service and app service plan.
Everything works just fine, and I am able to access the app service using the application gateway public ip. The only problem is that I can access the app service from its own endpoint too, and I would like to restrict this access only throu my application gateway, so if somebody tried to access the app service directly, it should get a 403
error.
Doing some research, I managed to achieve this from the terminal >> app service >> Networking
But I would like to automate this process with terraform. and here is were I am stuck.
Because the only source I found refers to "azurerm_app_service_slot_virtual_network_swift_connection"
but that resource requires a app service slot which I don't want or need.
I was wondering, how can I implement the Networking access restriction to the app service?
here is my code and how I am building my infra:
networking.tf
locals {
cidr_block = "<cidr>"
subnets = {
frontend = cidrsubnet(local.cidr_block, 8, 0)
}
}
#########################################
# RESOURCE GROUP
#########################################
resource "azurerm_resource_group" "example" {
name = "rg-hri-prd-app-gateway"
location = "West US"
}
#########################################
# VIRTUAL NETWORK
#########################################
resource "azurerm_virtual_network" "example" {
name = "hri-prd-vnet"
resource_group_name = azurerm_resource_group.example.name
location = azurerm_resource_group.example.location
address_space = [local.cidr_block]
}
#########################################
# SUBNETS
#########################################
resource "azurerm_subnet" "example" {
count = length(keys(local.subnets))
name = keys(local.subnets)[count.index]
resource_group_name = azurerm_resource_group.example.name
virtual_network_name = azurerm_virtual_network.example.name
address_prefixes = [local.subnets[keys(local.subnets)[count.index]]]
service_endpoints = ["Microsoft.Web"]
delegation {
name = "my-access-delegation"
service_delegation {
name = "Microsoft.Web/serverFarms"
actions = ["Microsoft.Network/virtualNetworks/subnets/action"]
}
}
}
resource "azurerm_app_service_virtual_network_swift_connection" "appservice-subnet" {
count = length(azurerm_app_service.example)
app_service_id = azurerm_app_service.example[count.index].id
subnet_id = azurerm_subnet.example[count.index].id
}
app.tf
locals {
app_services = [
{
kind = "Linux"
sku = {
tier = "Standard"
size = "S1"
}
}
]
}
#########################################
# APP SERVICE PLAN
#########################################
resource "azurerm_app_service_plan" "example" {
count = length(local.app_services)
name = "${lower(local.app_services[count.index].kind)}-asp"
location = azurerm_resource_group.example.location
resource_group_name = azurerm_resource_group.example.name
kind = local.app_services[count.index].kind
reserved = true
sku {
tier = local.app_services[count.index].sku.tier
size = local.app_services[count.index].sku.size
}
}
#########################################
# APP SERVICE PLAN
#########################################
resource "azurerm_app_service" "example" {
count = length(local.app_services)
name = "${lower(local.app_services[count.index].kind)}-appservice"
location = azurerm_resource_group.example.location
resource_group_name = azurerm_resource_group.example.name
app_service_plan_id = azurerm_app_service_plan.example[count.index].id
}
gateway.tf
locals {
backend_probe_name = "${azurerm_virtual_network.example.name}-health"
http_setting_name = "${azurerm_virtual_network.example.name}-htst"
public_ip_name = "${azurerm_virtual_network.example.name}-public"
}
#########################################
# AZURE PUBLIC IP
#########################################
resource "azurerm_public_ip" "example" {
name = local.public_ip_name
resource_group_name = azurerm_resource_group.example.name
location = azurerm_resource_group.example.location
allocation_method = "Dynamic"
}
#########################################
# APPLICT
#########################################
resource "azurerm_application_gateway" "network" {
depends_on = [azurerm_public_ip.example]
name = "hri-prd-appgateway"
resource_group_name = azurerm_resource_group.example.name
location = azurerm_resource_group.example.location
sku {
name = "Standard_Small"
tier = "Standard"
capacity = 2
}
gateway_ip_configuration {
name = "my-gateway-ip-configuration"
subnet_id = azurerm_subnet.example.0.id
}
dynamic "frontend_port" {
for_each = azurerm_app_service.example
content {
name = "${azurerm_virtual_network.example.name}-${frontend_port.value.name}-feport"
port = "808${frontend_port.key}"
}
}
frontend_ip_configuration {
name = "${azurerm_virtual_network.example.name}-feip"
public_ip_address_id = azurerm_public_ip.example.id
}
dynamic "backend_address_pool" {
for_each = azurerm_app_service.example
content {
name = "${azurerm_virtual_network.example.name}-${backend_address_pool.value.name}-beap"
fqdns = [backend_address_pool.value.default_site_hostname]
}
}
probe {
name = local.backend_probe_name
protocol = "Http"
path = "/"
interval = 30
timeout = 120
unhealthy_threshold = 3
pick_host_name_from_backend_http_settings = true
match {
body = "Welcome"
status_code = [200, 399]
}
}
backend_http_settings {
name = local.http_setting_name
probe_name = local.backend_probe_name
cookie_based_affinity = "Disabled"
path = "/"
port = 80
protocol = "Http"
request_timeout = 120
pick_host_name_from_backend_address = true
}
dynamic "http_listener" {
for_each = azurerm_app_service.example
content {
name = "${azurerm_virtual_network.example.name}-${http_listener.value.name}-httplstn"
frontend_ip_configuration_name = "${azurerm_virtual_network.example.name}-feip"
frontend_port_name = "${azurerm_virtual_network.example.name}-${http_listener.value.name}-feport"
protocol = "Http"
}
}
dynamic "request_routing_rule" {
for_each = azurerm_app_service.example
content {
name = "${azurerm_virtual_network.example.name}-${request_routing_rule.value.name}-rqrt"
rule_type = "Basic"
http_listener_name = "${azurerm_virtual_network.example.name}-${request_routing_rule.value.name}-httplstn"
backend_address_pool_name = "${azurerm_virtual_network.example.name}-${request_routing_rule.value.name}-beap"
backend_http_settings_name = local.http_setting_name
}
}
}
Please if anyone can help to understand how to achieve this bit with terraform.
EDIT:
I updated my network code with the azure_app_service_network_swift_connection
but when I run terraform, I get the following error:
Error: creating/updating Application Gateway: (Name "hri-prd-appgateway" / Resource Group "rg-hri-prd-app-gateway"): network.ApplicationGatewaysClient#CreateOrUpdate: Failure sending request: StatusCode=0 -- Original Error: Code="ResourceNotPermittedOnDelegatedSubnet" Message="Resource /subscriptions/<subscription>/resourceGroups/rg-hri-prd-app-gateway/providers/Microsoft.Network/applicationGateways/hri-prd-appgateway cannot be created in or updated to use the subnet /subscriptions/<subscription>/resourceGroups/rg-hri-prd-app-gateway/providers/Microsoft.Network/virtualNetworks/hri-prd-vnet/subnets/frontend since it has delegation(s) [Microsoft.Web/serverFarms: /subscriptions/<subscription>/resourceGroups/rg-hri-prd-app-gateway/providers/Microsoft.Network/virtualNetworks/hri-prd-vnet/subnets/frontend/delegations/my-access-delegation] to external services." Details=[]
on gateway.tf line 22, in resource "azurerm_application_gateway" "network":
22: resource "azurerm_application_gateway" "network" {
Upvotes: 1
Views: 1654
Reputation: 23121
If you want to restrict the web app so that it only receives traffic from the application gateway, one way is to use Azure App Service static IP restrictions. After using the way, if the address isn't allowed access based on the rules in the list, the service replies with an HTTP 403 status code For more details, please refer to here and here
Regarding how to implement it with terraform, please refer to the following script
site_config {
...
always_on = true
ip_restriction {
ip_address = ""
priority=
}
# etc.
For further information about it, please refer to here and here
Upvotes: 1