Tag Archives: AWS Transit Gateway

VPC Lattice: What It Actually Replaces, What It Costs, and When I’d Reach for It

AWS App Mesh shuts down on September 30, 2026. Not “enters maintenance mode” — the console and the resources stop working. If you’re one of the teams that bet on it in 2019 for EKS service-to-service traffic, you’ve got a couple of months left, and AWS has been pointing everyone at the same replacement for ECS workloads and EKS workloads alike: Amazon VPC Lattice.

That deadline is a decent excuse to actually understand what Lattice is, because it’s not just an App Mesh clone. It quietly replaces a chunk of what Transit Gateway and PrivateLink do too, and it changes some assumptions network engineers have had baked in since VPC peering existed. Worth twenty minutes even if you have no App Mesh to migrate.

What VPC Lattice actually is

Strip away the marketing and VPC Lattice is a managed, regional application-layer proxy that sits between your consumers and your services, handles service discovery, applies IAM-based authorization, and routes requests — all without you deploying a load balancer, a sidecar, or a peering connection. AWS’s own description is that it manages network connectivity and application layer routing between services across different VPCs and AWS accounts, and that’s a fair summary, if a little dry.

The mental model that clicked for me: think of it as a load balancer that doesn’t live in any one VPC. You publish a service into a service network (a logical boundary, not a piece of infrastructure you provision), and any VPC or account associated with that service network can reach it by DNS name — no route tables, no CIDR planning, no peering mesh growing into an unmanageable tangle.

Lattice Service Network.

A service network can span accounts via AWS Resource Access Manager, so a platform team can own the network and share it out to application teams without those teams ever touching a route table. That’s the part that made this interesting to me as an architect rather than as a networking hobbyist — it moves network topology out of the app team’s problem space entirely.

What it’s quietly replacing

Nobody built this in a vacuum. Every one of these had a gap Lattice was built to close.

VPC peering doesn’t scale past a certain account count — it’s point-to-point, so N accounts means something close to N² connections, and overlapping CIDRs break it outright. Lattice’s data plane assigns consumers a link-local address and doesn’t care what your VPC CIDR looks like, overlapping or not.

Transit Gateway solved the peering-mesh problem at layer 3/4 — it’s still the right tool for routing IP traffic between VPCs and on-premises networks at scale, and I wouldn’t rip one out to replace it with Lattice. But TGW has no concept of an HTTP request, a path, or an identity. It moves packets, not requests. If your actual problem is “service A needs to call /v2/orders on service B and I want to enforce that with IAM,” TGW can’t help you get there on its own.

AWS PrivateLink is the closest sibling — it’s also a proxy-based, non-peering way to expose a service across accounts. The difference is PrivateLink is fundamentally point-to-point: each consumer VPC needs its own interface endpoint, and there’s no native request-level routing or IAM authorization baked into the data path. Lattice centralizes that into one service network that many consumers attach to, and layers on HTTP-aware routing rules on top.

AWS App Mesh is the one with the deadline. It gave you real service-mesh features — client-side retries, circuit breaking, fine control — but it did that with an Envoy sidecar next to every task, which is real operational weight: certificate rotation, sidecar upgrades, resource overhead per pod. Lattice deliberately drops the sidecar. You lose some of App Mesh’s client-side sophistication in the trade — Lattice’s routing and auth decisions happen server-side, not in a proxy next to your code — but for most teams that’s a fair trade for not operating a mesh control plane.

VPC PeeringTransit GatewayPrivateLinkVPC Lattice
OSI layerL3L3/L4L3/L4L7 (app layer)
Cross-account model1:1 meshHub-and-spoke1:1 endpoint per consumerMany-to-many via service network
CIDR overlap tolerantNoNoYesYes
Identity-aware authNoNoNo (SG/NACL only)Yes (IAM/SigV4)
Request-level routingNoNoNoYes (path, method, header, weighted)
Sidecars requiredNoNoNoNo

How it’s actually built

Four concepts do the work. A service is the logical front door — listeners, rules, target groups — conceptually a load balancer, but one that isn’t tied to a single VPC. A listener is a protocol and port (HTTP, HTTPS, or TLS_PASSTHROUGH). A rule matches on path, HTTP method, or header and forwards to a target group, which can hold EC2 instances, IP addresses, Lambda functions, or an Application Load Balancer, and — as of the more recent releases — ECS and Fargate tasks natively alongside EC2 and EKS.

Worth calling out explicitly: Lattice terminates HTTPS itself using an ACM-managed certificate, which is convenient, but it only does server-side TLS. If you need mutual TLS, you have to use a TLS_PASSTHROUGH listener and let the target negotiate the client certificate — Lattice’s own data plane won’t do mTLS termination for you.

