Transit Gateway — centralized egress
Centralized egress inspection using an AWS Transit Gateway (TGW) hub. All internet-bound traffic from three workload (spoke) VPCs is steered through a single dedicated edge/inspection VPC, where a pair of Enforza NVAs — one per Availability Zone — perform secure NAT and L7 egress filtering before traffic leaves via the Internet Gateway. Return traffic is forced back through the same firewall that handled the outbound flow — which is what makes a stateful NVA work correctly behind a TGW. Deploy with Terraform or CloudFormation.
Architecture
Section titled “Architecture”Three workload spoke VPCs default-route to the TGW; the TGW forwards all egress to the edge VPC’s TGW attachment (appliance mode on), which pins each flow to one AZ / firewall. Each edge firewall SNATs out via its own EIP + IGW.
workload-a VPC workload-b VPC workload-c VPC 10.1.0.0/16 10.2.0.0/16 10.3.0.0/16 priv default 0/0→TGW priv default 0/0→TGW priv default 0/0→TGW └────────────────────┼────────────────────┘ TGW attachments (one per spoke) │ ┌──────────────┴───────────────────────────┐ │ TRANSIT GATEWAY (hub) │ │ default assoc/propagation DISABLED │ │ SPOKE RT : 0.0.0.0/0 → edge attach │ │ FIREWALL RT : 10.1/16→wl-a 10.2/16→wl-b │ │ 10.3/16→wl-c │ └──────────────┬───────────────────────────┘ edge VPC attachment · APPLIANCE MODE = enable ┌──────────────┴───────────────────────────┐ │ EDGE / INSPECTION VPC 10.0.0.0/16 │ │ tgw-subnet-a 10.0.2.0/28 tgw-subnet-b 10.0.3.0/28 │ │ 0/0 → FW-A ENI 0/0 → FW-B ENI │ │ Enforza FW-A (AZ0) Enforza FW-B (AZ1)│ │ EIP · SNAT · src/dst off EIP · SNAT · off │ │ public-a 10.0.0.0/24 public-b 10.0.1.0/24 │ │ 0/0 → IGW · 10.x/16 → TGW (return) │ └──────────────┬───────────────────────────┘ IGW → InternetWhat it deploys
Section titled “What it deploys”- One edge/inspection VPC
10.0.0.0/16: an IGW; two public subnets (10.0.0.0/24AZ0,10.0.1.0/24AZ1) each with an Enforza firewall + Elastic IP (source/dest check off); two TGW-attachment subnets (10.0.2.0/28AZ0,10.0.3.0/28AZ1). - A Transit Gateway (default route-table association and propagation disabled), with two TGW route tables: SPOKE and FIREWALL.
- The edge VPC TGW attachment with appliance mode enabled.
- Three workload VPCs (
10.1.0.0/16,10.2.0.0/16,10.3.0.0/16), each with two private subnets, a TGW attachment, and a default route to the TGW.
Prerequisites
Section titled “Prerequisites”- TWO Enforza deployment keys — one per edge firewall, each one-time-use (Onboard Firewall → Deployment Keys). Firewall A and B need different keys.
- A base OS AMI: defaults to the latest Amazon Linux 2023 (auto-resolved) — nothing to supply.
- Terraform ≥ 1.5 or the AWS CLI.
- IAM permissions for EC2, VPC, Transit Gateway, and Elastic IP; a region with ≥ 2 AZs.
How the bootstrap works
Section titled “How the bootstrap works”Each firewall launches the stock AL2023 AMI and runs a small user-data script at first boot:
curl -fsSL https://dl.neon.efz.io/install.sh | bash -s -- --regkey=<KEY> --name=<NAME>The installer sets up prerequisites and the engine and registers it. One key per
firewall: firewall A uses deployment_key_a (name enforza-edge-fw-a), firewall B
uses deployment_key_b (name enforza-edge-fw-b).
Option A — Deploy with Terraform
Section titled “Option A — Deploy with Terraform”cd terraformterraform initterraform apply \ -var "deployment_key_a=<KEY-FOR-FIREWALL-A>" \ -var "deployment_key_b=<KEY-FOR-FIREWALL-B>"# optional overrides:# -var 'base_ami_id=ami-xxxxxxxx' -var 'instance_type=c6i.xlarge'# -var 'ssh_key_name=my-key'# -var 'availability_zones=["eu-west-2a","eu-west-2b"]'Option B — Deploy with CloudFormation
Section titled “Option B — Deploy with CloudFormation”cd cloudformationaws cloudformation create-stack \ --stack-name enforza-03-tgw-centralized-egress-deployment-key \ --template-body file://template.yaml \ --parameters \ ParameterKey=DeploymentKeyA,ParameterValue=<KEY-FOR-FIREWALL-A> \ ParameterKey=DeploymentKeyB,ParameterValue=<KEY-FOR-FIREWALL-B> \ ParameterKey=AvailabilityZoneA,ParameterValue=eu-west-2a \ ParameterKey=AvailabilityZoneB,ParameterValue=eu-west-2bAfter either deploy, each firewall self-registers via its key on first boot and appears in the Enforza console within a minute or two — no manual claim step.
Packet path
Section titled “Packet path”Outbound (workload → internet):
- A workload sends to an internet IP; its private route table (
0.0.0.0/0 → TGW) enters the Transit Gateway via that spoke’s attachment. - The TGW SPOKE route table (
0.0.0.0/0 → edge attachment) forwards it to the edge VPC. - The packet arrives on the edge TGW attachment ENI in the same AZ it left
(appliance mode preserves AZ affinity); that TGW-subnet’s route table sends
0.0.0.0/0 → the same-AZ firewall ENI(AZ0 → FW-A, AZ1 → FW-B). - The firewall applies L7 egress policy and SNATs behind its EIP; its public
route table (
0.0.0.0/0 → IGW) sends the packet to the internet.
Return (internet → workload), symmetric:
5. The reply hits the firewall’s EIP; the firewall un-NATs it and, via its public
route 10.x.0.0/16 → TGW, hands it to the TGW.
6. The TGW FIREWALL route table has a route per workload CIDR pointing at that
workload’s attachment, so the reply reaches the originating spoke — over the same
AZ ENI and same firewall (appliance mode pinned the flow).
Scaling notes
Section titled “Scaling notes”Adding a workload VPC is three small, mechanical changes:
- Terraform: add one entry to the
workload_vpcsmap (name → CIDR + two subnet CIDRs);for_eachcreates the VPC, subnets, TGW attachment, spoke association, default route, and the FIREWALL-RT return route automatically. - CloudFormation: add the VPC + two subnets + route table + TGW attachment, one SPOKE association, and one FIREWALL-RT return route (following the Workload A/B/C blocks), plus the new CIDR to the firewall security-group ingress.
To scale throughput, raise instance_type; the two firewalls already give per-AZ
horizontal split via appliance-mode AZ affinity.
Teardown
Section titled “Teardown”# Terraformcd terraformterraform destroy \ -var "deployment_key_a=<KEY-FOR-FIREWALL-A>" \ -var "deployment_key_b=<KEY-FOR-FIREWALL-B>"
# CloudFormationaws cloudformation delete-stack --stack-name enforza-03-tgw-centralized-egress-deployment-keyRemember to remove the firewalls from the Enforza console after teardown.