Managing Azure NAT Gateway with Terraform

Learn how to set up and manage Azure NAT Gateway using Terraform, including outbound connectivity and IP configuration

Managing Azure NAT Gateway with Terraform

Azure NAT Gateway provides outbound internet connectivity for resources in your virtual network. This guide demonstrates how to set up and manage NAT Gateway using Terraform.

Video Tutorial

Learn more about managing Azure NAT Gateway with Terraform in this comprehensive video tutorial:

Prerequisites

  • Azure CLI configured with appropriate permissions
  • Terraform installed (version 1.0.0 or later)
  • Resource group created
  • Understanding of networking concepts

Project Structure

terraform-azure-natgateway/
├── main.tf
├── variables.tf
├── outputs.tf
├── modules/
│   └── natgateway/
│       ├── main.tf
│       ├── variables.tf
│       └── outputs.tf
└── configs/
    └── settings.json

NAT Gateway Configuration

Create modules/natgateway/main.tf:

# Public IP Prefix
resource "azurerm_public_ip_prefix" "main" {
  name                = "${var.project_name}-pip-prefix"
  location            = var.location
  resource_group_name = var.resource_group_name
  prefix_length       = 30
  zones               = ["1", "2", "3"]

  tags = var.tags
}

# Public IP
resource "azurerm_public_ip" "main" {
  name                = "${var.project_name}-pip"
  location            = var.location
  resource_group_name = var.resource_group_name
  allocation_method   = "Static"
  sku                 = "Standard"
  zones               = ["1", "2", "3"]

  tags = var.tags
}

# NAT Gateway
resource "azurerm_nat_gateway" "main" {
  name                    = "${var.project_name}-natgw"
  location                = var.location
  resource_group_name     = var.resource_group_name
  sku_name                = "Standard"
  idle_timeout_in_minutes = 10
  zones                   = ["1", "2", "3"]

  tags = var.tags
}

# NAT Gateway Public IP Association
resource "azurerm_nat_gateway_public_ip_association" "main" {
  nat_gateway_id       = azurerm_nat_gateway.main.id
  public_ip_address_id = azurerm_public_ip.main.id
}

# NAT Gateway Public IP Prefix Association
resource "azurerm_nat_gateway_public_ip_prefix_association" "main" {
  nat_gateway_id      = azurerm_nat_gateway.main.id
  public_ip_prefix_id = azurerm_public_ip_prefix.main.id
}

# Virtual Network
resource "azurerm_virtual_network" "main" {
  name                = "${var.project_name}-vnet"
  address_space       = ["10.0.0.0/16"]
  location            = var.location
  resource_group_name = var.resource_group_name

  tags = var.tags
}

# Subnet
resource "azurerm_subnet" "main" {
  name                 = "workload-subnet"
  resource_group_name  = var.resource_group_name
  virtual_network_name = azurerm_virtual_network.main.name
  address_prefixes     = ["10.0.1.0/24"]
}

# NAT Gateway Subnet Association
resource "azurerm_subnet_nat_gateway_association" "main" {
  subnet_id      = azurerm_subnet.main.id
  nat_gateway_id = azurerm_nat_gateway.main.id
}

# Network Security Group
resource "azurerm_network_security_group" "main" {
  name                = "${var.project_name}-nsg"
  location            = var.location
  resource_group_name = var.resource_group_name

  security_rule {
    name                       = "AllowHTTPSOutbound"
    priority                   = 100
    direction                  = "Outbound"
    access                     = "Allow"
    protocol                   = "Tcp"
    source_port_range          = "*"
    destination_port_range     = "443"
    source_address_prefix      = "*"
    destination_address_prefix = "Internet"
  }

  security_rule {
    name                       = "DenyAllInbound"
    priority                   = 4096
    direction                  = "Inbound"
    access                     = "Deny"
    protocol                   = "*"
    source_port_range          = "*"
    destination_port_range     = "*"
    source_address_prefix      = "*"
    destination_address_prefix = "*"
  }

  tags = var.tags
}

# NSG Association
resource "azurerm_subnet_network_security_group_association" "main" {
  subnet_id                 = azurerm_subnet.main.id
  network_security_group_id = azurerm_network_security_group.main.id
}

