When deploying modern applications to Azure, security isn’t just an afterthought—it’s baked into the architecture. In this deep dive, we’ll explore how to secure your application network using Azure’s built-in features, with a specific focus on Terraform code examples. We’ll examine how to design subnets, set up proper delegation, configure private endpoints, and leverage Azure Private Link to enable seamless, secure communication between your services—all while keeping external exposure to a minimum.
Azure’s network security blueprint includes several key components:
By configuring subnets in this manner, you’re essentially establishing “zones of trust” where only the right services are allowed. However, this comes with an important restriction: once a subnet is delegated to a specific service type, you cannot add resources like private endpoints that require unconstrained subnet access.
• Error Example:
"Private endpoint ... cannot be created as the subnet is delegated."
To address this conflict, the solution is to create a dedicated subnet exclusively for private endpoints. For example:
By isolating private endpoints in a separate subnet (in this case, subnet3), we maintain the integrity of our delegated subnets while still allowing secure, private communication between services.
Azure Private Link can be used with any Azure PaaS service, including SQL Database, Storage Accounts, App Services, and even Azure Kubernetes Service (AKS). By leveraging Private Link, you can ensure that even if all services are hosted within the same VNet, the communication between them remains secure, isolated, and compliant with regulatory standards.
These resources are straightforward but are essential for the deployment and scaling of function apps.
This Terraform code demonstrates best practices: not only are we segmenting our resources into defined subnets, but we’re also ensuring that the function apps can seamlessly communicate internally when necessary, without exposing them to unwanted external traffic.
By isolating private endpoints in their own subnet (subnet3), you ensure that these endpoints can securely connect to your function apps over Azure’s private network infrastructure via Azure Private Link. This segregation of duties within your network is a best practice that simplifies both management and troubleshooting.
As you move forward with your own deployments:
Stay curious, keep experimenting, and let your network architecture be as secure as it is scalable—and never forget that sometimes the devil (or the hacker) is in the details.
Source: Medium
Securing Your Application Network in Azure: An Overview
When you deploy an app to Azure, the last thing you want is an open door for unauthorized access. Microsoft recommends isolating your services into dedicated subnets, ensuring that each component—be it a function app, a database, or an API—is accessible only to the services that need to communicate. This approach adheres to the principle of least privilege and helps minimize the attack surface of your applications.Azure’s network security blueprint includes several key components:
- Subnets and Virtual Networks (VNets): Act as the foundational layer, setting up isolated environments.
- Subnet Delegation: Automates configuration tasks like IP allocation and routing, but comes with important caveats.
- Private Endpoints: Offer private IP connectivity for Azure services, ensuring that even if traffic is routed via the Azure backbone, it remains shielded from the public internet.
- Private Link: Bridges the gap between services using private endpoints and the actual application resources.
- DNS & Network Security Groups (NSGs): Manage internal name resolution and restrict traffic flows, respectively.
The Architecture: Segregation and Service-Specific Subnets
Subnets and Their Roles
Azure’s best practice is to isolate services into separate subnets. In our example, two distinct function apps reside in their own subnets within the same VNet. This ensures that each service is only accessible to the designated consumers. However, deploying services in isolation isn’t enough on its own—each subnet must be carefully configured to support the intended workloads.Subnet Delegation
Delegation allows Azure to automatically manage key networking rules for specific services. For instance, by delegating a subnet to an Azure service like App Service or Azure Functions, you enable Azure to:- Automatically allocate IP addresses.
- Enforce routing rules designed for that service.
- Prevent conflicts by reserving the subnet exclusively for the intended service.
- Apply service-specific policies without manual intervention.
Code:
resource "azurerm_virtual_network" "vnet" {
name = "dns-vnet"
location = azurerm_resource_group.rg.location
resource_group_name = azurerm_resource_group.rg.name
address_space = ["10.0.0.0/16"]
}
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",
]
}
}
}
resource "azurerm_subnet" "subnet2" {
name = "subnet2"
resource_group_name = azurerm_resource_group.rg.name
virtual_network_name = azurerm_virtual_network.vnet.name
address_prefixes = ["10.0.2.0/24"]
delegation {
name = "delegation"
service_delegation {
name = "Microsoft.Web/serverFarms"
actions = [
"Microsoft.Network/virtualNetworks/subnets/join/action",
"Microsoft.Network/virtualNetworks/subnets/prepareNetworkPolicies/action",
]
}
}
}
Private Endpoints and Their Requirements
A private endpoint in Azure works by assigning a private IP to an Azure service, making it accessible only within your VNet. It’s similar to assigning a NIC (network interface card) with its own IP address to that service. Despite their utility, private endpoints cannot coexist with subnet delegation when that delegation targets services such as those under Microsoft.Web/serverFarms. Attempting to place a private endpoint in a delegated subnet leads to an error:• Error Example:
"Private endpoint ... cannot be created as the subnet is delegated."
To address this conflict, the solution is to create a dedicated subnet exclusively for private endpoints. For example:
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
}
The Role of Azure Private Link
Once you’ve set up private endpoints, you need a mechanism to connect these endpoints to the actual application resources securely. This is where Azure Private Link comes into play—it facilitates a private connection between the private endpoint and the corresponding Azure service (for example, a function app). Internally, the private endpoint uses Azure’s backbone network to forward requests securely to the target, keeping traffic off the public internet.Azure Private Link can be used with any Azure PaaS service, including SQL Database, Storage Accounts, App Services, and even Azure Kubernetes Service (AKS). By leveraging Private Link, you can ensure that even if all services are hosted within the same VNet, the communication between them remains secure, isolated, and compliant with regulatory standards.
Diving into Terraform: Code Walkthrough
In our example, both function apps are deployed using Terraform with carefully structured code to ensure network security. Let’s break down the critical components:Application Components: Creating Storage and Service Plans
Before deploying function apps, we first provision a storage account and an App Service Plan. These components provide the backbone for our function apps.
Code:
# Storage account for Function Apps
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"
}
# App Service Plan for Function Apps
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"
}
Deploying Function Apps with VNet Integration
Next, we deploy two function apps that reside in two separate subnets. Notice how each function app is tied back to its respective subnet, ensuring that the applications are isolated from one another. This isolation not only promotes security but also simplifies network management and troubleshooting.
Code:
# Function App 1
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"
}
}
# Function App 2
resource "azurerm_windows_function_app" "app2" {
name = "dns-app2"
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.subnet2.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"
}
}
Configuring Dedicated Subnets for Private Endpoints
Remember the conflict between subnet delegation and private endpoints? To avoid this issue, a dedicated subnet is created specifically for private endpoints. This design decision is crucial, as it prevents configuration clashes and maintains clear boundaries between different network roles.
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
}
Testing, Troubleshooting, and Best Practices
Once you’ve deployed your environment, testing is critical. Ensure that:- Function apps in different subnets can communicate where required.
- Private endpoints correctly resolve via the Azure Private Link setup.
- NSGs (Network Security Groups) are applied as further safeguards to fine-tune access control.
- Deploying test requests via the Azure Portal and checking the flow of traffic.
- Verifying DNS resolution aligns with your private endpoints.
- Auditing NSG rules to ensure no unintended open paths exist.
Implications for Broader Cloud Security Strategies
This approach to application network security in Azure isn’t just a one-off solution—it exemplifies a broader trend in cloud infrastructure management:- Security Through Isolation: The closer you adhere to service-specific subnetting and isolation, the fewer lateral movement opportunities exist for potential attackers.
- Automation with Terraform: Leveraging Terraform for managing Azure resources ensures consistency. It reduces the incidence of human error during network configuration, which could otherwise lead to security vulnerabilities.
- Evolving Compliance Requirements: Regulatory frameworks and compliance standards often mandate rigorous access controls and network segmentation. Adopting these best practices not only improves security but also simplifies compliance efforts.
Conclusion and Next Steps
Securing application networks in Azure requires a thoughtful, well-planned approach. In our detailed walkthrough, we explored how segregating services into dedicated subnets, correctly implementing subnet delegation, and isolating private endpoints into their own subnet all contribute to a robust security posture. Azure Private Link not only bridges services securely but also ensures that private connectivity is maintained across your infrastructure.As you move forward with your own deployments:
- Review your subnet architecture to ensure resources are appropriately isolated.
- Use dedicated subnets for private endpoints to avoid conflicts with delegated subnets.
- Employ testing practices vigorously to validate that your internal communications remain secure.
Stay curious, keep experimenting, and let your network architecture be as secure as it is scalable—and never forget that sometimes the devil (or the hacker) is in the details.
Source: Medium