The newer half of the story is VPC Resources and Resource Gateways, which let you expose non-HTTP TCP endpoints — a database, an internal domain name, an on-premises system reachable over Direct Connect or VPN — through the same service network model, complete with the same IAM controls. This is the part that pushes Lattice past “App Mesh replacement” and into “how do I expose an RDS instance to another account without a peering connection or a bastion.” It’s genuinely useful, and it’s the feature I’d bring up first if a platform team asked me why this deserves attention beyond the App Mesh deadline.

For Kubernetes specifically, the AWS Gateway API Controller implements the open-source Kubernetes Gateway API and translates Gateway and HTTPRoute objects into Lattice service network objects behind the scenes. If your EKS team already writes Gateway API manifests, adopting Lattice barely changes their workflow — it’s the controller that’s doing the AWS-specific work.

Authorization runs on IAM. Auth policies attached at the service network or service level use standard IAM policy JSON, and clients authenticate with SigV4-signed requests, the same signing scheme every other AWS API call uses. This is a genuine strength if your org already centers identity around IAM roles, and a genuine adoption cost if you have legacy clients that have never had to sign a request in their life. Budget time for that conversation — it comes up in almost every migration writeup I’ve read.

When I’d actually reach for it

When Lattice makes sense.

Lattice earns its place when the actual requirement is cross-account or cross-VPC service exposure with identity-aware access control and some request-level routing, and you don’t want to own a control plane to get it. New microservice builds, platform teams centralizing how application teams expose services to each other, EKS shops trying to get off App Mesh before the clock runs out, and anyone who’s been maintaining a PrivateLink endpoint-per-consumer sprawl are the clearest fits.

I’d think twice before using it as a wholesale Transit Gateway replacement. It’s not built for raw IP-layer routing at TGW’s scale, and — as I’ll get to in pricing — the per-service hourly charge adds up fast if you’re running hundreds of services with modest traffic each. I’d also pause if you need genuine client-side mesh behavior: retries with backoff, circuit breakers, fault injection for chaos testing. That logic sits server-side in Lattice, which is simpler to operate but less flexible than a sidecar that runs next to your code.

Pros and cons, plainly

The upside is real: no sidecars to patch, no peering mesh to keep untangled, IAM auth you already understand, weighted routing for blue/green and canary out of the box, and a service directory that gives you an actual inventory of what’s exposed to what. Observability is baked in too — access logs and CloudWatch metrics per service without instrumenting anything yourself.

The downside is mostly about maturity and rigidity. It’s newer than TGW or PrivateLink, so you’ll hit rough edges — G2 reviewers flag protocol support currently limited to HTTP, HTTPS, and gRPC, and region coverage, while it’s grown a lot since GA, still isn’t everywhere. Security group design has a real gotcha: targets need to allow inbound traffic from the Lattice association security group, not from the consumer’s VPC CIDR, and that trips people up in early deployments because it looks wrong at first glance. And moving to IAM/SigV4 auth is a genuine client-side change — nothing you can skip past.

Pricing — the part that actually decides adoption

Three dimensions drive the bill: an hourly charge per service, a per-GB data processing charge, and a per-request (or per-connection, for TLS_PASSTHROUGH) charge above a free tier. In US East (N. Virginia), that’s $0.025 per service-hour, $0.025 per GB processed, and $0.10 per million requests beyond the first 300,000 free per hour. Compare that to PrivateLink at roughly $0.01 per hour per AZ plus $0.01/GB with volume discounts, and it’s clear Lattice costs more per unit — you’re paying for the extra L7 intelligence and the simpler operating model, not for cheaper bytes.

Run the numbers on a single, modestly busy service and it’s not scary: one service processing 100 GB and 200,000 requests an hour for a month lands around $18–20 in hourly charges alone before data and requests, and a heavier example AWS publishes — one service with HTTPS and TLS listeners together processing 2,100 GB and millions of requests a month — comes out to roughly $268 a month. The bill gets serious at fleet scale. One cloud architect’s published comparison modeled 200 services across 100 accounts pushing 30TB a month: Transit Gateway came out around $4,250, Lattice around $4,840 — roughly a 14% premium, driven almost entirely by the per-service hourly charge rather than data processing, which was actually cheaper for TGW in that scenario. If you’re running that many low-traffic services, the fixed hourly cost per service matters more than the per-GB rate.

VPC Resources (the database/on-prem exposure feature) bill separately and use a tiered per-GB rate: $0.01/GB for the first petabyte in a Region each month, dropping to $0.006 and then $0.004/GB at higher volumes, plus a small hourly charge per resource. Worth modeling separately from your service traffic if you’re planning to route a lot of data through it.

