When we create an internal API within our VPC not exposed to the internet and want to share it with other Aws accounts, we have two options.
Option one, VPC Peering. Peer our VPC with each VPC, same or different account, which needs access. However, this process has some disadvantages.
- It gets complicated once we have too many vpc to peer with, managing route tables, limiting access with security groups or nacl, etc.
- Can peer only with a max of 125 VPCs.
- Allows access to entire vpc (or subnets) to talk to each other.
- Need a non-overlapping CIDR.
Second option PrivateLink, which solves all the problems mentioned above. In a few words
- No vpc peering needed.
- Private connectivity between APIs. No need for IGW, traffic flow through Aws backbone network. Just like vpc peering but with higher throughput.
- Interface endpoints that provide a way to privately access all public AWS services like SNS, KMS, Cloudwatch, etc. is also powered by PrivateLink.
Here is how to setup privatelink for our use case.
In-Service Provider VPC, i.e where service is running.
- Create an API behind an NLB(Network Load Balancer) in private subnets(no IGW).
- Create an Endpoint Service for this NLB.
- Add all the principals which need access to this service, same or different AWS accounts.
In Consumer VPC i.e where service will be used.
- Create an Endpoint pointing to EndPoint Gateway service name. Must choose a vpc with subnets in the same AZ as the service provider.
- Point ALB to ip addresses of the Endpoint ENI.
This is extremely simple to set up and maintain across 100s or 1000s of Aws accounts. Lets me quickly go through this process step by step. All we need is two VPCs in the same or different Aws account.
Step 1: Set up a private API
We need an API running behind NLB, I decided to run a docker container in ECS Fargate.
- Sign up for a free Kafka cloud account with Confluent or CloudKarafka.
- Spin up the ECS Task by pulling docker image Kafka-UI and passing necessary environment variables to connect to a Kafka account. This image exposes a web UI for Kafka on port 5000.
- Create a TargetGroup pointing to ECS service task private ip.
- Create an NLB in private subnet point to that NLB. Since they are private, can’t be tested from the browser. I quickly moved subnets to custom route table with IGW just to test and moved them back to route table with no internet.
Step 2: Setup Vpc Endpoint Service
- Head over to ‘EndPoint Services’ in vpc service and create one, select nlb created above. Choose Acceptance Required as ‘Yes’, this will allow accepting when a new consumer is added to this service.
- Note the service name, we need it to share this with consumers.
- Add consumer aws account(s) in Principals.
Step 3: Setup Vpc Endpoint in Consumer account
- In the ‘Gateway’ section of Consumer Aws account vpc, create an endpoint. we need to give service name captured from service provider vpc gateway service and choose a vpc with subnets from the same AZ of the service provider NLB.
- We need to accept this connection in the service provider vpc endpoint service console. This will show the status ‘available’.
- Capture IP address of the endpoints.
Step 4: Create an ALB to test the endpoint
- Create a Target and choose target as IP and point to IP addresses of endpoint ENI.
- Then create a public facing ALB to point to the target.
This is it. We have successfully deployed a private API within our vpc and let other services in totally different vpc and account access it without vpc peering and public internet. Use cases of private link are countless Here is an excellent re-invent video covering them in great detail.