Nayden Van
Nayden Van

Reputation: 1569

Application gateway app service access restriction

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

Answers (1)

Jim Xu
Jim Xu

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

enter image description here enter image description 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

Related Questions