Quotas worth knowing before you design around them

These are the ones that actually shape an architecture, not just trivia:

QuotaDefaultAdjustable
Services per Region2,000Yes
Service networks per Region50Yes
Service associations per service network500Yes
VPC associations per service network500Yes
Target groups per service10Yes
Targets per target group1,000Yes
Listeners per service2Yes
Rules per listener10Yes
Requests/sec per service per AZ10,000Contact your SA/TAM
Bandwidth per service per AZ10 GbpsContact your SA/TAM
Connection idle timeout (HTTP/gRPC)1 minuteContact your SA/TAM
Max connection lifetime10 minutesFixed
Service networks a VPC can associate with directly1— (use service-network VPC endpoints for more)

Full, current numbers are on the official quotas page — check it before you design, not after you hit a wall. The one that catches people off guard most is the one-service-network-per-VPC-via-direct-association limit; if you need a VPC in more than one service network, you’re routing through service-network VPC endpoints instead, which is an extra layer to plan for.

A few concrete use cases

A platform team centralizing how forty application teams expose internal APIs to each other, replacing forty sets of ad-hoc security-group rules and a slowly decaying peering mesh with one service network and a consistent IAM auth policy. A company running canary deployments where 5% of production traffic gets weighted onto a new service version before a full cutover — Lattice’s weighted target groups do this natively, no custom load balancer logic required. An EKS shop migrating off App Mesh before the September deadline, using the Gateway API Controller so app teams keep writing the same HTTPRoute manifests they already know. And the resource-gateway pattern: exposing a shared RDS instance in a data-platform account to a dozen consuming accounts without provisioning a PrivateLink endpoint in every one of them.

Why this belongs on your radar even without the App Mesh deadline

The App Mesh shutdown is the forcing function, but the more interesting shift is architectural: AWS is pulling network topology out of individual VPCs and into a service-oriented abstraction that’s owned centrally and consumed by reference. That’s a meaningful change to how you’d write a network architecture standard or review an ADR — the question stops being “how do these two VPCs route to each other” and starts being “which service network does this belong to, and what’s the IAM policy governing who can call it.” If you own architecture review or network standards for your org, that’s worth getting ahead of before it shows up in someone else’s design doc and you’re reviewing it cold.

It’s not a wholesale replacement for Transit Gateway, and it’s not free — budget the per-service hourly charge honestly before you commit a few hundred services to it. But for the specific problem it targets, cross-account and cross-VPC service exposure with identity-aware access control, it’s a cleaner answer than anything that came before it, and worth prototyping now rather than in month eleven of an App Mesh migration deadline.

AWS Landing Zone, Part 3: Transit Gateway, Centralized Egress, and Where IPAM Earns Its Keep

Five VPCs connected by peering need ten peering connections. Ten VPCs need forty-five. Every new VPC means going back into the route tables of every existing VPC to add the new relationship, and every peering connection is a distinct thing that can be misconfigured, forgotten, or left open longer than it should be. That math is the whole argument for hub-and-spoke, and it’s why almost nobody designs a multi-account AWS network as a full peering mesh past the first few accounts.

AWS Landing Zone – Part 3

Part 1 and Part 2 covered the account structure and the guardrails that govern it. This post is about the network underneath: Transit Gateway as the hub almost everyone reaches for, centralized egress and what it costs against the alternative, IPAM (IP Address Management) as the CIDR governance layer, and where VPC Lattice fits without pretending it replaces Transit Gateway wholesale.

Transit Gateway as the hub

AWS Transit Gateway is a managed, regional routing hub. Spokes, VPCs, VPN connections, Direct Connect, attach to it once, and it handles routing between them using its own route tables instead of point-to-point relationships. One Transit Gateway per Region is typically enough since it’s highly available by design, though there’s a legitimate case for more than one where you want to limit the blast radius of a routing misconfiguration or separate control-plane operations between teams. Cross-region connectivity happens through Transit Gateway peering; hybrid connectivity, Direct Connect or VPN, attaches the same way a VPC would.

The account this lives in matters. Transit Gateway, IPAM, and centralized egress infrastructure all belong in the Infrastructure OU’s networking account, sometimes literally called Network or Network Hub, not scattered across workload accounts and not in the Control Tower management account. That account becomes the place a network engineer actually works day to day, and it’s worth treating its own access and change process with the same care as the Security OU from Part 2.

Laid out, the topology looks like this:

Transit Gateway topology!

