Skip to content

Repository files navigation

Terraform Azure Network

Creates an Azure virtual network and its subnets, with each subnet's optional NSG and route table associations. Route tables and NSGs are separate modules; this one associates them by id.

CI Release Terraform Registry License


Overview

A single virtual network plus its subnets (keyed map, stable for_each). Each subnet sets its prefixes, service endpoints, delegations (name the service; the actions are looked up from subnet_delegation_actions), and an optional NSG / route table id that the module associates. NSGs and route tables are owned by the separate nsg and route-table modules, so this composes by id without depending on them. Need subnets on an existing vnet from another stack? Use the standalone subnet module, which shares this subnet schema.

Secure defaults: subnets default to private_endpoint_network_policies = "Enabled" (enforces NSG and route rules on private endpoints) and default_outbound_access_enabled = false (no implicit outbound; Azure is retiring default outbound, so attach an explicit egress such as the nat-gateway module). Both are overridable per subnet.

Usage

module "network" {
  source  = "libre-devops/network/azurerm"
  version = "~> 4.0"

  resource_group_id = module.rg.ids["rg-ldo-uks-prd-001"]
  location          = "uksouth"
  tags              = module.tags.tags

  vnet_name     = "vnet-ldo-uks-prd-001"
  address_space = ["10.0.0.0/16"]

  subnets = {
    "snet-app-vnet-ldo-uks-prd-001" = {
      address_prefixes  = ["10.0.1.0/24"]
      service_endpoints = ["Microsoft.Storage"]
      delegations       = ["Microsoft.Web/serverFarms"]
    }
  }

  # Associations are keyed by subnet name; the ids may be computed in the same apply.
  nsg_associations = {
    "snet-app-vnet-ldo-uks-prd-001" = module.nsg.id
  }
}

Examples

  • examples/minimal - a virtual network with one subnet.
  • examples/complete - multiple subnets with service endpoints, a delegation, and NSG / route table associations.

Both examples call the tags and rg modules first, then this module.

Developing

Local work needs PowerShell 7+ and just, because the recipes wrap the LibreDevOpsHelpers PowerShell module (the same engine the libre-devops/terraform-azure action runs in CI). Install just with brew install just, or uv tool add rust-just then uv run just <recipe>.

Run just to list recipes: just update-ldo-pwsh (install or force-update LibreDevOpsHelpers from PSGallery), just validate, just scan (Trivy only), just pwsh-analyze (PSScriptAnalyzer only), just plan, just apply, just destroy, just e2e, just test, and just docs (the plan/apply/destroy recipes mirror the action, including the storage firewall dance; just e2e applies an example then always destroys it, defaulting to minimal, so nothing is left running). Releasing is also just: just increment-release [patch|minor|major] bumps, tags, and publishes a GitHub release, and the Terraform Registry picks up the tag.

Security scan exceptions

This module is scanned with Trivy; HIGH and CRITICAL findings fail the build. Any waiver is a deliberate, reviewed decision, never a way to quiet a finding that should be fixed. Waivers live in .trivyignore.yaml (the machine-applied source of truth, passed to Trivy with --ignorefile) and are mirrored in the table below so the reason is auditable.

Trivy ID Resource Finding Justification
None

To add an exception: add an entry to .trivyignore.yaml (id, optional paths to scope it, and a statement recording why), then add a matching row here. Where the finding is out of this module's scope, point the justification at the Libre DevOps module that does address it (for example the private-endpoint module). Both the file and this table are reviewed in the pull request.

Reference

The Requirements, Providers, Inputs, Outputs, and Resources below are generated by terraform-docs.

Requirements

Name Version
terraform >= 1.9.0, < 2.0.0
azurerm >= 4.0.0, < 5.0.0

Providers

Name Version
azurerm >= 4.0.0, < 5.0.0

Modules

No modules.

Resources

Name Type
azurerm_subnet.this resource
azurerm_subnet_network_security_group_association.this resource
azurerm_subnet_route_table_association.this resource
azurerm_virtual_network.this resource

Inputs

