DEV Community

Cover image for NIS2 Article 21 in Azure: Implementing Network Security Controls with Terraform
david
david

Posted on • Originally published at woitzik.dev

NIS2 Article 21 in Azure: Implementing Network Security Controls with Terraform

NIS2 Article 21 in Azure: Implementing Network Security Controls with Terraform

Tags: terraform, azure, security, devops

Canonical URL: https://woitzik.dev/blog/nis2-article-21-azure-terraform

Most NIS2 content is written by lawyers for lawyers. This article maps Article 21 network security requirements to concrete Azure resources — with Terraform code, not legal theory.

Disclaimer: This covers technical network infrastructure controls relevant to NIS2 Article 21. Full compliance requires organizational measures beyond infrastructure code. Nothing here constitutes legal advice.

What NIS2 Article 21 Actually Requires (For Engineers)

Four concrete network security areas:

  1. Network Segmentation — isolate systems by criticality
  2. Access Control — Default-Deny at network and identity layer
  3. Minimize Attack Surface — eliminate unnecessary public endpoints
  4. Auditability — traceable, version-controlled infrastructure changes

Here's how each maps to Azure Terraform resources.

Control 1: Network Segmentation via Hub & Spoke

Spoke-to-Spoke traffic blocked by default — all cross-workload communication routes through the Hub:

resource "azurerm_virtual_network_peering" "hub_to_spoke1" {
  name                      = "peer-hub-to-spoke1"
  virtual_network_name      = azurerm_virtual_network.hub.name
  remote_virtual_network_id = azurerm_virtual_network.spoke1.id
  allow_forwarded_traffic   = true
}
Enter fullscreen mode Exit fullscreen mode

Spokes only peer with the Hub — never with each other. Cross-Spoke traffic must be explicitly routed through the Firewall.

Control 2: Default-Deny NSG Baseline

security_rule {
  name                       = "Allow-VNet-Inbound"
  priority                   = 100
  access                     = "Allow"
  source_address_prefix      = "VirtualNetwork"
  destination_address_prefix = "VirtualNetwork"
}

security_rule {
  name                       = "Deny-Internet-Inbound"
  priority                   = 4096
  access                     = "Deny"
  source_address_prefix      = "Internet"
  destination_address_prefix = "*"
}
Enter fullscreen mode Exit fullscreen mode

Priority gap (100 → 4096) leaves room for application rules without restructuring the baseline.

Control 3: Egress Control via Forced Tunneling

All outbound Spoke traffic through Azure Firewall — logged, inspectable, FQDN-controlled:

route {
  name                   = "route-to-firewall"
  address_prefix         = "0.0.0.0/0"
  next_hop_type          = "VirtualAppliance"
  next_hop_in_ip_address = azurerm_firewall.fw.ip_configuration[0].private_ip_address
}

# Critical — without these, Windows VMs lose activation
route {
  name           = "bypass-azure-kms"
  address_prefix = "23.102.135.246/32"
  next_hop_type  = "Internet"
}
Enter fullscreen mode Exit fullscreen mode

The Firewall log is your audit trail for NIS2 Article 21(2)(b) — monitoring and incident detection.

Control 4: Zero Public PaaS Endpoints

resource "azurerm_key_vault" "kv" {
  public_network_access_enabled = false

  network_acls {
    default_action = "Deny"
    bypass         = "AzureServices"
  }
}
Enter fullscreen mode Exit fullscreen mode

An external scanner gets no TCP connection — the endpoint doesn't resolve to a public IP. Directly satisfies NIS2 Article 21(2)(h).

Control 5: No Static Credentials

Managed Identity + scoped RBAC — no connection strings, no access keys:

resource "azurerm_role_assignment" "app_kv_secrets" {
  scope                = azurerm_key_vault.kv.id
  role_definition_name = "Key Vault Secrets User"
  principal_id         = azurerm_linux_function_app.app.identity[0].principal_id
}
Enter fullscreen mode Exit fullscreen mode

When the resource is deleted, identity and permissions are automatically destroyed.

Control 6: Auditability via IaC

Every change is a Git commit. terraform plan is an audit artifact. No ClickOps, no undocumented Portal changes.

What This Covers — and What It Doesn't

This addresses technical network controls only. Full NIS2 compliance also requires incident response procedures, supply chain risk management, business continuity measures, and organizational governance.

Infrastructure code is the foundation. Compliance is the full building.


Full article with complete code for all six controls on my blog.

👉 Full article on woitzik.dev

Top comments (0)