Exam Room · Advanced Solutions Architect

Choosing PrivateLink for SaaS Vendor-to-Customer Connectivity

· 33 min read

Advanced Cloud Architecture · part of The Exam Room

The situation

Vantage Observability sells an ingestion API for metrics, traces and logs. It sits behind an Application Load Balancer on a public hostname, ingest.vantageobs.example, with a WAF in front and short-lived tokens for authentication. Eight enterprise customers signed this year. Four of them raised the same objection during procurement: production telemetry must not leave their network over the public internet, and their security teams will not approve egress to an internet destination whatever sits in front of it.

Vantage runs the ingest fleet from its own accounts, one production account per Region, and has no authority over anything a customer builds. The customers run their own multi-account organisations, and at least three of the eight already use parts of 10.0.0.0/8 that Vantage also uses. So the answer has to be one service definition, published once per Region, that many customer accounts consume from their own VPCs, with per-customer authorisation and an offboarding path that is not a network engineering project.

Five things could carry the traffic: a PrivateLink endpoint service, a PrivateLink resource endpoint, VPC peering, Transit Gateway, or the existing public endpoint hardened until the objection goes away. Only one of them describes a relationship between two companies.

What actually matters

An ALB with mTLS, SigV4 and a WAF is strongly authenticated and still fails this test, because the packets reach it across the internet. The requirement is about the path the bytes take, not the credential presented at the far end. An unauthenticated private endpoint would satisfy the stated requirement and be a bad idea for unrelated reasons. Keeping the two properties apart is what makes the procurement conversation short, and conflating them is how a vendor spends a quarter arguing about WAF rules for a security review that was never about authentication.

Vendor and customer address plans were designed a decade apart by people who never met. Asking a Fortune 500 network team to carve a dedicated /24 out of a plan that feeds their own inspection and routing design is an ask most deals do not survive. Any primitive that needs non-overlapping address space therefore drops out before the technical merits get weighed. The endpoint has to land on IP addresses from the consumer’s own subnets.

One side publishes, many consume, and each consumer must be invisible to the others. Onboarding should be an ARN added to a list and offboarding a removal, reviewable in a change ticket, rather than a peering connection to build and route tables to unpick in eight organisations. That asymmetry also decides where authorisation lives. A VPC endpoint policy is the customer’s usual lever for narrowing what an endpoint may do, and it does not apply here. For an endpoint service that is not an AWS service, AWS allows full access to the endpoint. Authorisation for what a request may write stays in Vantage’s own tokens, and the customer’s controls are the security group on the endpoint network interfaces plus whatever their platform team permits through identity policy.

Telemetry agents and SDKs across eight customers are configured with ingest.vantageobs.example, often baked into container images and configuration management the platform team does not own. A design that hands each customer a per-account endpoint URL turns one vendor change into eight customer rollouts. Resolving the familiar name to a private address from inside the consumer VPC keeps the change on Vantage’s side of the seam.

With PrivateLink the consumer owns the interface endpoint, so the consumer is billed for the endpoint network interface hours and for every gigabyte processed through it. AWS list price for data processing starts at USD$0.01 per GB for the first petabyte a Region each month, falling to USD$0.006 and then USD$0.004 in the higher tiers. Vantage stops paying internet egress on that traffic and starts having a pricing conversation with procurement instead. The same seam narrows what Vantage can observe. The source address arriving at the ingest fleet is the private IP of Vantage’s own load balancer nodes, so per-customer attribution has to come from somewhere other than the packet.

What we’ll filter on

  1. Works unchanged when both address plans overlap?
  2. Keeps the data plane off the public internet?
  3. Onboarding and revoking a customer is a policy change, not a routing change?
  4. Client hostname stays ingest.vantageobs.example?
  5. Clean seam, with neither company operating anything in the other’s account?
  6. Holds its shape as the customer count grows past a handful?

The landscape