Name Description Type Default Required
address_space Address space (CIDR ranges) for the virtual network. Set this OR ip_address_pool, not both. list(string) [] no
bgp_community BGP community for the virtual network, in the format :. Null for none. string null no
ddos_protection_plan DDoS protection plan to associate. id is the plan resource id; enable defaults to true but the caller controls it. Null for none.
object({
id = string
enable = optional(bool, true)
})
null no
dns_servers Custom DNS servers for the virtual network. Empty uses Azure-provided DNS. list(string) [] no
edge_zone Edge zone within the Azure region. Null for none. string null no
encryption_enforcement When set, enables virtual network encryption with this enforcement. Allowed: AllowUnencrypted, DropUnencrypted. Null leaves encryption unset: encryption needs supported VM SKUs, and encrypted vnets do not support the DNS Private Resolver, Application Gateway, or Azure Firewall, so it is opt-in. string null no
flow_timeout_in_minutes Flow timeout in minutes (4 to 30). Null uses the Azure default. number null no
ip_address_pool Allocate the virtual network's address space from a Network Manager IPAM pool. Set this OR address_space, not both.
object({
id = string
number_of_ip_addresses = string
})
null no
location Azure region for the virtual network. string n/a yes
nsg_associations Map of subnet name to network security group id to associate. Keys are subnet names (must exist in subnets); values may be computed in the same apply (the static keys keep for_each valid). map(string) {} no
private_endpoint_vnet_policies Private endpoint policy mode for the virtual network. Allowed: Disabled, Basic. string "Disabled" no
resource_group_id Resource id of the resource group to create the virtual network and subnets in. The name and subscription are parsed from it (pass the rg module's ids output, for example module.rg.ids["rg-..."]). string n/a yes
route_table_associations Map of subnet name to route table id to associate. Keys are subnet names (must exist in subnets); values may be computed in the same apply. map(string) {} no
subnet_delegation_actions Lookup of subnet delegation service name to its delegated actions. A subnet's delegations reference these by service name; a service not listed here falls back to the platform-inferred actions. map(list(string))
{
"GitHub.Network/networkSettings": [
"Microsoft.Network/virtualNetworks/subnets/action"
],
"Microsoft.AVS/PrivateClouds": [
"Microsoft.Network/virtualNetworks/subnets/action"
],
"Microsoft.ApiManagement/service": [
"Microsoft.Network/virtualNetworks/subnets/action"
],
"Microsoft.Apollo/npu": [
"Microsoft.Network/virtualNetworks/subnets/action"
],
"Microsoft.App/environments": [
"Microsoft.Network/virtualNetworks/subnets/action"
],
"Microsoft.App/testClients": [
"Microsoft.Network/virtualNetworks/subnets/action"
],
"Microsoft.AzureCosmosDB/clusters": [
"Microsoft.Network/virtualNetworks/subnets/action"
],
"Microsoft.BareMetal/AzureHPC": [
"Microsoft.Network/virtualNetworks/subnets/action"
],
"Microsoft.BareMetal/AzureHostedService": [
"Microsoft.Network/virtualNetworks/subnets/action"
],
"Microsoft.BareMetal/AzurePaymentHSM": [
"Microsoft.Network/virtualNetworks/subnets/action"
],
"Microsoft.BareMetal/AzureVMware": [
"Microsoft.Network/networkinterfaces/",
"Microsoft.Network/virtualNetworks/subnets/join/action"
],
"Microsoft.BareMetal/CrayServers": [
"Microsoft.Network/networkinterfaces/
",
"Microsoft.Network/virtualNetworks/subnets/join/action"
],
"Microsoft.BareMetal/MonitoringServers": [
"Microsoft.Network/virtualNetworks/subnets/action"
],
"Microsoft.Batch/batchAccounts": [
"Microsoft.Network/virtualNetworks/subnets/action"
],
"Microsoft.CloudTest/hostedpools": [
"Microsoft.Network/virtualNetworks/subnets/action"
],
"Microsoft.CloudTest/images": [
"Microsoft.Network/virtualNetworks/subnets/action"
],
"Microsoft.CloudTest/pools": [
"Microsoft.Network/virtualNetworks/subnets/action"
],
"Microsoft.Codespaces/plans": [
"Microsoft.Network/virtualNetworks/subnets/action"
],
"Microsoft.ContainerInstance/containerGroups": [
"Microsoft.Network/virtualNetworks/subnets/action"
],
"Microsoft.ContainerService/TestClients": [
"Microsoft.Network/virtualNetworks/subnets/action"
],
"Microsoft.ContainerService/managedClusters": [
"Microsoft.Network/virtualNetworks/subnets/action"
],
"Microsoft.DBforMySQL/flexibleServers": [
"Microsoft.Network/virtualNetworks/subnets/action"
],
"Microsoft.DBforMySQL/servers": [
"Microsoft.Network/virtualNetworks/subnets/action"
],
"Microsoft.DBforMySQL/serversv2": [
"Microsoft.Network/virtualNetworks/subnets/action"
],
"Microsoft.DBforPostgreSQL/flexibleServers": [
"Microsoft.Network/virtualNetworks/subnets/action"
],
"Microsoft.DBforPostgreSQL/serversv2": [
"Microsoft.Network/virtualNetworks/subnets/join/action"
],
"Microsoft.DBforPostgreSQL/singleServers": [
"Microsoft.Network/virtualNetworks/subnets/action"
],
"Microsoft.Databricks/workspaces": [
"Microsoft.Network/virtualNetworks/subnets/join/action",
"Microsoft.Network/virtualNetworks/subnets/prepareNetworkPolicies/action",
"Microsoft.Network/virtualNetworks/subnets/unprepareNetworkPolicies/action"
],
"Microsoft.DelegatedNetwork/controller": [
"Microsoft.Network/virtualNetworks/subnets/action"
],
"Microsoft.DevCenter/networkConnection": [
"Microsoft.Network/virtualNetworks/subnets/action"
],
"Microsoft.DevOpsInfrastructure/pools": [
"Microsoft.Network/virtualNetworks/subnets/join/action"
],
"Microsoft.DocumentDB/cassandraClusters": [
"Microsoft.Network/virtualNetworks/subnets/action"
],
"Microsoft.Fidalgo/networkSettings": [
"Microsoft.Network/virtualNetworks/subnets/action"
],
"Microsoft.HardwareSecurityModules/dedicatedHSMs": [
"Microsoft.Network/networkinterfaces/",
"Microsoft.Network/virtualNetworks/subnets/join/action"
],
"Microsoft.Kusto/clusters": [
"Microsoft.Network/virtualNetworks/subnets/action"
],
"Microsoft.LabServices/labplans": [
"Microsoft.Network/virtualNetworks/subnets/action"
],
"Microsoft.Logic/integrationServiceEnvironments": [
"Microsoft.Network/virtualNetworks/subnets/action"
],
"Microsoft.MachineLearningServices/workspaces": [
"Microsoft.Network/virtualNetworks/subnets/action"
],
"Microsoft.Netapp/volumes": [
"Microsoft.Network/networkinterfaces/
",
"Microsoft.Network/virtualNetworks/subnets/join/action"
],
"Microsoft.Network/dnsResolvers": [
"Microsoft.Network/virtualNetworks/subnets/join/action"
],
"Microsoft.Network/fpgaNetworkInterfaces": [
"Microsoft.Network/virtualNetworks/subnets/action"
],
"Microsoft.Network/managedResolvers": [
"Microsoft.Network/virtualNetworks/subnets/action"
],
"Microsoft.Network/networkWatchers": [
"Microsoft.Network/virtualNetworks/subnets/action"
],
"Microsoft.Network/virtualNetworkGateways": [
"Microsoft.Network/virtualNetworks/subnets/action"
],
"Microsoft.Orbital/orbitalGateways": [
"Microsoft.Network/virtualNetworks/subnets/action"
],
"Microsoft.PowerPlatform/enterprisePolicies": [
"Microsoft.Network/virtualNetworks/subnets/action"
],
"Microsoft.PowerPlatform/vnetaccesslinks": [
"Microsoft.Network/virtualNetworks/subnets/action"
],
"Microsoft.ServiceFabricMesh/networks": [
"Microsoft.Network/virtualNetworks/subnets/action"
],
"Microsoft.ServiceNetworking/trafficControllers": [
"Microsoft.Network/virtualNetworks/subnets/action"
],
"Microsoft.Singularity/accounts/networks": [
"Microsoft.Network/virtualNetworks/subnets/action"
],
"Microsoft.Singularity/accounts/npu": [
"Microsoft.Network/virtualNetworks/subnets/action"
],
"Microsoft.Sql/managedInstances": [
"Microsoft.Network/virtualNetworks/subnets/join/action",
"Microsoft.Network/virtualNetworks/subnets/prepareNetworkPolicies/action",
"Microsoft.Network/virtualNetworks/subnets/unprepareNetworkPolicies/action"
],
"Microsoft.Sql/managedInstancesOnebox": [
"Microsoft.Network/virtualNetworks/subnets/action"
],
"Microsoft.Sql/managedInstancesStage": [
"Microsoft.Network/virtualNetworks/subnets/action"
],
"Microsoft.Sql/managedInstancesTest": [
"Microsoft.Network/virtualNetworks/subnets/action"
],
"Microsoft.Sql/servers": [
"Microsoft.Network/virtualNetworks/subnets/action"
],
"Microsoft.StoragePool/diskPools": [
"Microsoft.Network/virtualNetworks/subnets/action"
],
"Microsoft.StreamAnalytics/streamingJobs": [
"Microsoft.Network/virtualNetworks/subnets/join/action"
],
"Microsoft.Synapse/workspaces": [
"Microsoft.Network/virtualNetworks/subnets/action"
],
"Microsoft.Web/hostingEnvironments": [
"Microsoft.Network/virtualNetworks/subnets/action"
],
"Microsoft.Web/serverFarms": [
"Microsoft.Network/virtualNetworks/subnets/action"
],
"NGINX.NGINXPLUS/nginxDeployments": [
"Microsoft.Network/virtualNetworks/subnets/action"
],
"PaloAltoNetworks.Cloudngfw/firewalls": [
"Microsoft.Network/virtualNetworks/subnets/action"
],
"Qumulo.Storage/fileSystems": [
"Microsoft.Network/virtualNetworks/subnets/action"
]
}
no
subnets Subnets to create in the virtual network, keyed by subnet name. Each subnet sets its address
prefixes (or ip_address_pool) and optional service endpoints, delegations (service names only;
the actions are looked up from subnet_delegation_actions), and policy flags. NSG and route table
associations are separate inputs (nsg_associations / route_table_associations) so their ids may be
computed in the same apply.

Secure defaults: private_endpoint_network_policies defaults to "Enabled" (enforces NSG and route
table rules on private endpoints), and default_outbound_access_enabled defaults to false (no
implicit outbound internet; Azure is retiring default outbound, so attach an explicit egress such
as the nat-gateway module). Both are overridable per subnet.
map(object({
address_prefixes = optional(list(string), [])
ip_address_pool = optional(object({ id = string, number_of_ip_addresses = string }), null)
service_endpoints = optional(list(string), [])
service_endpoint_policy_ids = optional(list(string), [])
delegations = optional(list(string), [])
private_endpoint_network_policies = optional(string, "Enabled")
private_link_service_network_policies_enabled = optional(bool, true)
default_outbound_access_enabled = optional(bool, false)
sharing_scope = optional(string, null)
}))
{} no
tags Tags to apply to the virtual network. map(string) {} no
vnet_name Name of the virtual network. string n/a yes

Outputs

Name Description
resource_group_name Resource group name parsed from resource_group_id.
subnet_address_prefixes Map of subnet name to its address prefixes.
subnet_ids Map of subnet name to its id.
subnet_ids_zipmap Map of subnet name to a { name, id } object, so the whole object can be passed where something needs the name and id together.
subnet_names The subnet names.
subnet_nsg_association_ids Map of subnet name to its network security group association id.
subnet_route_table_association_ids Map of subnet name to its route table association id.
subnets The full azurerm_subnet resources, keyed by subnet name.
subscription_id Subscription id parsed from resource_group_id.
tags The tags applied to the virtual network.
vnet_address_space The address space of the virtual network.
vnet_dns_servers The DNS servers set on the virtual network.
vnet_guid The GUID of the virtual network.
vnet_id The id of the virtual network.
vnet_location The region of the virtual network.
vnet_name The name of the virtual network.
vnet_resource_group_name The resource group of the virtual network.
vnet_tags The tags on the virtual network.

About

🌐 Terraform module for Azure virtual networks and subnets, with NSG and route table associations, delegations and secure defaults

Topics

Resources

Contributing

Stars

Watchers

Forks

Releases

Packages

Used by

Contributors

Languages