Back
Azure NAT Gateway Terraform – private subnet outbound architecture

Azure NAT Gateway with Terraform: Designing Outbound Access for Private Subnets

Private workloads still need the internet.
Not for exposure — but for controlled, auditable outbound traffic.

In Azure, outbound connectivity is often treated as an afterthought — yet Azure NAT Gateway Terraform provides a clean, architecture-grade way to design outbound identity for private subnets.

In production platforms, the real architectural question is not “does this VM have internet access?”
The real question is:

Where does the outbound identity of my private workloads live?

This article shows how Azure NAT Gateway acts as an egress boundary, not just a connectivity helper — and how to model this boundary cleanly with Terraform / OpenTofu.

❌ The common anti-pattern: public IP on a private VM

A surprisingly common solution to outbound connectivity looks like this:

  • VM in a “private” subnet

  • Public IP attached directly to the NIC

  • Outbound traffic works

  • Cloud-init can install packages

  • apt update succeeds

Architecturally, this breaks multiple design principles:

  • The workload now owns a public network identity

  • Egress identity is coupled to the VM lifecycle

  • Security boundaries are blurred

  • Auditing outbound traffic becomes harder

  • “Private subnet” becomes a naming convention, not a boundary

This is not an access plane.
This is accidental exposure.

✅ The architectural pattern: NAT Gateway as an egress boundary

The correct design separates concerns:

  • Workloads remain private

  • Subnets define security and traffic boundaries

  • Outbound traffic exits the VNet through a dedicated egress plane

This is exactly what Azure NAT Gateway provides:

  • A stable outbound public IP

  • No inbound exposure

  • Subnet-level attachment

  • Clear ownership of egress identity

Azure NAT Gateway is not about “giving internet to VMs”.
It is about centralizing outbound identity for a network tier.

👉 See the full Azure infrastructure with Terraform architecture model: Azure Infrastructure with Terraform – Architecture Model

🌐 Network foundation

Outbound traffic control starts at the network layer.

This example assumes a purpose-driven virtual network layout where subnets define traffic responsibilities — similar to the approach described here:

👉 Azure VNet Terraform Module – Explained

Once the network contract exists, egress policies such as NAT Gateway can be applied without redesigning the platform later.

🧭 Azure NAT Gateway with Terraform: outbound access for private subnets

In this reference architecture:

  • Backend VMs live in a private subnet

  • No public IPs are attached to any VM

  • A NAT Gateway is associated with the private subnet

  • Outbound traffic flows through the NAT Gateway public IP

  • Inbound traffic (if any) is handled separately (for example via Azure Load Balancer)

Key properties of this pattern:

  • Private subnet has controlled egress

  • Outbound IP is stable and auditable

  • Workloads have no public network identity

  • Egress plane is explicitly modeled in Infrastructure as Code

NAT Gateway defines the outbound contract for this subnet. Workloads do not “have internet access” — the platform exposes a controlled egress plane. This makes outbound traffic explicit, auditable, and decoupled from individual VMs.

Figure 1. Azure NAT Gateway with Terraform – private subnet outbound architecture

🧩 Modeling the egress plane with Terraform

The following example shows how to model Azure NAT Gateway Terraform as a dedicated egress boundary for a private subnet:

module "natgw" {
  source = "github.com/foggykitchen/terraform-az-fk-natgw" 

  name                = "fk-natgw"
  location            = azurerm_resource_group.foggykitchen_rg.location
  resource_group_name = azurerm_resource_group.foggykitchen_rg.name

  create_public_ip = true

  subnet_associations = {
    private_subnet = {
      subnet_id = module.vnet.subnet_ids["fk-subnet-private"]
    }
  }

  tags = var.tags
}

This makes the design intent explicit:

  • Outbound identity is owned by the platform layer

  • The subnet is the egress boundary

  • Workloads consume the egress plane instead of owning public IPs

No hidden defaults.
No portal-driven magic.
Just architecture as code.

🔍 Verifying outbound identity from a private VM

To prove that outbound traffic flows through the NAT Gateway, verify the egress IP from the private VM.

Using Azure Portal → Run Command, execute:

curl https://ifconfig.me

Verification result:

Figure 2. Azure NAT Gateway outbound IP verification using Terraform and Run Command

The returned IP matches the public IP assigned to the NAT Gateway.

This confirms:

  • Outbound traffic is centralized

  • The VM has no independent public identity

  • The NAT Gateway is the single egress boundary

🎯 Why this pattern matters in real platforms

This design becomes critical when you care about:

  • Egress allow-listing in partner systems

  • Firewall rules on external services

  • Auditing outbound traffic

  • Regulatory and compliance requirements

  • Zero-trust networking models

  • Private Endpoints combined with controlled internet egress

Without NAT Gateway, outbound identity is:

  • Implicit

  • Ephemeral

  • Or incorrectly attached to workloads

With NAT Gateway, outbound identity becomes a platform contract.

🧠 Design notes

Some principles that emerge from this pattern:

  • Outbound connectivity is an architectural plane, not a VM feature

  • Private subnets without egress design are operationally broken

  • Egress identity should be owned by the platform, not the workload

  • NAT Gateway is a boundary, not a convenience

  • Terraform modules should express design intent, not just resources

This is the same design philosophy behind:

Each plane has a role. Each boundary must be explicit.

📂 Reference implementation

This article is based on the FoggyKitchen reference module:

terraform-az-fk-natgw
Reusable Terraform / OpenTofu module for Azure NAT Gateway with clean subnet-level egress patterns.

The repository includes runnable examples:

🧭 Closing thought

If you don’t explicitly design your egress plane, your platform will design one for you — usually in the worst possible way.

Azure NAT Gateway with Terraform is not about internet access. It is about where your platform’s outbound identity lives.

👉 Egress is not about internet access. It is about defining how your platform is seen from the outside.

🚀 If you want to see how networking, compute, storage, and private connectivity come together into a complete Azure platform — built step by step with Terraform/OpenTofu:
➡️ Explore the Azure Fundamentals course: https://foggykitchen.com/courses/azure-fundamentals-terraform-course/
 
azure fundamentals terraform course architecture diagram with vnet subnets private endpoints and compute

From NAT Gateway to Real Azure Egress Architecture

This example shows how outbound connectivity is controlled at the subnet level — but real Azure platforms require consistent egress design across all workloads.

NAT Gateway is a core building block of production-grade Azure architectures.

🔒 Lifetime • ⏱️ Self-paced • 🧪 Real labs

Check also other courses:​

Leave A Reply

Build Real Azure Architecture with Terraform / OpenTofu

Learn how to design, provision, and evolve Azure platforms step by step — starting from networking, through compute and storage, to private connectivity.

No portals. No shortcuts. Just real, production-ready architecture.

🎓 What you’ll learn:
- Virtual Network design and subnet architecture
- Compute patterns (VMs, Load Balancers, scaling)
- Storage layers (Blob, File, Disks)
- Private connectivity (Private Endpoints, DNS, NAT Gateway)

azure fundamentals terraform course architecture diagram with vnet subnets private endpoints and compute