PrivateLink endpoint services. A provider registers one or more Network Load Balancers as an endpoint service and gets back a service name of the form com.amazonaws.vpce.<region>.vpce-svc-<hash>. Consumers in other accounts create an interface VPC endpoint against that name, which places AWS-managed network interfaces in subnets they choose, with IP addresses from their own CIDR ranges. Traffic goes from the consumer’s endpoint network interface across the AWS network to the provider’s load balancer. Gateway Load Balancers can back an endpoint service too. That variant exists to insert inspection appliances into a traffic path, and it does not support private DNS names, so it is the wrong end of the product for an ingest API. Application Load Balancers cannot back an endpoint service at all; since September 2021 an NLB can register an ALB as a target, which is how a service that needs layer-7 routing gets there.

PrivateLink resource endpoints. A newer shape, aimed at reaching one specific thing rather than a load-balanced fleet. The owner describes a database, host, IP address or domain target as a resource configuration behind a resource gateway, shares it through AWS Resource Access Manager, and the consumer creates a resource endpoint against it. No load balancer is involved, and the resource gateway does not provide one. It carries TCP only, connections can only be initiated from the endpoint side, and ARN-based resources are limited to Amazon RDS. For a scaling HTTPS ingest fleet with a principal allow-list and manual acceptance per customer, the endpoint-service shape is the closer fit; resource endpoints are how a vendor would expose a single managed database to one customer.

VPC peering. A direct Layer 3 relationship between two VPCs. It cannot be created at all between VPCs with matching or overlapping IPv4 or IPv6 CIDRs, and that holds even when only the unused ranges overlap. Routing is non-transitive, each side maintains its own route table entries, and referencing a security group across the peering works only when both VPCs sit in the same Region. It suits two networks planned together under one governance domain.

Transit Gateway. A Regional router that VPCs, VPN and Direct Connect gateway attachments join. It scales to many-to-many and supports segmentation through multiple route tables, but a route table holds one route per destination prefix, so overlapping attachment CIDRs cannot be resolved to different attachments inside it. Someone also has to own the gateway, pay for the attachments and answer for the routing policy, and neither a vendor nor its customer has a reason to take that on for the other.

Public endpoint with strong authentication. The current design, tightened: WAF, mTLS, SigV4 or tokens, maybe CloudFront in front. Every one of those controls answers who is calling. None of them changes where the packets travelled.

Evaluation

Side by side

Mechanism Overlapping CIDRs Off the internet Policy-only onboarding Hostname unchanged Clean seam Scales with customers
PrivateLink endpoint service ✓ ✓ ✓ ✓ ✓ ✓
PrivateLink resource endpoint ✓ ✓ ✓ ✓ ✓ ✗
VPC peering ✗ ✓ ✗ ✗ ✗ ✗
Transit Gateway ✗ ✓ ✗ ✗ ✗ ✗
Public endpoint, hardened ✓ ✗ ✓ ✓ ✓ ✓

One row carries every tick. Peering and Transit Gateway fail on the first filter, which is enough on its own, and they fail again on the operational ones. The tempting misread is that peering is cheap, since it has no hourly charge and only attracts data transfer. Cheapness does not help when the connection cannot be created against an overlapping range, and cannot be created a ninth time without another round of address negotiation. Resource endpoints clear the network filters and fall over on the product. The hostname would survive, since a single resource configuration can carry a provider’s own custom domain name and the provider can have that name verified. The shape does not. Authorisation is a resource share in AWS RAM rather than a named-principal allow-list with a dated acceptance per connection, and a consumer can add a resource configuration shared with it to a service network that is shareable with further accounts unless the provider disallows that, which is the opposite of eight customers who cannot see each other.

Matching the relationship to the primitive

