0
votes

Working on project where a custom policy enforces the subnet and nsg association. If subnet doesn’t have NSG associated with it then cannot be provisioned.

Used terraform to deploy resources- resource group, VNET, NSG and before Subnet is created I created NSG associated to Subnet as part of VNET deployment,deployed an app service plan, web app and then tried doing app service virtual network swify connection but it fails because service delegation is missing.

terraform script

provider "azurerm" {
  version                    = "=2.0.0"
  skip_provider_registration = true
  features {}
}

resource "azurerm_resource_group" "main" {
  name     = var.resourceGroupName
  location = var.location
}

resource "azurerm_network_security_group" "main" {
  name                = var.nsgName
  location            = azurerm_resource_group.main.location
  resource_group_name = azurerm_resource_group.main.name
  security_rule {
    name                       = "test123"
    priority                   = 100
    direction                  = "Inbound"
    access                     = "Allow"
    protocol                   = "Tcp"
    source_port_range          = "*"
    destination_port_range     = "443"
    source_address_prefix      = "*"
    destination_address_prefix = "10.1.0.0/26"
  }
  tags = {
    environment = "NonProduction"
  }
}
data "azurerm_network_security_group" "main" {
  name                = azurerm_network_security_group.main.name
  resource_group_name = azurerm_resource_group.main.name
}

resource "azurerm_virtual_network" "main" {
  name                = var.vNetName
  location            = azurerm_resource_group.main.location
  resource_group_name = azurerm_resource_group.main.name
  address_space       = ["10.1.0.0/16"]
  dns_servers         = ["10.1.0.4", "10.1.0.5"]
  subnet {
    name           = var.subNetName
    address_prefix = "10.1.0.0/26"
    security_group = data.azurerm_network_security_group.main.id
  }
  tags = {
    environment = "NonProduction"
  }
}

resource "azurerm_app_service_plan" "main" {
  name                = var.appServicePlanName
  location            = azurerm_resource_group.main.location
  resource_group_name = azurerm_resource_group.main.name
  sku {
    tier = "Standard"
    size = "S1"
  }
}
resource "azurerm_app_service" "main" {
  name                = var.appServiceName
  location            = azurerm_resource_group.main.location
  resource_group_name = azurerm_resource_group.main.name
  app_service_plan_id = azurerm_app_service_plan.main.id
  https_only          = true
}
data "azurerm_subnet" "main" {
  name                 = var.subNetName
  virtual_network_name = var.vNetName
  resource_group_name  = azurerm_resource_group.main.name
}
resource "azurerm_app_service_virtual_network_swift_connection" "main" {
  app_service_id = azurerm_app_service.main.id
  subnet_id      = data.azurerm_subnet.main.id
}

Only thing I am unable to figure out is how to apply service delegation. I could have easily done this if the custom policy which enforces NSG before subnet creation was not there

terraform script

resource "azurerm_resource_group" "test" {
  name     = "example-resources"
  location = "uksouth"
}

resource "azurerm_virtual_network" "test" {
  name                = "acctestvnet"
  address_space       = ["10.0.0.0/16"]
  location            = azurerm_resource_group.test.location
  resource_group_name = azurerm_resource_group.test.name
}

resource "azurerm_subnet" "test1" {
  name                 = "acctestsubnet1"
  resource_group_name  = azurerm_resource_group.test.name
  virtual_network_name = azurerm_virtual_network.test.name
  address_prefix       = "10.0.1.0/24"

  delegation {
    name = "acctestdelegation"

    service_delegation {
      name    = "Microsoft.Web/serverFarms"
      actions = ["Microsoft.Network/virtualNetworks/subnets/action"]
    }
  }
}

resource "azurerm_app_service_plan" "test" {
  name                = "acctestasp"
  location            = azurerm_resource_group.test.location
  resource_group_name = azurerm_resource_group.test.name

  sku {
    tier = "Standard"
    size = "S1"
  }
}

resource "azurerm_app_service" "test" {
  name                = "acctestas"
  location            = azurerm_resource_group.test.location
  resource_group_name = azurerm_resource_group.test.name
  app_service_plan_id = azurerm_app_service_plan.test.id
}

resource "azurerm_app_service_virtual_network_swift_connection" "test" {
  app_service_id = azurerm_app_service.test.id
  subnet_id      = azurerm_subnet.test1.id
}

I could have used below tf config to set NSG association if required

resource "azurerm_subnet_network_security_group_association" "example" {
  subnet_id                 = azurerm_subnet.example.id
  network_security_group_id = azurerm_network_security_group.example.id
}

but problem with this approach is that association will happen post Subnet deployment but since custom policy is in place tf apply fails with policy violation error

Is there any way I can associate NSG before subnet creation and also apply service delegation?

1
can you share the terrafrom error you receive during the subnet creation?MoonHorse
Error creating App Service "acctestas" (Resource Group "terraform-VNET-webApp-Rg"): web.AppsClient#CreateOrUpdate: Failure sending request: StatusCode=403 -- Original Error: Code="RequestDisallowedByPolicy" Message="Resource 'acctestas' was disallowed by policy. Policy identifiers:Sudama Tripathi

1 Answers

2
votes

Since your custom policy required that the NSG needs to be associated with the subnet creation time or before the subnet is created. You have to use azurerm_virtual_network block to create the subnet and security group.

In this case, you could use local-exec Provisioner to invoke a local executable CLI command after a resource is created.

Example

resource "azurerm_virtual_network" "test" {
  name                = "acctestvnet"
  address_space       = ["10.0.0.0/16"]
  location            = azurerm_resource_group.main.location
  resource_group_name = azurerm_resource_group.main.name

 subnet {
   name = var.subnet
   address_prefix = "10.0.1.0/24"
   security_group = azurerm_network_security_group.main.id
 }

}

resource "azurerm_app_service" "test" {
  name                = "acctestas"
  location            = azurerm_resource_group.main.location
  resource_group_name = azurerm_resource_group.main.name
  app_service_plan_id = azurerm_app_service_plan.test.id

provisioner "local-exec" {
  command = "az webapp vnet-integration add --name ${azurerm_app_service.test.name} --resource-group ${azurerm_resource_group.main.name}  --vnet ${azurerm_virtual_network.test.name} --subnet ${var.subnet}"
  interpreter = ["PowerShell", "-command" ]
}

}

Result

enter image description here