title | author | date | tags | summary | ||||||
---|---|---|---|---|---|---|---|---|---|---|
Azure Virtual Networking Module |
Matt Braunwart |
2024-01-24 |
|
Terraform module for deploying and managing Azure Virtual Networks with integrated DNS zones and network peering capabilities |
This Terraform module provides an enterprise-ready framework for creating and managing secure, scalable, and compliant Azure Virtual Networks (VNets). It simplifies the deployment of networking components, integrates with Azure DNS and security features, and supports various connectivity models for both cloud-only and hybrid scenarios.
The module’s main objective is to streamline the provisioning of Azure networking resources, ensuring they adhere to organizational standards for security and reliability. By packaging best practices into a reusable Terraform module, it reduces the overhead typically associated with large-scale or multi-environment VNet deployments.
-
Configurable Network Security Groups (NSGs)
Enforce default deny-all rules and introduce granular inbound/outbound control to align with zero-trust security principles. -
Private DNS Zone Integration
Seamlessly create and link private DNS zones to VNets for internal name resolution, supporting cross-region and cross-subscription scenarios. -
Hub and Spoke or VHUB Peering
Establish hub-and-spoke network topologies or connect to Azure Virtual WAN for centralized network management and traffic routing. -
Azure Monitor and Logging Support
Stream diagnostic logs and metrics to Azure Monitor and Log Analytics to capture traffic flows, NSG hits, and gateway diagnostics.
Beneath the surface, this module applies a “security-by-default” philosophy. Every subnet is created with an NSG that denies all inbound and outbound traffic unless explicitly permitted. Private endpoints can be deployed to securely connect to Azure PaaS services, while integrated private DNS ensures name resolution remains internal. Users can customize these behaviors through input variables, allowing the module to fit a broad range of enterprise requirements.
The module supports traditional hub-and-spoke designs, where spokes isolate workloads while sharing centralized services in the hub, as well as mesh architectures that provide direct connectivity among all VNets. In hybrid scenarios, you can add an ExpressRoute or VPN Gateway to your network for secure connections to on-premises environments. To further simplify connectivity, the module can attach to Azure Virtual WAN when global or large-scale connectivity is needed.
When deploying multiple VNets, plan out IP address ranges to avoid overlap, especially across different subscriptions or on-premises networks. Use Azure Policy to enforce tagging and logging standards so resources remain consistent. Apply role-based access control (RBAC) to minimize the blast radius of changes, and leverage Log Analytics for detailed monitoring. Finally, adopt the Azure Well-Architected Framework to guide decisions on performance, security, operational excellence, reliability, and cost optimization.
Diagnostics can be configured to route logs to Log Analytics, Azure Storage, or Event Hubs. This includes flow logs for each NSG, which record traffic details and rule matches. By centralizing logs in Azure Monitor, you gain real-time visibility and can create actionable alerts that help teams respond quickly to network anomalies or security incidents.
Overlapping IP address spaces in complex networks may require additional planning. Cross-subscription deployments can fail without proper RBAC permissions. Latency in multi-region VNet peering depends on Azure’s global backbone, affecting highly latency-sensitive workloads. Lastly, ensure subscription and service quotas (e.g., number of VNets or peering links) are sufficient for large-scale rollouts.
module "vnet_advanced" {
source = "github.com/example/terraform-azurerm-network"
providers = {
azurerm.prod = azurerm.prod
azurerm.shared = azurerm.shared
azurerm = azurerm
}
resource_group_name = "rg-advanced-network"
vnet_name = "vnet-advanced"
vnet_address_prefixes = ["10.2.0.0/16"]
subnets = [
{
name = "snet-web"
address_prefixes = ["10.2.1.0/24"]
service_endpoints = ["Microsoft.Storage"]
},
{
name = "snet-db"
address_prefixes = ["10.2.2.0/24"]
delegation = {
name = "db-delegation"
service_delegation = {
name = "Microsoft.Sql/servers"
actions = ["Microsoft.Network/virtualNetworks/subnets/action"]
}
}
}
]
log_analytics_workspace_id = "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/log-analytics/providers/Microsoft.OperationalInsights/workspaces/loganalytics"
}
The following requirements are needed by this module:
- azurerm (>= 4.12.0)
The following providers are used by this module:
-
azurerm (>= 4.12.0)
-
azurerm.prod (>= 4.12.0)
-
azurerm.shared (>= 4.12.0)
The following resources are used by this module:
- azurerm_network_security_group.nsg (resource)
- azurerm_private_dns_zone.sub_z (resource)
- azurerm_private_dns_zone_virtual_network_link.dns_link (resource)
- azurerm_public_ip.pip (resource)
- azurerm_subnet.snet (resource)
- azurerm_subnet_network_security_group_association.nsg_association (resource)
- azurerm_virtual_hub_connection.conn (resource)
- azurerm_virtual_network.vnet (resource)
- azurerm_virtual_network_peering.remote_to_source_prod (resource)
- azurerm_virtual_network_peering.remote_to_source_shared (resource)
- azurerm_virtual_network_peering.source_to_remote (resource)
The following input variables are required:
Description: (Required) The environment identifier (e.g., 'dev', 'staging', 'prod'). Used for resource naming convention and environment-specific configurations.
Type: string
Description: (Optional) Map of Public IP configurations to create alongside the Virtual Network.
Properties for each Public IP:
- name : (Required) Name of the Public IP resource
- sku : (Required) SKU of the Public IP (Basic or Standard)
- allocation_method : (Required) IP allocation method (Static or Dynamic)
Note: Standard SKU is required when using with Standard Load Balancer
Type:
map(object({
allocation_method = string
sku = string
name = string
}))
Description: (Required) The name of the Azure Resource Group where the Virtual Network and related resources will be deployed. This resource group must exist before deployment.
Type: string
Description: (Required) Name of the resource group containing shared resources. This resource group is used for Private DNS zones and must exist in the subscription referenced by the 'azurerm.shared' provider.
Type: string
Description: (Required) List of address spaces in CIDR notation for the Virtual Network.
Example: ["10.0.0.0/16", "172.16.0.0/12"]
Ensure these ranges:
- Don't overlap with existing network ranges
- Provide sufficient IP space for current and future needs
- Comply with your organization's IP addressing scheme
Type: list(string)
Description: (Required) The name of the Virtual Network to be created. Should follow your organization's naming convention and clearly identify the network's purpose and environment.
Type: string
The following input variables are optional (have default values):
Description: (Optional) Controls whether to create a Private DNS Zone for the Virtual Network. Enable this for private DNS resolution capabilities within the VNet and across peered networks.
Type: bool
Default: false
Description: (Optional) Controls creation of a connection between this VNet and an Azure Virtual WAN hub. Enable for integration with Azure Virtual WAN architecture.
Type: bool
Default: false
Description: (Optional) Number of days to retain diagnostic logs (0-365). Set to 0 for infinite retention. Helps manage compliance and audit requirements while controlling storage costs.
Type: number
Default: 30
Description: (Optional) Resource ID of an existing Private DNS Zone to link with this Virtual Network. This variable is required if create_dns_zone is false and DNS integration is needed.
Type: string
Default: null
Description: (Optional) The DNS subdomain name for the private DNS zone (e.g., "prod.internal.contoso.com").
Required when create_dns_zone is true.
Must be:
- A valid DNS name format
- Unique within your DNS hierarchy
- Compliant with your organization's naming standards
Type: string
Default: ""
Description: (Optional) Custom DNS server IP address for the Virtual Network. When specified, this IP will be configured as the primary DNS server for name resolution within the VNet.
Type: string
Default: null
Description: (Optional) The Azure region where the Virtual Network and associated resources will be created. Defaults to East US if not specified. Should align with your organization's region strategy.
Type: string
Default: "East US"
Description: (Optional) The resource ID of the Log Analytics workspace for diagnostic settings. Required for centralized logging and monitoring of network traffic and events.
Type: string
Default: null
Description: (Optional) List of Virtual Networks to peer with this VNet. Supports both hub-spoke and mesh topologies.
Each peering configuration requires:
- resource_group_name : (Required) Resource group containing the remote VNet
- name : (Required) Name of the remote VNet
- id : (Required) Resource ID of the remote VNet
- source : (Optional) Outbound peering configuration
- allow_gateway_transit : (Optional) Allow gateway transit, defaults to true
- allow_forwarded_traffic : (Optional) Allow forwarded traffic, defaults to true
- use_remote_gateways : (Optional) Use remote gateways, defaults to true
- triggers : (Optional) Map of values that trigger peering updates
- remote : (Optional) Inbound peering configuration
- Same options as source, plus:
- provider : (Optional) Provider alias for remote VNet (prod or shared)
Type:
list(object({
resource_group_name = string
name = string
id = string
source = object({
allow_gateway_transit = optional(bool, true)
allow_forwarded_traffic = optional(bool, true)
use_remote_gateways = optional(bool, true)
triggers = optional(map(string))
})
remote = object({
allow_gateway_transit = optional(bool, true)
allow_forwarded_traffic = optional(bool, true)
use_remote_gateways = optional(bool, true)
provider = optional(string)
triggers = optional(map(string))
})
}))
Default: []
Description: (Optional) Defines subnet configurations within the Virtual Network. Each subnet can be customized with security, connectivity, and service integration options.
-
name
: (Required) Unique identifier for the subnet (1-80 characters, alphanumeric, hyphens, underscores) -
address_prefixes
: (Required) List of CIDR ranges for the subnet (must be within VNet address space) -
service_endpoints
: (Optional) List of Azure service endpoints to enable on the subnet -
delegation
: (Optional) Configuration for Azure service delegationname
: (Required) Name of the delegation configurationservice_delegation
: (Required) Service-specific delegation settingsname
: (Required) Azure service to delegate to (e.g., Microsoft.Web/serverFarms)actions
: (Required) List of actions the service is allowed to perform
-
nsg_name
: (Optional) Name for the Network Security Group -
security_rules
: (Optional) Map of security rulespriority
: (Required) Rule priority (100-4096)direction
: (Required) Traffic direction (Inbound/Outbound)access
: (Required) Allow/Denyprotocol
: (Required) Network protocolsource_port_range
: (Required) Source port or rangedestination_port_range
: (Required) Destination port or rangesource_address_prefix
: (Required) Source address prefixdestination_address_prefix
: (Required) Destination address prefixdescription
: (Required) Rule description
-
private_endpoint_network_policies_enabled
: (Optional) Enable/disable private endpoint network policies -
private_link_service_network_policies_enabled
: (Optional) Enable/disable private link service network policies
Type:
list(object({
name = string
address_prefixes = list(string)
service_endpoints = optional(list(string), [])
delegation = optional(object({
name = string
service_delegation = object({
name = string
actions = list(string)
})
}))
nsg_name = optional(string)
security_rules = optional(map(object({
name = optional(string, null)
priority = number
direction = string
access = string
protocol = string
source_port_range = string
destination_port_range = string
source_address_prefix = string
destination_address_prefix = string
description = optional(string, "")
})), {})
private_endpoint_network_policies_enabled = optional(bool, true)
private_link_service_network_policies_enabled = optional(bool, true)
}))
Default: []
Description: (Optional) A map of tags to be applied to all resources created by this module. Tags help organize and track resources across your Azure infrastructure.
Type: map(string)
Default: {}
Description: (Optional) Configuration for Azure Virtual WAN hub connection. Required if create_virtual_hub_connection is true.
Configuration properties:
- name : (Required) Name of the Virtual Hub to connect to
- id : (Required) Resource ID of the Virtual Hub
- vhub_route_table : (Optional) Route table configuration
- associated_id : (Optional) Route table to associate with connection
- inbound_route_map_id : (Optional) Resource ID of inbound route map
- outbound_route_map_id : (Optional) Resource ID of outbound route map
- propagated_route_table: (Optional) Route propagation settings
Type:
object({
name = string
id = string
vhub_route_table = optional(object({
associated_id = optional(string)
inbound_route_map_id = optional(string)
outbound_route_map_id = optional(string)
propagated_route_table = optional(object({
labels = list(string)
route_table_ids = list(string)
}))
}), null)
})
Default: null
The following outputs are exported:
Description: Private DNS zone configuration
Description: Network Security Groups configurations
Description: Network peering configurations
Description: Public IP configurations indexed by name
Description: Map of subnet configurations indexed by subnet name
Description: Virtual Hub connection configuration
Description: Virtual Network configuration and properties