Every spoke VPC gets one attachment to the hub instead of a direct relationship with every other spoke. Whether Prod and Test can actually reach each other is a routing table decision inside the Transit Gateway, not something the topology forces one way or the other, which is exactly the control you lose with a flat peering mesh.

Centralized egress and what it actually costs

The other big reason to centralize on a hub isn’t just routing hygiene, it’s cost. Every VPC that needs internet access wants its own NAT gateway per Availability Zone for resilience, and NAT Gateway data processing charges add up fast once you’re running dozens of VPCs, each with its own pair or trio of gateways running independently. Centralizing egress means routing outbound traffic from every spoke through the Transit Gateway into a single egress VPC in the network account, where it exits through one set of NAT gateways instead of dozens. One practitioner audit found organizations spending around $15,000 a month on NAT Gateway data processing alone, spread thin across VPC after VPC, and cut that by 40 to 70 percent by consolidating.

Adding traffic inspection to that same choke point is a natural next step. AWS Network Firewall sits in the egress VPC and inspects traffic before it reaches the NAT gateway, at a real but bounded cost, roughly $0.40 an hour per endpoint plus a per-gigabyte processing charge, which is a fair trade in a regulated environment and a harder sell if you’re mostly optimizing for spend. One genuine gotcha here: DNS doesn’t follow this path by default. Route 53 Resolver and DNS Firewall are a separate egress route entirely, so centralizing your data-plane egress through Transit Gateway and Network Firewall doesn’t automatically mean your DNS queries are inspected the same way. If DNS-based filtering matters to your threat model, it needs its own explicit design, not an assumption that it rides along with everything else.

IPAM: get the CIDR plan right before account one

IP address planning is one of those things that’s cheap to fix before it exists and expensive to fix after. Amazon VPC IPAM gives you a hierarchical pool structure, a top-level pool subdivided into regional pools, then further into business-unit or environment pools, so that a new VPC in the Workloads_Test OU pulls its CIDR from a pool already guaranteed not to overlap with Prod, Sandbox, or anything else in the organization. IPAM should be delegated to the network account rather than run from the Control Tower management account, the same separation-of-duties instinct as everything else in this series.

The failure mode IPAM prevents is duller than a security incident but just as disruptive: two teams independently pick 10.0.0.0/16 for their VPCs, everything works fine in isolation, and then someone needs to connect the two networks and discovers the ranges collide. Fixing that after the fact means readdressing a live VPC, which is exactly the kind of maintenance window nobody wants to schedule. Getting the CIDR plan right before the first account exists costs an afternoon. Getting it wrong costs a migration.

Route 53 Profiles solve the equivalent problem for DNS. Instead of manually associating private hosted zones, resolver rules, and DNS firewall rule groups to every VPC individually, you bundle them into a single profile in the network account and share it across accounts through AWS RAM. New VPCs associate with the profile once and inherit the whole DNS configuration, rather than someone remembering to wire up each piece by hand every time an account gets vended.

Where VPC Lattice actually fits

VPC Lattice gets pitched sometimes as a Transit Gateway replacement, and that framing oversells it. Transit Gateway operates at Layer 3, it moves packets between IP addresses and doesn’t know or care which identity sent them; security has to come from route tables, security groups, and NACLs. VPC Lattice operates at Layer 7, HTTP, HTTPS, and gRPC specifically, and it’s service-centric rather than network-centric: services register into a service network, consumers discover them by DNS name, and access is governed by IAM policy rather than which subnet you happen to be in. It’s also currently single-region, so it isn’t a drop-in for anything that needs to span regions the way Transit Gateway peering does.

In practice these coexist rather than compete. Transit Gateway keeps doing the job of moving bulk traffic, hybrid connectivity, and anything that isn’t a clean HTTP service call. VPC Lattice picks up new service-to-service communication where IAM-based authorization is a better fit than managing security group rules across account boundaries. I’d reach for Lattice for a new internal API a team wants to expose across accounts without punching new holes in the network layer, not as a project to migrate an existing Transit Gateway backbone onto.

As a decision, it collapses to one real question about the shape of the traffic:

Shaping traffic!

Bulk data, non-HTTP protocols, or anything crossing regions stays on Transit Gateway. A specific, well-defined service boundary within one region is where Lattice earns its keep, and it’s rarely an either-or choice at the level of the whole network.

What’s next

The network is the part of a landing zone that’s genuinely painful to change once workloads depend on it, which is exactly why it deserves the same up-front discipline as the OU structure in Part 1. The last post in this series moves from design to operations: how account vending actually scales once you’re provisioning dozens of accounts a month, why Control Tower can tell you about drift automatically but won’t fix it for you, and the CI/CD pipeline that should sit in front of every change to the guardrails from Part 2 before it reaches a real account.