Azure Firewall in una Landing Zone Azure con Terraform: ispezione centralizzata del traffico con Firewall Policy
Azure Firewall e’ il firewall stateful gestito che, nell’hub di una topologia hub & spoke, ispeziona il traffico in uscita verso Internet e il traffico tra gli spoke. Centralizzarlo nell’hub permette di applicare un unico punto di controllo per l’intera landing zone, riducendo la complessita’ delle regole e i costi rispetto a un firewall per spoke.
Questa guida descrive il deployment con Terraform di Azure Firewall Standard e della relativa Firewall Policy tramite gli Azure Verified Modules (AVM), nel resource group rg-hub-itn (subscription Connectivity, region Italy North). Presuppone la Hub Virtual Network gia’ deployata con la subnet AzureFirewallSubnet.
Cos’e’ un firewall e perche’ implementarlo
Un firewall e’ il componente che controlla il traffico di rete che entra ed esce, decidendo cosa lasciare passare e cosa bloccare in base a un insieme di regole. E’ l’equivalente digitale di un posto di controllo: ogni pacchetto che vuole raggiungere Internet, o passare da un’applicazione all’altra, viene esaminato e autorizzato o respinto.
Azure Firewall è la versione gestita e cloud-native di questo componente: non richiede di installare e mantenere macchine virtuali, scala automaticamente e si integra con i servizi di Azure. Nell’hub svolge due funzioni chiave: ispeziona il traffico in uscita verso Internet (egress) e il traffico tra un’applicazione e l’altra (spoke-to-spoke), impedendo che una rete compromessa raggiunga liberamente le altre.
I motivi principali per implementare un firewall centralizzato sono:
- Controllo dell’egress – si decide con precisione verso quali siti e servizi le applicazioni possono comunicare, riducendo il rischio di esfiltrazione di dati e di comunicazioni verso destinazioni malevole.
- Segmentazione – il traffico tra applicazioni diverse non e’ libero ma passa dal firewall, cosi’ un eventuale attacco resta confinato e non si propaga.
- Protezione dalle minacce – il Threat Intelligence integrato riconosce IP e domini malevoli noti e segnala o blocca il traffico verso di essi.
- Un unico punto di gestione – le regole si scrivono e si verificano in un solo posto invece che su decine di reti, semplificando audit e conformita’.
Architettura: firewall e policy separati
La configurazione delle regole non risiede sull’istanza del firewall ma su una Firewall Policy separata. Questa scelta consente di versionare le regole, condividerle tra piu’ firewall (scenari multi-region o multi-hub) e gestire gerarchie di policy padre/figlio. I componenti deployati sono:
- afw-policy-hub-itn – la Firewall Policy Standard con DNS proxy e Threat Intelligence.
- pip-afw-hub-itn – l’IP pubblico Standard statico, zone-redundant.
- afw-hub-itn – l’istanza di Azure Firewall Standard nella AzureFirewallSubnet.
Passo 1: La Firewall Policy
La policy e’ creata con il modulo AVM avm-res-network-firewallpolicy in SKU Standard. Il DNS proxy e’ abilitato per permettere al firewall di intercettare le query DNS e applicare le regole basate su FQDN nelle network rule collection. Il Threat Intelligence e’ in modalita’ Alert: registra il traffico verso IP e FQDN malevoli noti senza bloccarlo.
NOTA: Portare il Threat Intelligence da Alert a Deny solo dopo aver verificato che non ci siano falsi positivi sul traffico legittimo.
Passo 2: L’IP pubblico
L’IP pubblico del firewall deve essere Standard SKU statico per supportare le availability zones. Non esiste ancora un modulo AVM dedicato al public IP, quindi si usa il resource nativo azurerm_public_ip con distribuzione sulle zone 1, 2, 3.
Passo 3: L’istanza di Azure Firewall
Il firewall e’ creato con il modulo AVM avm-res-network-azurefirewall con SKU AZFW_VNet tier Standard, distribuito sulle availability zones 1, 2, 3 per l’alta disponibilita’ intra-region. Viene collegato alla policy creata sopra e alla AzureFirewallSubnet tramite la ip_configuration principale.
Il file completo afw.tf con policy, IP pubblico e firewall:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 |
# La Firewall Policy e' il contenitore delle regole del firewall. # Tenerla come risorsa separata dal firewall permette di condividere # la stessa policy tra piu firewall in futuro (es. multi-region). # SKU Standard e' sufficiente per la maggior parte degli scenari enterprise. module "firewall_policy" { source = "Azure/avm-res-network-firewallpolicy/azurerm" version = "~> 0.3" name = var.firewall_policy_name location = var.location resource_group_name = module.resource_group.name tags = local.global_tags enable_telemetry = false firewall_policy_sku = "Standard" # Il DNS proxy e' abilitato per permettere al firewall di intercettare # le query DNS e applicare le regole FQDN nelle network rule collection. firewall_policy_dns = { proxy_enabled = true } # Threat Intelligence in modalita' Alert registra il traffico verso IP # e FQDN malevoli noti senza bloccarlo. Si puo' portare a Deny # una volta verificato che non ci siano falsi positivi. firewall_policy_threat_intelligence_mode = "Alert" } # L'indirizzo IP pubblico del firewall deve essere Standard SKU # per supportare le availability zones. Non esiste ancora un modulo AVM # dedicato al public IP, quindi usiamo il resource nativo azurerm. resource "azurerm_public_ip" "firewall" { name = "pip-${var.firewall_name}" location = var.location resource_group_name = module.resource_group.name allocation_method = "Static" sku = "Standard" zones = ["1", "2", "3"] tags = local.global_tags } # Azure Firewall Standard deployato nella AzureFirewallSubnet della hub VNet. # Le availability zones garantiscono alta disponibilita' all'interno della region. module "firewall" { source = "Azure/avm-res-network-azurefirewall/azurerm" version = "~> 0.4" name = var.firewall_name location = var.location resource_group_name = module.resource_group.name tags = local.global_tags enable_telemetry = false firewall_sku_name = "AZFW_VNet" firewall_sku_tier = "Standard" firewall_zones = ["1", "2", "3"] # Colleghiamo il firewall alla policy creata sopra. firewall_policy_id = module.firewall_policy.resource_id # ip_configurations definisce come il firewall si collega alla subnet e all'IP pubblico. # Solo una delle configurazioni puo avere subnet_id (quella principale). ip_configurations = { default = { name = "azureFirewallIpConfig" subnet_id = module.vnet.subnets["AzureFirewallSubnet"].resource_id public_ip_address_id = azurerm_public_ip.firewall.id } } } } |
Passo 4: Gli output del firewall
Il file outputs.tf espone i valori del firewall utili agli spoke. In particolare firewall_private_ip e’ l’IP privato da usare come next hop nelle User Defined Routes (UDR) degli spoke (default route 0.0.0.0/0) per forzare l’egress attraverso il firewall.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
# L'IP privato del firewall e' il next hop da usare nelle User Defined Route # delle spoke VNet per forzare il traffico attraverso il firewall. output "firewall_private_ip" { description = "Indirizzo IP privato dell'Azure Firewall, usato come next hop nelle UDR" value = module.firewall.resource.ip_configuration[0].private_ip_address } output "firewall_public_ip" { description = "Indirizzo IP pubblico dell'Azure Firewall" value = azurerm_public_ip.firewall.ip_address } output "firewall_policy_id" { description = "Resource ID della firewall policy" value = module.firewall_policy.resource_id } |
Passo 5: Applicare e verificare
Dopo terraform init, applicare il piano. Il deployment del firewall richiede tipicamente diversi minuti.
|
1 2 3 |
Terraform plan -out tfplan Terraform apply tfplan |
ATTENZIONE: Azure Firewall comporta costi orari non trascurabili gia’ dal momento della creazione, indipendentemente dal traffico. In ambienti non produttivi valutare l’uso di risorse condivise o lo spegnimento quando non necessario.
Al termine, aprire rg-hub-itn nel portale e verificare la presenza di afw-hub-itn (Firewall), afw-policy-hub-itn (Firewall Policy) e pip-afw-hub-itn (Public IP address).

