API Gateway is one the better-known services of AWS and one that fits great in a serverless architecture. It’s your go-to service when you want to create, publish, maintain, and secure your API. Combine it with a Lambda function as your backend together with a DynamoDB as your database and you have a great serverless setup that can dynamically scale to your demands. And we have a great hack for you to create a custom domain name on a private REST API Gateway.
Getting around the Gateway
The API Gateway comes in four different flavors:
- HTTP API
- WebSocket API
- REST API (public)
- REST API (private)
One of the nice features you have with the API Gateway is that you can create a custom domain for the API Gateway (e.g., www.example.com). BUT there is a big catch to this: when you choose the private REST API flavor, you can’t use a custom domain name with your API Gateway. This means you end up with an AWS-provided domain name which is not user-friendly. For example, https://ab123456789.execute-api.eu-west-1.amazonaws.com/test (The format of the AWS provided domain name is: <API ID>.execute-api.<AWS Region>.amazonaws.com/<Stage Name>).
BUT have no fear: Cloudar is here!
We can bypass this limitation by utilizing an internal application load balancer in front of our API Gateway. This way the load balancer acts as our front door, giving us the ability to use custom domain names and forwarding all traffic to the API Gateway.
Important note: In this example we aren’t going to dive into the configuration of the API Gateway or the resources that are behind the API Gateway (Lambda, ECS, etc.), but rather the solution for using a custom domain name with your API Gateway.
The architectural design
The components that should already be in place are:
- A VPC with subnets
- Route53 private hosted zone
- A valid TLS certificate
The components we are going to create are:
- Internal Application Load balancer
- ALB Target group based on IPs
- VPC Endpoint for the API Gateway. (In our design we went with VPC Endpoint deployed in 2 AZs for high availability, but you it also works with 1 or 3 AZs)
- A private REST API Gateway
Configuring all the components
Create a Route53 private hosted zone and connect it to your VPC. This is the zone that is going to provide our custom domain name for our API Gateway. In our case the private hosted zone is called “cloudar.be”.
Via Amazon Certificate Manager (ACM) you can create or import a certificate to use with our Application load balancer. In our case, we created a certificate for “api.cloudar.be”.
VPC Endpoints for API Gateway
You can create the VPC Endpoints for API Gateway to ensure that you call the API using private IPs only. VPC Endpoints can be found under VPC >> Endpoints in the console. Under “AWS services”, search for “com.amazonaws.<your region>.execute-api”, select your VPC, select the subnets you want to deploy this, select the security group you want to couple with this endpoint and leave all the settings as is.
After the creation of your endpoint note, collect the following information that we are going to need later:
- The endpoint ID
- The IP addresses of the endpoints
- This can be found in the console under: VPC >> Endpoints >> select your endpoint >> Subnets tab
Next, we create our private REST API Gateway. Choose an API Name and a description. Endpoint Type should be set to “Private”, and under “VPC Endpoint IDs” you fill in the endpoint ID we created in the step above.
At this point your API should have been created. First thing we are going to do is add a resource policy to the API Gateway. This is mandatory, because otherwise we can’t deploy our API later.
For this demo, we are going to allow everyone who is in our network to call the API, but in real-life scenarios you can use a Condition to limit only traffic coming from certain IPs, VPC or VPC endpoint.
Don’t forget to save your resource policy!
After completing this, we can go ahead and create a GET method under “/” of the API Gateway. As “Integration type” we are going to choose “Mock” since this is just a tutorial to show you how to use custom domain names with a private API Gateway.
Now that we have a private REST API, with its resource policy allowing it to be invoked and a GET method, we can deploy this API to a stage. In our case we have a stage called “test” where we deployed this API to.
So by now you should have received your Amazon-provided domain name for your API Gateway in the following format:
https://<API ID>.execute-api.<AWS region>.amazonaws.com/<stage name>
This can be found/verified in the console under API Gateway >> API’s >> your API >> Stages >> select your stage. There at the top of the page, you can find your Amazon-provided domain name for that stage.
The only thing that remains is to map this API to a custom domain name. Open “Custom domain names” under the API Gateway section.
- Create a new custom domain name, in our case: api.cloudar.be
- Endpoint type: Regional
- ACM Certificate: Select the certificate you made for api.cloudar.be in ACM
After the creation of the custom domain name, we go to “API mappings” within the custom domain names screen and configure a new API mapping and save it by going to:
- API: Select the API you just created
- Stage: test
Application Load balancer & target group
To set up the load balancer, we start by creating a target group. This is a target group based on IPs of the API Gateway VPC Endpoints. In our case:
- Target type: IP addresses
- Target group name: api-endpoints
- Protocol: HTTPS
- VPC: Choose your VPC
- Health check protocol: HTTPS
- Under “Advanced health check settings” >> Success codes: 200,403
- Register the IP addresses of the API Gateway VPC endpoints on port 443 and create the target group. These IPs can be found under: VPC >> Endpoints >> select your endpoint >> Subnets tab
Now that we have our target group, we can create our Application load balancer:
- Load balancer name: private-api-loadbalancer
- Scheme: Internal
- Select your VPC, subnets and the security group for this load balancer
- Listener: HTTPS
- Default action: Forward to api-endpoints target group
Configuring the security groups
The last step is to finetune our security groups for the load balancer and the API Gateway endpoints.
Security Group VPC Endpoint
In the security group of the VPC Endpoint, we are going to add a rule that allows HTTPS traffic from the security group of the internal ALB (red underlined in example here below).
Security group application load balancer
This security group acts as our entry point when we call the API Gateway. Here you can allow traffic from your VPC CIDR range, on-premises range, only a certain IP or many more variations. In our case we are going to allow inbound on HTTPS from our VPC CIDR range.
Important note: Traffic can still be dropped if your API’s resource policy doesn’t have a valid allow statement. In our scenario we control the inbound traffic via the internal ALB’s security group. Our API’s resource policy is created in such a way that it accepts all traffic (see example API resource policy under API Gateway section).
The final step
Now you can deploy an EC2 instance in a subnet and make a call to: https://api.cloudar.be and getting forwarded to your private REST API Gateway.