PrivateLink implementation guide for a third-party SaaS integration
Establishing private connectivity between a company VPC and a third-party SaaS application over AWS PrivateLink. The result is API access that never crosses the public internet and needs no shared address space.
Prerequisites
Section titled “Prerequisites”- An AWS account with permission to create VPC endpoints.
- An existing VPC with private subnets in at least two Availability Zones.
- The provider’s service name, in the form
com.amazonaws.vpce.<region>.vpce-svc-xxxxxxxx. - The list of API endpoints and ports the application will use.
- Confirmation from the provider that they have allow-listed your account as a principal on their endpoint service.
- The AWS CLI configured.
1. Pre-implementation checks
Section titled “1. Pre-implementation checks”- Confirm the endpoint service exists in the same Region as your VPC, or that a cross-Region endpoint is supported for it.
- Verify each subnet has free IP addresses for an endpoint network interface.
- Document the API endpoints and ports required.
- Decide whether private DNS will be used, or whether the application will be pointed at the endpoint-specific DNS name.
Overlapping CIDR blocks are not a concern here — that is one of the reasons to use PrivateLink rather than peering.
2. Security group
Section titled “2. Security group”aws ec2 create-security-group \ --group-name "privatelink-endpoint-sg" \ --description "Security group for PrivateLink endpoint" \ --vpc-id "vpc-xxxxx"
aws ec2 authorize-security-group-ingress \ --group-id "sg-xxxxx" \ --protocol tcp \ --port 443 \ --cidr 10.0.0.0/16Allow only the ports the API uses, and only from the address ranges or security groups that should reach it. This security group applies to the endpoint network interfaces, so it is the first place traffic is filtered.
3. Create the interface endpoint
Section titled “3. Create the interface endpoint”aws ec2 create-vpc-endpoint \ --vpc-id vpc-xxxxx \ --vpc-endpoint-type Interface \ --service-name com.amazonaws.vpce.eu-west-2.vpce-svc-xxxxx \ --subnet-ids subnet-xxxxx subnet-yyyyy \ --security-group-ids sg-xxxxx \ --private-dns-enabled trueChoose one subnet per Availability Zone that the provider’s endpoint service supports. The endpoint enters pendingAcceptance until the provider accepts the connection request, unless they have enabled automatic acceptance.
4. DNS
Section titled “4. DNS”With private DNS enabled, the provider’s public hostname resolves inside your VPC to the endpoint’s private addresses, and the application needs no configuration change. This requires enableDnsSupport and enableDnsHostnames on the VPC.
Without it, use the endpoint-specific DNS name that AWS generates, or point a Route 53 private hosted zone record at it.
5. IAM
Section titled “5. IAM”{ "Version": "2012-10-17", "Statement": [ { "Sid": "ManagePrivateLinkEndpoints", "Effect": "Allow", "Action": [ "ec2:DescribeVpcEndpoints", "ec2:CreateVpcEndpoint", "ec2:DeleteVpcEndpoints", "ec2:ModifyVpcEndpoint" ], "Resource": "*", "Condition": { "StringEquals": { "aws:RequestedRegion": ["eu-west-2"] } } } ]}Separately, attach an endpoint policy to the endpoint itself if the service supports one, to restrict which principals and actions may use it.
6. Validate
Section titled “6. Validate”# Resolution should return a private address from your subnet rangenslookup api.saasprovider.example
# Then the API itselfcurl -sS -o /dev/null -w '%{http_code}\n' https://api.saasprovider.example/healthCheck off:
- DNS resolves to a private address inside the VPC, not a public one.
- API calls succeed through the endpoint.
- No traffic reaches the internet gateway or NAT gateway for this destination — confirm in VPC flow logs.
- The endpoint reports
availableand its CloudWatch metrics show traffic.
Interface endpoints do not answer ICMP, so ping proves nothing. Use nc or nmap if you need a connectivity test below the application layer.
Monitoring
Section titled “Monitoring”AWS PrivateLink publishes endpoint metrics in the AWS/PrivateLinkEndpoints namespace:
| Metric | What it tells you |
|---|---|
ActiveConnections | Concurrent connections through the endpoint |
NewConnections | Connections established in the period |
BytesProcessed | Bytes in both directions — this is what you are billed on |
PacketsDropped | Packets the endpoint dropped; a rising value suggests the endpoint or the service is unhealthy |
RstPacketsReceived | RST packets received; a rising value suggests the endpoint service is unhealthy |
Dimensions are Endpoint Type, Service Name, VPC Endpoint Id, VPC Id and, at finer granularity, Subnet Id.
If you also publish an endpoint service, its metrics are in AWS/PrivateLinkServices.
An alarm on dropped packets:
aws cloudwatch put-metric-alarm \ --alarm-name "privatelink-endpoint-packets-dropped" \ --alarm-description "PrivateLink endpoint is dropping packets" \ --namespace "AWS/PrivateLinkEndpoints" \ --metric-name "PacketsDropped" \ --dimensions Name="VPC Endpoint Id",Value=vpce-xxxxx \ --statistic "Sum" \ --period 300 \ --threshold 1 \ --comparison-operator GreaterThanThreshold \ --evaluation-periods 1 \ --alarm-actions "arn:aws:sns:eu-west-2:<account-id>:<topic-name>"Metrics are published for interface endpoints, Gateway Load Balancer endpoints and endpoint services. They are not published for gateway endpoints, so an alarm on an S3 gateway endpoint will never fire.
Security practice
Section titled “Security practice”- Review the endpoint security group rules on the same schedule as any other production control.
- Use an endpoint policy for fine-grained control where the service supports one.
- Enable VPC flow logs on the endpoint subnets.
- Use IAM roles rather than long-lived access keys for anything calling the API.
- Audit which accounts hold endpoints against the provider’s service, and ask the provider to remove principals you no longer use.
Troubleshooting
Section titled “Troubleshooting”| Symptom | Look at |
|---|---|
Endpoint stuck in pendingAcceptance | The provider has not accepted the connection, or your account is not on their allow list |
| DNS returns a public address | Private DNS not enabled; enableDnsSupport/enableDnsHostnames off; a conflicting Route 53 record |
| Connection times out | Endpoint security group; network ACLs on the endpoint subnets; no endpoint interface in the caller’s Availability Zone |
| Intermittent failures | PacketsDropped and RstPacketsReceived; provider-side target health |
ping fails but the API works | Expected — interface endpoints do not respond to ICMP |
- Per endpoint-hour, per Availability Zone.
- Per gigabyte processed.
- Cross-Availability-Zone data transfer if callers and endpoint interfaces are in different zones — put an interface in every zone that has callers.