Figura 1: Il contenuto di rg-hub-itn: si riconoscono afw-hub-itn (Firewall), afw-policy-hub-itn (Firewall Policy) e il Public IP pip-afw-hub-itn.
Verifica del deployment
Il deployment del firewall e’ completo quando:
- afw-hub-itn e’ in stato Succeeded con SKU Standard e zone 1/2/3.
- afw-policy-hub-itn e’ associata al firewall, con DNS proxy e Threat Intelligence attivi.
- L’output firewall_private_ip restituisce l’IP privato da usare nelle UDR degli spoke.
COMPLETATO: Azure Firewall e’ operativo nell’hub. Gli spoke possono ora instradare il proprio egress verso l’IP privato del firewall tramite UDR, ottenendo l’ispezione centralizzata del traffico verso Internet e tra spoke.
Conclusioni
Abbiamo deployato Azure Firewall Standard con una Firewall Policy separata, IP pubblico zone-redundant e DNS proxy abilitato. La separazione tra policy e istanza e’ la best practice che consente di versionare e riutilizzare le regole.
NOTA: Come evoluzione, popolare la Firewall Policy con le rule collection di egress (application e network rules), configurare le UDR sugli spoke verso l’IP privato del firewall e, una volta validato il traffico, valutare il passaggio del Threat Intelligence a Deny.