One-to-one shared governance, aligned CIDRs SaaS, many-to-one vendor publishes, customers consume Many-to-many, one org shared address plan across VPCs Two VPCs, one org CIDRs planned together non-transitive acceptable simple peering Vantage + 8 customers separate companies CIDRs overlap freely customers can't see each other 52 VPCs, one org central networking team prod / non-prod segments shared inspection hop CIDRs align? yes CIDRs overlap? yes One governance domain? yes Only two VPCs? transitive not needed? yes Publisher/consumer asymmetric? allow-list + acceptance? both yes Transitive many-to-many? central inspection seam? yes VPC Peering cheap, simple non-transitive wrong for SaaS PrivateLink endpoint service NLB / GWLB origin principal allow-list private DNS name Transit Gateway regional hub route table segmentation one governance domain
Three relationship shapes, three primitives. Vantage and its customers sit in the middle column and nowhere else.

The solution

Vantage publishes one endpoint service per Region, backed by a Network Load Balancer with a TLS listener on 443 in front of the ingest auto-scaling group, and requires manual acceptance. Customers create interface endpoints against the published service name in the subnets they choose. Everything interesting is in what that arrangement leaves to be decided.

Two gates, and only one of them revokes

Access is controlled twice. The principal allow-list decides who may create an endpoint, and it takes an ARN per entry: a whole account as arn:aws:iam::<account>:root, a single role or user, or * for a service open to everyone. The acceptance setting decides whether a created endpoint goes live, and with acceptance required each connection sits in PendingAcceptance until Vantage accepts it. Setting both, as Vantage does, means a customer can neither connect without being named nor go live without being approved, and the approval is a dated record of which account was let in.

Offboarding is where this gets misread. Removing a principal from the allow-list stops that account creating new endpoints and does nothing to connections already accepted, which keep passing traffic. Revoking a customer therefore means removing the principal and rejecting the existing endpoint connection, and a runbook that does only the first leaves a departed customer shipping telemetry. Leaving the service open to * with automatic acceptance has a consequence AWS states plainly: the load balancer is public, even though it has no public IP address.

Keeping the hostname

A private DNS name on the endpoint service is what keeps ingest.vantageobs.example in the customers’ agent configuration. Vantage proves it owns vantageobs.example by publishing a TXT record whose name and value AWS supplies. Once verification passes, every consumer that enables private DNS on its endpoint gets an AWS-managed private hosted zone associated with its VPC. That zone holds a CNAME from the private DNS name to the endpoint’s Regional DNS name. Requests from inside that VPC resolve to the endpoint network interfaces; requests from anywhere else resolve through public DNS to the public endpoint, so Vantage keeps the public record in place rather than deleting it.

Three constraints come with this. A service can carry exactly one private DNS name, though it may be a wildcard such as *.vantageobs.example. The consumer VPC must have DNS hostnames and DNS resolution both enabled or private DNS does nothing. And if verification later fails, perhaps because someone tidied the TXT record, new connection requests are denied while existing connections carry on, which is a failure that shows up in onboarding weeks after the cause.

Zones, and what the customer can actually see

The endpoint service is available only in the Availability Zones enabled on its load balancers, and a consumer can only place endpoint network interfaces in those zones. Zone names do not help, because ap-southeast-2a maps to different physical infrastructure in different accounts. Vantage should publish AZ IDs such as apse2-az1. A customer comparing zone names with the vendor is comparing nothing. A consumer also sees only the zones it has in common with the provider, which is the usual reason a customer reports a zone missing from the console.

Cross-zone load balancing is the shortcut for a vendor that has enabled two zones and only populated one, and it moves the failure rather than removing it. Consumers in either zone reach the fleet, and they all lose it together when the single populated zone fails. Regional data transfer charges apply to the traffic it moves between zones as well. Targets in both zones is the design; cross-zone covers the gap between the zones enabled and the zones running instances.

What the vendor can see, and who governs the rest

Requests arrive at the ingest fleet from the private addresses of the load balancer nodes, not from the customer. Per-tenant attribution, rate limiting by customer and any per-customer audit trail therefore need proxy protocol version 2 enabled on the target group, which carries both the consumer’s address and the interface endpoint ID in its header. The endpoint ID is the sturdier of the two identifiers, because AWS issues it and ties it to the accepted connection. Pin a token to the endpoint ID it was first seen on and Vantage has a stolen-token signal that customer-side IP addresses cannot give it.

