Quanto mais VNets você tem, mais chato fica manter peering, NSG e regra de segurança consistentes entre todas elas — um time esquece um NSG, outro cria um peering a mais, e a governança de rede vira um “cada um faz do seu jeito”. O Azure Virtual Network Manager (AVNM) resolve isso: um único recurso que aplica topologia de conectividade e regras de segurança em grupos de VNets inteiros, de forma centralizada — e neste artigo a gente cria isso do zero com Terraform.
Vamos criar 3 VNets de exemplo (simulando times/apps diferentes), agrupá-las num Network Group, aplicar uma Connectivity Configuration com topologia Mesh (o Network Manager cria o peering entre as três automaticamente) e uma Security Admin Configuration que bloqueia RDP/SSH vindos da Internet em todo o grupo — com prioridade acima de qualquer NSG que alguém configure (ou esqueça de configurar) depois.
Segurança: os comandos deste guia de Azure Virtual Network Manager com Terraform utilizam variáveis de ambiente para credenciais. Nunca insira IDs de subscription, senhas ou chaves diretamente nos comandos — use TF_VAR_*, um arquivo .tfvars fora do Git, ou o Azure Key Vault.
Sumário
- Pré-requisitos
- Por que centralizar com o Azure Virtual Network Manager
- Criando as VNets de exemplo
- Criando o Azure Virtual Network Manager
- Connectivity Configuration: topologia mesh
- Security Admin Configuration: regra centralizada
- terraform plan e apply
- Confirmando o Azure Virtual Network Manager no portal
- Troubleshooting: o bug do “*” na porta
- Conclusão
- Referências oficiais
Pré-requisitos
Antes de criar o Azure Virtual Network Manager com Terraform, você vai precisar do Azure CLI autenticado (az login), do Terraform >= 1.5 e de permissão de Network Contributor (ou Owner) na subscription — o Network Manager precisa poder criar recursos no escopo da subscription inteira. O provider usado é o azurerm ~> 4.0.
az account show --query "{name:name, id:id}" -o table
Por que centralizar com o Azure Virtual Network Manager
Sem o Azure Virtual Network Manager, manter várias VNets consistentes significa declarar peering par-a-par manualmente — como fizemos na Hub-Spoke Landing Zone com Terraform (azurerm_virtual_network_peering em dobro pra cada conexão) — e replicar as mesmas regras de NSG em cada VNet — e torcer pra ninguém esquecer de atualizar todas quando a regra mudar. Com o AVNM, você declara a topologia e a regra uma vez, aponta pra um Network Group, e o serviço aplica (e mantém) isso em todo membro do grupo, inclusive VNets que entrarem no grupo depois. A regra de segurança também tem uma vantagem que NSG sozinho não tem: ela é avaliada antes do NSG local, então nenhuma VNet do grupo consegue “abrir” a porta bloqueada por engano.
Criando as VNets de exemplo
Antes de o Azure Virtual Network Manager entrar em ação, precisamos das VNets que ele vai gerenciar. Pra deixar o exemplo realista, criamos 3 VNets simulando times diferentes — frontend, backend e shared — cada uma com seu próprio endereçamento e uma subnet:
# variables.tf
variable "vnets" {
type = map(object({
address_space = string
subnet_prefix = string
}))
default = {
frontend = { address_space = "10.20.1.0/24", subnet_prefix = "10.20.1.0/26" }
backend = { address_space = "10.20.2.0/24", subnet_prefix = "10.20.2.0/26" }
shared = { address_space = "10.20.3.0/24", subnet_prefix = "10.20.3.0/26" }
}
}
# main.tf — a partir do módulo reutilizável terraform-resource-group-modules
# e uma instância de terraform-virtual-network-modules por VNet (for_each)
module "rg" {
source = "../../terraform-resource-group-modules"
resource_type = "rg"
project_name = "blog-castilho-vnet-manager"
environment = "prod"
location = var.location
tags = var.tags
}
module "vnets" {
source = "../../terraform-virtual-network-modules"
for_each = var.vnets
name = "vnet-${each.key}-blog-castilho"
resource_group_name = module.rg.name
location = var.location
address_space = [each.value.address_space]
subnets = [
{ key = "default", name = "snet-${each.key}", address_prefixes = [each.value.subnet_prefix] },
]
tags = var.tags
}
Criando o Azure Virtual Network Manager
O recurso azurerm_network_manager, que representa o Azure Virtual Network Manager no Terraform, precisa de um scope (a subscription, no nosso caso) e dos scope_accesses que ele vai gerenciar — aqui, Connectivity e SecurityAdmin. Em vez de declarar cada recurso cru separadamente, este ambiente usa o módulo reutilizável terraform-network-manager-modules, que encapsula o Network Manager, o Network Group (com as 3 VNets como membros estáticos), a Connectivity Configuration e a Security Admin Configuration numa única chamada:
module "network_manager" {
source = "../../terraform-network-manager-modules"
name = "avnm-blog-castilho"
resource_group_name = module.rg.name
location = var.location
subscription_id = var.subscription_id
network_group_name = "ng-app-vnets"
member_vnet_ids = { for k, v in module.vnets : k => v.vnet_id }
connectivity_topology = "Mesh"
connectivity_configuration_name = "conn-mesh-app-vnets"
security_admin_configuration_name = "secadmin-baseline"
admin_rule_collection_name = "rulecoll-baseline"
admin_rules = [
{
name = "deny-rdp-ssh-from-internet"
action = "Deny"
direction = "Inbound"
priority = 100
protocol = "Tcp"
source_address_prefix_type = "ServiceTag"
source_address_prefix = "Internet"
destination_address_prefix_type = "IPPrefix"
destination_address_prefix = "*"
source_port_ranges = ["0-65535"]
destination_port_ranges = ["22", "3389"]
},
]
tags = var.tags
}
No Azure Virtual Network Manager, membro estático é o mais simples de começar: você lista explicitamente quais VNets entram no grupo. Dá pra evoluir depois pra membros dinâmicos, onde o Azure Policy decide automaticamente quem entra no grupo com base em tags ou outros critérios — útil quando o número de VNets cresce demais pra listar uma a uma.

