How to create a VPC endpoint for API Gateway
API Gateway is a managed service provided by AWS to expose APIs at any scale to the users. At the time of introduction, API gateway only supported public endpoints which was a real problem when implementing production APIs because in the majority of cases the APIs should be private making only the front-facing application (i.e web app, mobile app) public. But later on, AWS introduced private VPC endpoints for API Gateway which was a most awaited announcement. But when I was trying to implement a private API gateway I didn’t find any straightforward documentation to do that. Here I will explain everything in detail on how to implement a private VPC endpoint for API gateway.
Create a Lambda function
Here I will be using a lambda function as the target for the API gateway endpoint. But you can use anything according to your use case. Here I have created a simple Lambda function to serve a static response.
Create public API Gateway endpoint
I will be using an API Gateway GET endpoint as the trigger for the Lambda function I have created.
Then if I go to the API Gateway dashboard I can see the endpoint to trigger my Lambda function through API Gateway.
I can simply copy-paste this URL in the browser and access the endpoint I have created form public internet.
Now I have an API Gateway endpoint which can be accessed from the public internet. Now I want to restrict the access of this endpoint to my VPC by making it a private endpoint.
Create VPC endpoint
First, you have to create a VPC endpoint within your VPC if you don’t have one yet. You can do this easily by going to the VPC dashboard of the AWS Console.
When creating a VPC endpoint to be used by API Gateway you must use the service name as execute-api
. And also make sure to make the Enable DNS name option. I will explain why we need this option enabled in the end. More details on creating a VPC endpoint can be found here.
You have to attach a security group for the VPC endpoint with correct inbound rules. When creating a security group for VPC endpoint it’s good to open the ports only for the source IP range of the related VPC. If you are creating a VPC endpoint to be accessed from your VPC you can use the same CIDR range of the VPC as the source IP rage of the security group inbound rule. If you expect to access the VPC endpoint from several VPCs connected thought VPC peering or an AWS transit gateway you can use the CIDR range from all VPCs as the source IP range for the security group inbound rule.
Attach VPC endpoint for API Gateway
Go to the API Gateway dashboard and open the API you have created in the earlier step for the Lambda (or any of your existing API Gateway). Then go to the settings tab. Under Endpoint Configuration select the Endpoint Type as Private and click Save Changes. Then go the same page and select the VPC endpoint you have created in the previous step for as the VPC Endpoint IDs. Then click Save Changes again.
Then go to the Resource Policy tab. You must have a resource policy when attaching a VPC endpoint for the API Gateway. Resource Policy can be used to restrict access to the API Gateway using different conditions. In this use case, we have to limit the API Gateway access only for the VPC endpoint. That means the API Gateway should only allow the traffic originating from the VPC endpoint. Use this configuration for the resource policy. Make sure to replace <accound-id>, <aws-region>, <api-id> and <vpc-endpoint-id> with correct values. You can find more resource policy example here.
Here is a screenshot of my resource policy.
Now we are done with the configurations. Don’t forget to redeploy the API with the new configurations.
Now if you go to the same URL we tried above from the browser it won’t be working anymore. This is because we have restricted the access to the API Gateway to traffic generated only through the VPC endpoint.
How to access the API through VPC endpoint?
Actually this was the hardest part to figure out using the AWS documentation for me. As I mentioned above, the URL displayed in the API Gateway console will not be working furthermore after creating the private endpoint.
There are many ways to access the API Gateway through VPC endpoint as documented here. The easiest way to access without additional options is through the Route 53 alias which is automatically created for the VPC endpoint. Other access methods require some additional headers in the request. To use this method you should have marked the Enable DNS name options as I highlighted in the steps to create the VPC endpoint.
Your VPC endpoint for the API Gateway will be as follows.
https://{rest-api-id}-{vpce-id}.execute-api.{region}.amazonaws.com/{stage}
In my case it is,
If I try to access this URL through the browser or by a curl command with the terminal it won’t be working since this is not visible to the public internet. So in order to test this endpoint, I spawned an EC2 instance in the same VPC as my VPC endpoint and SSHed into that instance. If I execute a curl from that EC2 I can see the response from my Lambda function successfully.
Now my request flows as EC2 -> VPC endpoint -> API Gateway -> Lambda.
Note: You may get a “Missing Authentication Token” error when trying to call the endpoint. But please note that in most of the cases you will get this error when your request path is wrong. In real authentication errors, you will get a “Forbidden” error. Yes, there is an error in the error message returned by API Gateway :) In case you get above error double-check your request path, especially the latter part of the URL.
Now we are done on creating a private endpoint for our API Gateway. Try it yourself and feel free to leave a comment if you face any problems.