# Route Table
resource "azurerm_route_table" "main" {
  name                = "${var.project_name}-rt"
  location            = var.location
  resource_group_name = var.resource_group_name

  route {
    name                   = "ToInternet"
    address_prefix         = "0.0.0.0/0"
    next_hop_type         = "Internet"
  }

  tags = var.tags
}

# Route Table Association
resource "azurerm_subnet_route_table_association" "main" {
  subnet_id      = azurerm_subnet.main.id
  route_table_id = azurerm_route_table.main.id
}

# Example VM Scale Set using NAT Gateway
resource "azurerm_linux_virtual_machine_scale_set" "main" {
  name                = "${var.project_name}-vmss"
  resource_group_name = var.resource_group_name
  location            = var.location
  sku                = "Standard_B2s"
  instances          = 2
  admin_username     = "adminuser"

  admin_ssh_key {
    username   = "adminuser"
    public_key = file("~/.ssh/id_rsa.pub")
  }

  source_image_reference {
    publisher = "Canonical"
    offer     = "UbuntuServer"
    sku       = "18.04-LTS"
    version   = "latest"
  }

  network_interface {
    name    = "nic"
    primary = true

    ip_configuration {
      name      = "internal"
      primary   = true
      subnet_id = azurerm_subnet.main.id
    }
  }

  os_disk {
    caching              = "ReadWrite"
    storage_account_type = "Standard_LRS"
  }

  tags = var.tags
}

## Monitoring Configuration

1. **Diagnostic Settings**
```hcl
resource "azurerm_monitor_diagnostic_setting" "natgateway" {
  name                       = "${var.project_name}-diag"
  target_resource_id        = azurerm_nat_gateway.main.id
  log_analytics_workspace_id = var.log_analytics_workspace_id

  metric {
    category = "AllMetrics"
    enabled  = true

    retention_policy {
      enabled = true
      days    = 30
    }
  }
}

# NAT Gateway Alerts
resource "azurerm_monitor_metric_alert" "snat_connections" {
  name                = "${var.project_name}-snat-alert"
  resource_group_name = var.resource_group_name
  scopes              = [azurerm_nat_gateway.main.id]
  description         = "Alert when SNAT connections are high"

  criteria {
    metric_namespace = "Microsoft.Network/natGateways"
    metric_name      = "TotalConnectionCount"
    aggregation      = "Average"
    operator         = "GreaterThan"
    threshold        = 50000
  }

  action {
    action_group_id = var.action_group_id
  }
}

resource "azurerm_monitor_metric_alert" "dropped_packets" {
  name                = "${var.project_name}-dropped-packets-alert"
  resource_group_name = var.resource_group_name
  scopes              = [azurerm_nat_gateway.main.id]
  description         = "Alert when packets are being dropped"

  criteria {
    metric_namespace = "Microsoft.Network/natGateways"
    metric_name      = "DroppedPackets"
    aggregation      = "Total"
    operator         = "GreaterThan"
    threshold        = 1000
  }

  action {
    action_group_id = var.action_group_id
  }
}

Flow Logs Configuration

  1. Network Watcher and Flow Logs
resource "azurerm_network_watcher_flow_log" "natgateway" {
  network_watcher_name = var.network_watcher_name
  resource_group_name  = var.resource_group_name

  network_security_group_id = azurerm_network_security_group.main.id
  storage_account_id        = var.storage_account_id
  enabled                   = true

  retention_policy {
    enabled = true
    days    = 30
  }

  traffic_analytics {
    enabled               = true
    workspace_id          = var.log_analytics_workspace_id
    workspace_region      = var.location
    workspace_resource_id = var.log_analytics_workspace_resource_id
    interval_in_minutes   = 10
  }
}

Best Practices

  1. Performance

    • Size appropriately
    • Monitor connections
    • Configure timeouts
    • Use zones
  2. High Availability

    • Use multiple zones
    • Configure failover
    • Monitor health
    • Scale resources
  3. Security

    • Configure NSGs
    • Enable logging
    • Monitor traffic
    • Review policies
  4. Cost Optimization

    • Monitor usage
    • Right-size gateway
    • Optimize IPs
    • Review metrics

Conclusion

You’ve learned how to set up and manage Azure NAT Gateway using Terraform. This setup provides:

  • Outbound connectivity
  • IP management
  • Traffic monitoring
  • High availability

Remember to:

  • Monitor connections
  • Review configurations
  • Update policies
  • Maintain performance