Securing your applications in Azure is more than just deploying code—it's about building a robust network architecture that ensures services communicate safely while remaining isolated from unwanted external access. In this deep dive, we explore how to use Terraform to implement a layered network security approach in Azure by leveraging subnets, subnet delegation, private endpoints, DNS, and network security groups (NSGs).
In our sample architecture, we have two services—each represented as a Windows Function App—that need to communicate with one another. By placing them in separate subnets, we ensure controlled and secure communication. The approach starts with core resources such as a storage account and a service plan, then moves into app deployments via Terraform.
• A storage account for holding application data
• A service plan that supports the Windows Function Apps
• Two Function Apps (app1 and app2), each assigned its own subnet within a vNet
Here’s an abbreviated version of the Terraform code used to deploy these resources:
The code for app2 follows a similar pattern, but with its subnet reference adjusted accordingly. This illustrates not just resource creation but also the importance of properly assigning network segments to each service.
The Terraform code to add delegation to a subnet is straightforward. For example, here’s how you delegate a subnet for your Function Apps:
By delegating a subnet to Microsoft.Web/serverFarms, you ensure that Azure manages the networking aspects for resources like App Service Plans and Function Apps automatically.
However, a challenge emerges if you attempt to place private endpoints directly into a subnet that’s already delegated for a particular service. Azure won’t allow this, and you might encounter an error like:
"Private endpoint cannot be created as subnet … is delegated."
This error occurs because the subnet is reserved exclusively for the delegated service (in this case, Microsoft.Web/serverFarms). The takeaway? Separate subnets for delegated resources and private endpoints are a must.
By isolating your private endpoints on a dedicated subnet (subnet3), you avoid any interference with the subnet delegation rules for your Function Apps. This separation reinforces security boundaries and simplifies network management—a practice that aligns with the zero-trust principle.
With Private Link, you can:
• Access PaaS services—such as Storage Accounts, App Services, and Azure SQL—via a private IP address
• Keep traffic off the public Internet, drastically reducing exposure to potential attacks
• Simplify network routing and improve governance by consolidating network policies
This model fits seamlessly with the idea of separating duties via dedicated subnets, where one subnet handles delegated app services and another handles private endpoint connectivity.
• Configure Private DNS Zones to ensure that your private endpoints resolve correctly without leaking to the public DNS
• Implement NSGs to enforce granular traffic rules, both inbound and outbound, on your subnets
• Create A records linking your private IP addresses to internal domain names, further streamlining and securing communications
By integrating these elements, you create a robust security model where every piece of network communication is scrutinized and allowed only if it meets predetermined criteria. This layered approach forms the backbone of a truly secure application landscape on Azure.
Automation with Terraform isn’t just about speed; it’s about discipline. It forces you to adhere to best practices by eliminating ad hoc manual configurations. In a world where cybersecurity threats are evolving rapidly, having your infrastructure defined and auditable in code adds an extra layer of trust.
• Segregate application services into dedicated subnets for maximal isolation
• Use subnet delegation to offload network management to Azure for specific services
• Avoid conflicts by placing private endpoints within their own isolated subnet
• Leverage Azure Private Link to ensure service-to-service communication remains secure
• Harden your network further with properly configured NSGs and Private DNS zones
• Automate your network setup with Terraform to enforce consistency and security across deployments
As you refine your architecture, it’s worth questioning the traditional “one-size-fits-all” approach to cloud networking. Could further separation of duties or a refined NSG rule set add another layer of security? The answer often lies in the unique demands of your applications and their threat profiles.
This approach underlines that a secure network is not simply an off-the-shelf feature; it’s built through deliberate design choices that balance convenience, isolation, and strict access control. The sample code and configuration techniques we discussed serve as a comprehensive blueprint for those looking to secure their Azure applications while maintaining the agility needed for modern cloud deployments.
For Windows administrators and cloud professionals alike, applying these concepts can dramatically improve the resilience of your applications, keeping your data and services secure while ensuring seamless internal connectivity. As always, feedback and discussions are encouraged—your insights could be the next step in evolving these best practices further.
Source: Medium
The Philosophy of Network Segmentation in Azure
Microsoft’s best practices emphasize isolating each component of your application by deploying them into separate subnets within a virtual network (vNet). This segmentation means that each service only interacts with the entities it absolutely needs to. Not only does this reduce the attack surface, but it also simplifies both monitoring and management.In our sample architecture, we have two services—each represented as a Windows Function App—that need to communicate with one another. By placing them in separate subnets, we ensure controlled and secure communication. The approach starts with core resources such as a storage account and a service plan, then moves into app deployments via Terraform.
Deploying Azure Resources with Terraform
Let’s break down the Terraform code that initiates the deployment. The process begins by creating essential Azure resources:• A storage account for holding application data
• A service plan that supports the Windows Function Apps
• Two Function Apps (app1 and app2), each assigned its own subnet within a vNet
Here’s an abbreviated version of the Terraform code used to deploy these resources:
Code:
resource "azurerm_storage_account" "sa1" {
name = "dnsexamplesa"
resource_group_name = azurerm_resource_group.rg.name
location = azurerm_resource_group.rg.location
account_tier = "Standard"
account_replication_type = "LRS"
}
resource "azurerm_service_plan" "asp" {
name = "dns-asp"
resource_group_name = azurerm_resource_group.rg.name
location = azurerm_resource_group.rg.location
os_type = "Windows"
sku_name = "P1v2"
}
resource "azurerm_windows_function_app" "app1" {
name = "dns-app1"
resource_group_name = azurerm_resource_group.rg.name
location = azurerm_resource_group.rg.location
storage_account_name = azurerm_storage_account.sa1.name
storage_account_access_key = azurerm_storage_account.sa1.primary_access_key
service_plan_id = azurerm_service_plan.asp.id
virtual_network_subnet_id = azurerm_subnet.subnet1.id
site_config {
application_stack {
dotnet_version = "v8.0"
}
cors {
allowed_origins = ["[Microsoft Azure](https://portal.azure.com)"]
support_credentials = true
}
}
app_settings = {
"WEBSITE_RUN_FROM_PACKAGE" = "1"
"WEBSITE_USE_PLACEHOLDER_DOTNETISOLATED" = "1"
}
}
Understanding Subnet Delegation
One of the key elements in this architecture is subnet delegation. Subnet delegation in Azure allows you to dedicate a subnet to a specific service (for example, Azure App Services). Delegation helps automate functions like IP allocation, routing, conflict prevention, and policy application. Essentially, Azure applies service-specific rules to the subnet, ensuring that resources within it adhere to best practices without manual interference.The Terraform code to add delegation to a subnet is straightforward. For example, here’s how you delegate a subnet for your Function Apps:
Code:
resource "azurerm_subnet" "subnet1" {
name = "subnet1"
resource_group_name = azurerm_resource_group.rg.name
virtual_network_name = azurerm_virtual_network.vnet.name
address_prefixes = [ "10.0.1.0/24" ]
delegation {
name = "delegation"
service_delegation {
name = "Microsoft.Web/serverFarms"
actions = [
"Microsoft.Network/virtualNetworks/subnets/join/action",
"Microsoft.Network/virtualNetworks/subnets/prepareNetworkPolicies/action"
]
}
}
}
The Private Endpoint Conundrum
Once your applications are part of their respective subnets, the next puzzle is secure connectivity between them. That’s where private endpoints come into play. A private endpoint assigns a private IP address from your virtual network to a resource, functioning much like a network interface card (NIC). Under the hood, Azure creates this NIC and attaches it to the private endpoint, facilitating internal communication over the Azure backbone.However, a challenge emerges if you attempt to place private endpoints directly into a subnet that’s already delegated for a particular service. Azure won’t allow this, and you might encounter an error like:
"Private endpoint cannot be created as subnet … is delegated."
This error occurs because the subnet is reserved exclusively for the delegated service (in this case, Microsoft.Web/serverFarms). The takeaway? Separate subnets for delegated resources and private endpoints are a must.
Creating Dedicated Subnets for Private Endpoints
To work around the conflict mentioned above, you need to provision a dedicated subnet for private endpoints. Here’s how you can update your Terraform code:
Code:
resource "azurerm_subnet" "subnet3" {
name = "subnet3"
resource_group_name = azurerm_resource_group.rg.name
virtual_network_name = azurerm_virtual_network.vnet.name
address_prefixes = [ "10.0.3.0/24" ]
}
resource "azurerm_private_endpoint" "app1_pe" {
name = "app1-pe"
location = azurerm_resource_group.rg.location
resource_group_name = azurerm_resource_group.rg.name
subnet_id = azurerm_subnet.subnet3.id
}
resource "azurerm_private_endpoint" "app2_pe" {
name = "app2-pe"
location = azurerm_resource_group.rg.location
resource_group_name = azurerm_resource_group.rg.name
subnet_id = azurerm_subnet.subnet3.id
}
Bridging Communication with Azure Private Link
Even though private endpoints assign internal IP addresses, they need a way to direct traffic securely to the application. This is exactly where Azure Private Link comes into play. Private Link creates a secure connection between your private endpoint and the target Azure service (such as your Function App) over the Azure backbone network. Essentially, while the private endpoint serves as a door, Private Link acts as the secure corridor ensuring that requests remain within the trusted network pathway.With Private Link, you can:
• Access PaaS services—such as Storage Accounts, App Services, and Azure SQL—via a private IP address
• Keep traffic off the public Internet, drastically reducing exposure to potential attacks
• Simplify network routing and improve governance by consolidating network policies
This model fits seamlessly with the idea of separating duties via dedicated subnets, where one subnet handles delegated app services and another handles private endpoint connectivity.
DNS, NSGs, and Further Hardening
While our focus so far has been on segmentation and private connectivity, comprehensive network security often involves additional facets such as DNS configuration and network security groups. In a fully hardened environment, you would need to:• Configure Private DNS Zones to ensure that your private endpoints resolve correctly without leaking to the public DNS
• Implement NSGs to enforce granular traffic rules, both inbound and outbound, on your subnets
• Create A records linking your private IP addresses to internal domain names, further streamlining and securing communications
By integrating these elements, you create a robust security model where every piece of network communication is scrutinized and allowed only if it meets predetermined criteria. This layered approach forms the backbone of a truly secure application landscape on Azure.
Automating Secure Infrastructure with Terraform
Terraform brings immense value by codifying your infrastructure as code (IaC). This approach promotes repeatability, transparency, and version control. When you script out your network security constructs—subnets, delegation, private endpoints, DNS configurations, and NSGs—you reduce the risk of human error and ensure that every deployment complies with your organization’s security policies.Automation with Terraform isn’t just about speed; it’s about discipline. It forces you to adhere to best practices by eliminating ad hoc manual configurations. In a world where cybersecurity threats are evolving rapidly, having your infrastructure defined and auditable in code adds an extra layer of trust.
Lessons Learned and Best Practices
Drawing from the architecture and code examples discussed, here are some best practices every Windows and cloud administrator should incorporate:• Segregate application services into dedicated subnets for maximal isolation
• Use subnet delegation to offload network management to Azure for specific services
• Avoid conflicts by placing private endpoints within their own isolated subnet
• Leverage Azure Private Link to ensure service-to-service communication remains secure
• Harden your network further with properly configured NSGs and Private DNS zones
• Automate your network setup with Terraform to enforce consistency and security across deployments
As you refine your architecture, it’s worth questioning the traditional “one-size-fits-all” approach to cloud networking. Could further separation of duties or a refined NSG rule set add another layer of security? The answer often lies in the unique demands of your applications and their threat profiles.
Conclusion
Deploying a secure application in Azure involves a confluence of best practices—from carefully segmenting your network with subnets and subnet delegation to ensuring private endpoints and Azure Private Link work harmoniously. By leveraging Terraform, you not only accelerate the deployment process but also enforce a disciplined, repeatable, and auditable security model.This approach underlines that a secure network is not simply an off-the-shelf feature; it’s built through deliberate design choices that balance convenience, isolation, and strict access control. The sample code and configuration techniques we discussed serve as a comprehensive blueprint for those looking to secure their Azure applications while maintaining the agility needed for modern cloud deployments.
For Windows administrators and cloud professionals alike, applying these concepts can dramatically improve the resilience of your applications, keeping your data and services secure while ensuring seamless internal connectivity. As always, feedback and discussions are encouraged—your insights could be the next step in evolving these best practices further.
Source: Medium