Connectivity Configuration: topologia mesh
Aqui está a parte que substitui o peering manual: uma Connectivity Configuration do Azure Virtual Network Manager, com topologia Mesh aplicada ao grupo inteiro — os parâmetros connectivity_topology = "Mesh" e connectivity_configuration_name no bloco module "network_manager" mostrado acima. Internamente, o módulo cria um azurerm_network_manager_connectivity_configuration apontando pro network_group_id do grupo. O Network Manager cuida de criar (e manter) o peering entre todas as VNets do grupo — sem precisar declarar azurerm_virtual_network_peering pra cada par.
Com 3 VNets isso já elimina 3 pares de peering manual (6 recursos de azurerm_virtual_network_peering, já que cada peering é bidirecional). Com 10 VNets numa topologia mesh completa, seriam 45 pares — 90 recursos de peering só pra manter todo mundo conectado com todo mundo. A Connectivity Configuration substitui isso tudo por um único bloco, e ainda mantém sozinha se você adicionar uma 11ª VNet ao grupo depois.
Security Admin Configuration: regra centralizada
A segunda parte é a regra de segurança do Azure Virtual Network Manager que vale pra todo o grupo, com prioridade acima de qualquer NSG local: bloquear RDP (3389) e SSH (22) vindos da Internet. Isso funciona em 3 níveis — Security Admin Configuration (o container), Rule Collection (onde você associa o(s) network group(s) alvo) e a Admin Rule propriamente dita. No módulo, é só a lista admin_rules mostrada no bloco module "network_manager" acima — o módulo cria a Security Admin Configuration, a Rule Collection e uma azurerm_network_manager_admin_rule pra cada item da lista internamente.
Por fim, as duas configurações precisam ser implantadas (committed) numa região — sem isso, elas existem como definição mas não valem pra nada. O módulo já cuida disso sozinho, criando os dois azurerm_network_manager_deployment (um pra Connectivity, outro pra SecurityAdmin) automaticamente — não é preciso declarar isso na chamada do módulo.
terraform plan e apply
Com tudo declarado no Azure Virtual Network Manager, o fluxo é o de sempre — init, plan, apply:
terraform init -backend-config=backend.hcl
terraform plan -out=tfplan.out
terraform apply tfplan.out
No total, esse ambiente cria 20 recursos: o Resource Group, 3 VNets + 3 subnets, o Network Manager, o Network Group + 3 membros estáticos, a Connectivity Configuration, a Security Admin Configuration + rule collection + admin rule, e os 2 deployments. Vale notar que nenhum desses recursos tem custo direto — VNets, Network Manager e as configurações de conectividade/segurança são gratuitas; você só paga pelo que rodar dentro delas (VMs, gateways, etc.).

Confirmando o Azure Virtual Network Manager no portal
A prova de que a configuração do Azure Virtual Network Manager realmente “pegou” está em dois lugares. Primeiro, na página Configurations, as duas configurações aparecem como Deployed in 1 region(s):

Segundo — e essa é a parte mais interessante — abrindo a aba Network manager de qualquer uma das 3 VNets (não a aba clássica “Peerings”, que continua vazia), ela mostra a Connectivity Configuration Mesh já aplicada, puxada do grupo ng-app-vnets, sem que a gente tenha declarado nenhum azurerm_virtual_network_peering:

E a regra de segurança, dentro da Security Admin Configuration, mostra exatamente o que foi declarado — Deny, Inbound, prioridade 100, origem Internet, destino portas 22 e 3389:

Troubleshooting: o bug do “*” na porta
Quem já escreveu regra de NSG e agora está migrando pro Azure Virtual Network Manager tem o hábito de usar "*" pra “qualquer porta” — e foi exatamente isso que quebrou aqui. A primeira tentativa de source_port_ranges usava ["*"], copiando o padrão comum de NSG, e o apply falhou com:
Error: creating Security Admin Configuration Rule Collection Rule: unexpected status 400 (400 Bad Request)
with error: BadRequest: [Invalid Port Range](*) in Resource [...]
is out of range expected: (0-65535)
Diferente das regras de NSG, a API do azurerm_network_manager_admin_rule não aceita o curinga "*" pra porta — ela espera um range numérico explícito. A correção foi trocar ["*"] por ["0-65535"], que expressa a mesma intenção (“qualquer porta de origem”) de um jeito que a API aceita. Vale a mesma atenção pra destination_port_ranges se algum dia precisar de “qualquer porta de destino” — o padrão é o mesmo.
Conclusão
O Azure Virtual Network Manager não substitui NSG nem peering — ele centraliza a governança de ambos, garantindo que topologia de conectividade e regras de segurança de linha de base sejam consistentes em qualquer VNet que entre no grupo, presente ou futura. Pra ambientes com poucas VNets isoladas o ganho é pequeno, mas conforme o número de times/apps cresce, é exatamente esse tipo de configuração declarativa e centralizada que evita que a rede vire um emaranhado de peerings esquecidos e NSGs divergentes.
Próximo artigo da série artigos-network: Application Gateway + WAF v2 com Terraform.
Referências oficiais
- Azure Virtual Network Manager overview — Microsoft Learn
- Connectivity configurations — Microsoft Learn
- Security admin rules — Microsoft Learn
- azurerm_network_manager — Terraform Registry
Interessado em saber mais sobre esse assunto?