On the customer’s side the governance lever is identity policy rather than the endpoint. AWS allows full access to an endpoint created for a service that is not an AWS service, so the endpoint policy gives the customer no leverage and a platform team controls which third-party services its accounts reach at creation time instead. The instrument is a service control policy on ec2:CreateVpcEndpoint, conditioned on ec2:VpceServiceName for a specific service name, or on ec2:VpceServiceOwner to allow only amazon, aws-marketplace or a named account. Vantage should expect that question in the security review and answer it with the exact service name per Region. Vantage can apply the mirror image internally: ec2:VpceServicePrivateDnsName restricts which private DNS name its own accounts may claim on an endpoint service, so a staging account cannot publish a service under the production hostname.

Limits and the bill

An interface endpoint supports 10 Gbps per Availability Zone by default and scales automatically to 100 Gbps. For a telemetry data plane that is generous. The MTU of 8500 bytes matters more: Path MTU Discovery is not supported, and oversized packets are dropped rather than fragmented. Consumers hit the combined quota of 50 interface and Gateway Load Balancer endpoints per VPC sooner than they expect once several vendors are consumed this way, and it is adjustable through Service Quotas. On Vantage’s side the cardinality runs one way. A Network Load Balancer belongs to a single endpoint service, while an endpoint service can carry several. Each consumer network interface is then bound at random to one load balancer in its zone, for the life of that interface. Listener and target group configuration has to be identical across all of them, or customers get different behaviour with no pattern to it.

Across Regions

Cross-Region access is opt-in on both sides. Vantage adds supported Regions to the endpoint service, and a consumer names a service Region when creating its endpoint. Both accounts must have opted in to any opt-in Region involved. The IAM entities on both sides also need the vpce:AllowMultiRegion permission-only action before either step works. The host Region cannot be removed from the supported set. Four exclusions then decide whether it fits a data plane. The zones use1-az3, usw1-az2, apne1-az3, apne2-az2 and apne2-az4 are not supported. Neither is a Network Load Balancer with a custom TCP idle timeout, nor UDP fragmentation. And PrivateLink manages failover between zones, not between Regions. Inter-Region gigabytes are charged to the endpoint owner, whichever way they travel, on top of AWS cross-Region data transfer rates, and Vantage pays an hourly charge for each remote Region its service is active in: USD$0.05 an hour in ap-southeast-2.

For Vantage that makes per-Region endpoint services the default and cross-Region access the exception. Each Region gets its own endpoint service, its own domain verification, and its own allow-list, and a customer in Sydney consumes the ap-southeast-2 service. Whether Vantage replicates ingested telemetry between Regions is a separate decision about the storage tier, and cross-Region PrivateLink does not make it for them. Cross-Region access suits one customer with a single low-volume workload stranded in a Region Vantage has not launched in. It is the wrong tool for a production ingest path that has to survive losing a Region.

What’s worth remembering

  1. Endpoint services fit vendor-to-customer links. Endpoint interfaces sit in the consumer’s own subnets, so the two address plans never have to agree.
  2. Revocation takes two steps. Removing a principal from the allow-list leaves accepted connections running; reject the connection as well.
  3. NLBs back endpoint services; ALBs cannot. Register the ALB as a target of an NLB when layer-7 routing is needed.
  4. Private DNS keeps the hostname. Verify the name on the service; the consumer VPC needs DNS hostnames and DNS resolution enabled.
  5. Proxy protocol v2 identifies consumers. The provider sees its own load balancer addresses; v2 carries the consumer address and endpoint ID.
  6. Endpoint policies do not apply here. Customers govern third-party services with a service control policy on ec2:CreateVpcEndpoint, keyed to ec2:VpceServiceName.

These posts are LLM-aided. Backbone, original writing, and structure by Craig. Research and editing by Craig + LLM. Proof-reading by Craig.