Introduction#
Most teams start with per-environment networks; Dev, QA, and Prod each with their own NAT, firewall, DNS, and load balancers. This approach is simple at first but quickly becomes costly, inconsistent, and difficult to secure.
In this post, I walk through how to adopt a hub-and-spoke network architecture secured with Cloudflare Zero Trust (ZTN). I cover why teams choose this model, how traffic flows, and the security benefits in production.
This is a write-up of a session I ran in 2025.
The Problem: Per-Environment Networking#
Each environment duplicating infrastructure looks like this:
- NAT, firewall, load balancer, DNS repeated in every environment
- Multiple ingress/egress points to manage
- Firewall policies scattered and inconsistent
- Logs and monitoring fragmented
- Higher costs and configuration drift risks
What seems easy for a small setup becomes a bottleneck at scale.
The Solution: Hub-and-Spoke Architecture#
In a hub-and-spoke model:
- The hub contains shared services: NAT, firewall, DNS, load balancer.
- Spokes are isolated environments (Dev, QA, Prod) that stay private.
- All ingress and egress flows through the hub.
Benefits:
- Centralized firewall and NAT management
- Uniform policies
- Reduced cost (one NAT, one firewall instead of many)
- Easier audits and observability
Traffic flows#
Per-environment model#
- Public traffic hits environment-specific load balancers.
- Applications egress through separate NATs.
- Each environment manages its own firewall rules.
Hub-and-spoke model#
- Public traffic flows → hub load balancer → spokes.
- Outbound traffic flows → spokes → hub NAT → internet.
- Developers and admins authenticate via Zero Trust before reaching any spoke.
Cloudflare Zero Trust#
Cloudflare Zero Trust replaces traditional VPN-based access with identity and context-aware policies:
- No public IPs needed for internal services
- Access authenticated per user, device, and policy
- Granular access control instead of broad VPN tunnels
With Cloudflare ZTN, neither the hub nor the spokes need public exposure. Access flows through Cloudflare’s global edge, authenticated per user/device/policy.
In practice, this gave me tighter access control and much cleaner audit trails than a shared VPN model.
Deploying the Cloudflare connector#
Run the cloudflared daemon on a hub VM:
sudo cloudflared service install <token>
Then apply a strict firewall rule so cloudflared can only reach Cloudflare endpoints on TCP/UDP 7844.
From there, internal spokes no longer need public IPs. Developer and admin access goes through Cloudflare, while production traffic can continue through the external load balancer.
{
name = "allow-cloudflared-to-endpoints"
description = "Allow cloudflared egress to the cloudflare endpoints"
action = "allow"
direction = "EGRESS"
priority = 501
dest_fqdns = [
"region1.v2.argotunnel.com",
"region2.v2.argotunnel.com",
"cftunnel.com",
"h2.cftunnel.com",
"quic.cftunnel.com"
]
layer4_configs = [
{
ip_protocol = "tcp"
ports = ["7844"]
},
{
ip_protocol = "udp"
ports = ["7844"]
}
]
}
See the Cloudflare Docs – Tunnel with Firewall.
Final architecture#
The final state looks like this:
- Hub centralises NAT, firewall, and load balancers
- Spokes are fully private
- Cloudflare Tunnel provides secure developer/admin access
- End users reach production apps only via the external load balancer
This pattern isolates environments, simplifies operations, and eliminates public exposure.
You trade a bit of routing complexity for a much cleaner security and operations model.
Industry references#
Google Cloud#
Google Cloud publishes a reference hub-and-spoke model with Fortinet appliances protecting the hub.
See the Google Cloud – Fortinet Reference Architecture.
Microsoft Azure#
Azure publishes a reference hub-and-spoke model with Azure Firewall appliances, Bastion, and VPN gateways protecting the hub.
See the Hub-spoke network topology in Azure.
Tradeoffs#
No design is free:
- Routing is more complex than per-environment
- Hub is a critical dependency → must be highly available
- Steeper learning curve for teams
- Centralization means changes affect all environments
Key considerations#
When deploying hub-and-spoke, plan for:
- IP address space (avoid overlaps)
- Non-transitive peering (spoke-to-spoke must go via hub, or use Shared VPC / PSC / NCC)
- Scaling limits (peering, firewall throughput,
cloudflaredsizing) - High availability (multi-zone, multi-region hub design)
Hands-on resources#
I published Terraform examples that show three ways to deploy Cloudflare Tunnels in hub-and-spoke:
- Full IaC with Kubernetes (complete automation)
- Manual + Kubernetes (use existing tunnel, deploy cloudflared only)
- Manual VM on GCP (run cloudflared on Compute Engine)
Cloudflare Zero Trust Terraform templates (GitHub)
Further Reading & Resources#
- How Cloudflare does outbound-only connections
- Cloudflare firewall configuration for tunnels
- GCP Hub-and-Spoke Architecture (official reference)
- GCP Hub-and-Spoke in practice with Fortinet
- Azure Landing Zone – Hub-and-Spoke Architecture
- Cloudflare Zero Trust Terraform templates (GitHub)
Closing note#
Hub-and-spoke with Zero Trust is not magic, but it is practical. If your environments are growing and your network policy is getting noisy, this pattern is worth piloting.