The situation
A logistics company needs to expose a consignment-tracking API to four freight partners. Each partner runs their own AWS account, two of them in a different region, and one is not on AWS at all but has a Direct Connect link into the company’s network already.
The company’s requirement is narrow. Partners call one API, over HTTPS, and must reach nothing else in the VPC. The security team wants no inbound path from a partner network into the company’s address space, and no dependency on the partners’ internal security posture, on the reasonable grounds that the company cannot audit four other organisations.
Two complications. Two of the partners use 10.0.0.0/16 internally, which is the company’s range as well. And a previous integration with a fifth partner, built as a VPC peering connection three years ago, is the reason this requirement is worded so carefully: that peering gave the partner a route to the whole VPC, and an incident at their end became an incident at this one.
What actually matters
The first thing that matters is that most connectivity options join networks, and joining networks grants reachability to everything routing allows, restricted afterwards by security groups. The requirement here is the opposite shape: grant one service, and have no network-level path to anything else. A control that starts by connecting and then restricts is fighting its own default.
The second is that overlapping address space is not a detail to solve around; it is a signal about which options are viable. Peering and VPN both need non-overlapping CIDRs, and two partners using the same range as the company removes both from consideration before any security argument is made.
The third is directionality. A partner needs to reach into the company, and the company does not need to reach the partner. A mechanism that establishes one-way exposure fits the requirement better than one that creates mutual reachability and then denies half of it with rules that somebody could later change.
The fourth is that the company cannot audit its partners, so the design should assume a partner is compromised and ask what that gets them. Under peering, it gets them whatever the company’s security groups allow, and those change over time as teams add rules. Under a service-level exposure, it gets them the one API, permanently, because the mechanism cannot express anything else.
Underneath it, one partner is not on AWS, which means whichever mechanism is chosen may need a second answer for them rather than being forced to fit all four.
What we’ll filter on
- Does it connect networks, or expose one service?
- Does it work with overlapping CIDRs?
- Is the reachability one-way or mutual?
- What does a compromised partner reach?
- Does it work for a partner who is not on AWS?
- Who manages the credential or the acceptance, and can it be revoked unilaterally?
The landscape
VPC peering. A routing relationship between two VPCs. It is simple, has no bandwidth bottleneck and no per-GB charge within a region, and it is the mechanism that caused the earlier incident. It requires non-overlapping CIDRs, it is not transitive, and once peered the reachability is bounded only by route tables and security groups. It scales badly across many partners, at n-squared connections.
Site-to-Site VPN. An encrypted tunnel to a customer gateway, terminating on a Virtual Private Gateway or a Transit Gateway. It suits partners not on AWS and connects networks in the same way peering does, with the same overlapping-CIDR constraint and the same “reachable then restricted” shape.
Transit Gateway peering. Connects Transit Gateways across regions or accounts. It is the scalable version of joining networks, and it is still joining networks.
AWS PrivateLink. A service provider creates an endpoint service backed by a Network Load Balancer or Gateway Load Balancer; a consumer creates an interface endpoint in their own VPC, which appears as an ENI with an address from the consumer’s own range. Traffic flows from consumer to provider only. The networks are never connected, so overlapping CIDRs are irrelevant, and the consumer reaches exactly the service behind the endpoint service and nothing else. The provider controls an allow-list of principals permitted to connect, and acceptance can be manual.
API Gateway with a private endpoint. A private REST API reachable through an interface endpoint, with a resource policy restricting which VPC endpoints or accounts may call it. It adds API-level controls, throttling, authorisers and usage plans on top of the network exposure, and it suits an API rather than an arbitrary TCP service.
A public API with strong authentication. Publish the API on the internet behind CloudFront and WAF, and control access with mutual TLS, signed requests, or OAuth. It works for every partner regardless of where they run, it costs no per-partner network configuration, and it puts the service on a public address, which is the thing the security team objected to.
Resource-based policies. Where the thing being shared is an AWS resource rather than a service the company runs, a resource policy on it may be the whole answer, with no network path involved at all.
Evaluation
Side by side
| Option | Joins networks | Overlapping CIDRs | Direction | Partner reaches | Works off-AWS |
|---|---|---|---|---|---|
| VPC peering | ✓ | ✗ | Mutual | Whatever SGs allow | ✗ |
| Site-to-Site VPN | ✓ | ✗ | Mutual | Whatever SGs allow | ✓ |
| Transit Gateway peering | ✓ | ✗ | Mutual | Whatever routes allow | ✓ via VPN |
| PrivateLink | ✗ | ✓ irrelevant | Consumer to provider | One service | ✗ directly |
| Private API Gateway | ✗ | ✓ irrelevant | Consumer to provider | One API | ✗ directly |
| Public API with strong auth | ✗ | ✓ irrelevant | Client to service | One API | ✓ |
The overlapping-CIDR column eliminates the top three for two of the four partners before any security judgement is applied, which is convenient because the security judgement points the same way. The bottom three all satisfy “one service and nothing else”, and they differ on whether the partner is on AWS.
The solution
PrivateLink for the three AWS partners, a public endpoint with mutual TLS for the one that is not, and retire the peering that started this.
Stand up an endpoint service in front of the tracking API: a Network Load Balancer targeting the API’s tasks, exposed as a VPC endpoint service, with an allow-list naming the three partner account principals and acceptance set to manual. Each partner creates an interface endpoint in their own VPC and reaches the API through a private address from their own range. The company’s network is never joined to theirs, the overlapping 10.0.0.0/16 is irrelevant because no routes are exchanged, and a compromised partner reaches the tracking API and has no path to anything else, permanently, because the mechanism cannot express anything else.
The cross-region partners are handled the same way, because PrivateLink supports cross-region endpoint connections, so their region difference stops being a design factor.
The partner not on AWS gets the public path, and it is worth being clear that this is a different security posture rather than a lesser one. Publish the API through CloudFront with WAF in front, and require mutual TLS so the partner authenticates with a certificate issued by the company’s private CA. The API is on a public address and unauthenticated requests get nowhere. The existing Direct Connect link is available as an alternative, and it has the same shape as the VPN option: it joins networks, so choosing it would reintroduce the problem the requirement exists to avoid.
Then retire the peering connection with the fifth partner, which is the finding that prompted all of this. Migrate them to PrivateLink and delete the peering rather than leaving it in place with tightened security groups, because a peering with restrictive rules is one rule change away from being a peering with permissive ones.
Layer the API’s own controls on top of the network exposure regardless of path. Authorisation per partner, usage plans and throttling per partner, and access logs attributable to a partner. Network exposure decides who can reach the endpoint; the API decides what they can do, and both are needed. A partner reaching the endpoint through PrivateLink is authenticated as a network peer, not as a caller.
Why not peering with tight security groups. It meets the requirement on the day it is configured, and the reachability is bounded by rules that many people can change over years. The earlier incident is the argument, and the mechanism-level guarantee is worth more than a rule.
Why not put everyone on the public endpoint and skip PrivateLink. It works, it is simpler, and it puts a private service on a public address for three partners who did not need it there. It also makes the company’s exposure dependent on the API’s authentication being correct, where PrivateLink adds a layer that is correct by construction.
Worked example
The endpoint service takes an afternoon. The NLB already existed in front of the API; exposing it as an endpoint service is a configuration, and the allow-list is three account ARNs.
The first partner connects the following week. The interesting moment is when their network team asks which CIDR to allow in their route table, and the answer is none: the endpoint is an ENI in their subnet with an address from their own range, and there is no route to add. That conversation happens with all three partners and is the clearest demonstration of what the mechanism does.
The overlapping-CIDR partners connect with no discussion of addressing at all, which under the peering design would have required one of the two organisations to renumber.
The off-AWS partner takes longer, mostly on certificate logistics: issuing them a client certificate from the private CA, agreeing a rotation schedule, and getting their integration server configured. The mutual TLS handshake fails twice on an intermediate certificate not being sent, which is the usual failure and takes a packet capture to see.
Retiring the peering surfaces one thing nobody expected. A reporting job in the company’s account had been reaching into the fifth partner’s VPC over the same peering, in the other direction, unnoticed for two years. It is a legitimate integration that nobody documented, and it needs its own answer, which turns out to be an endpoint service on the partner’s side pointing the other way.
What’s worth remembering
- Peering, VPN and Transit Gateway peering all join networks and then restrict with rules; PrivateLink exposes one service and cannot express anything else, which is a mechanism-level guarantee rather than a configuration.
- Overlapping CIDRs eliminate the network-joining options outright, and PrivateLink is unaffected because no routes are exchanged between the two address spaces.
- PrivateLink is directional: the consumer reaches the provider and not the reverse, which matches how most partner integrations actually work.
- The consumer’s interface endpoint gets an address from the consumer’s own range, so there is nothing for their network team to route, which is the clearest sign the networks are not connected.
- Assume a partner is compromised and ask what that reaches. Under peering it is whatever security groups currently allow, which changes over years; under PrivateLink it is the one service, permanently.
- Network exposure and API authorisation are separate layers: reaching an endpoint through PrivateLink authenticates a network peer, not a caller, so per-partner authorisation, throttling and logging are still required.