AWS Private API Gateway with Custom domain names
A step-by-step guide to create a Private REST endpoint with Custom DNS
API gateway is great when it comes to exposing your APIs publicly and you will find a lot of blogs and videos around it. However, most organizations want to define private APIs for consumption by other sub-systems within the organization. I had a lot of struggle learning how to define private APIs with custom DNS. This article gives a step-by-step guide on how to achieve this. Below is the depiction of what we are going to achieve at the end of this article.
Step 1: Create an interface VPC endpoint
Login to your AWS console and select the VPC service. Select “Endpoints” from the left navigation pane and then hit the “Create Endpoint” button. In the list of AWS services, select com.amazonaws.com.[region].execute-api. Make sure to select the right VPC, subnets and the security group which allows traffic on port 80 and 443. You can also define the custom policy as per your need OR leave it as “Full Access.” Note down the VPC Endpoint ID once its created. We will need it in step 3. Also note down the IPV4 addresses from the subnets tab. These are needed when we create a Internal load balancer.
Step 2: Create a lambda function within VPC
Select the Lambda service and create a lambda function within the VPC. You can create a simple function which returns “Hello from VPC Lambda” in the programming language of your choice. Few things to take note of while creating the function:
a. Create a IAM execution role which has AWSLambdaBasicExecutionRole and AWSLambdaVPCAccessExecutionRole policies attached. Select this role when creating lambda function. (Change default execution role → Use an existing role)
a. In the Advanced Settings, Make sure to select the same subnets which you selected for VPC endpoint creation.
Step 3: Create Private REST API in API Gateway
Select API Gateway service and create a new API. Choose the API to be Rest API Private. Provide API name and description and in the Endpoint Type select “Private”. Give the VPC Endpoint ID from step 1 in the “VPC Endpoint IDs” and click Add. Click on Create API. This creates the new Private REST API.
Once the API is created, click on the Resource Policy in the left navigation pane and enter the below resource policy. [NOTE: replace vpce-<id> with the VPC Endpoint Id]
Step 4: Integrate Lambda function with API gateway, Deploy and Test
Select the newly created API and from the Actions menu select “GET” method. Select Integration Type as Lambda Function and choose the lambda function created in step 2.
From the Actions menu, select Deploy API. Select Deployment State as [New Stage] and give the Stage name as dev. Once the API is deployed, click on the Stages in the left navigation pane and select the dev stage. You will see the API URL on the right hand side. Try to access the URL from your browser which is outside VPC. You will not be able to access the API since its private. For the purpose of testing, create a EC2 instance in the VPC, and try to use curl command to test the API with the stage URL. This should work fine since its defined within the VPC.
Step 5: Create SSL Certificate and upload to AWS Certificate Manager
This is the next important step. Since you are defining a private https REST API, you have to provide the SSL certificate to access the API. I cannot detail this step here since your organization will have ways of generating the SSL certificate. You can use the openssl command to generate the self signed certificate if you are just exploring. Once the certificate is generated, go to Certificate Manager in AWS and click on “Import Certificate.” Provide the details and import the certificate. Note down the domain name given while creating the certificate. We will need this domain name when configuring API gateway custom domain names.
Step 6: Application Load Balancer and Target Group
AWS does not support custom domain names for private APIs. So this is a work around needed to access APIs via custom domain names.
Select the EC2 service in top search bar. In the left navigation pane, select Load Balancers and then click Create Load Balancer in the right side view. Select Application Load Balancer and hit Create. Follow the below steps to complete the load balancer creation wizard:
NOTE: This is going to be a bit of a long process and must be done accurately. Please do this carefully.
- Configure Load Balancer
a. Select Scheme as Internal
b. Listeners → Add HTTPS (default port is 443)
c. VPC and subnets → Ensure to select the right VPC where your VPC endpoint is created and also make sure to select the same set of subnets.
2. Configure Security Settings
a. Certificate type → Choose a certificate from ACM
b. Certificate name → Select the name of the certificate from the dropdown
c. Security Policy → Leave it to default (ELBSecurityPolicy-2016–08)
3. Configure Security Groups
Assign a security group → Create a new security group → Provide the name and description and ensure to select HTTPS from the dropdown
4. Configure Routing
a. Target group → [New target group]
b. Target type → IP
c. Protocol → HTTPS
d. Health checks → Protocol → HTTPS
e. Advanced health check settings → Port → [traffic port]
f. Advanced health check settings → Success codes → [200, 403]
Leave the other values to be defaults.
5. Register Targets
Network dropdown → Other private IP addresses → Enter the IPV4 addresses noted in step 1 and hit Add to list
The load balancer targets should be the IP addresses of the ENIs that the VPC endpoint created. These were done in step 1. You can find those ENIs by selecting your VPC endpoint and opening the Subnets tab.
Click on Review and create the load balancer. Once the load balancer is created, open the Target Groups from the left navigation pane and open the target group you create as part of load balancer creation. Click on the Targets tab and ensure that health checks for both the IPs are shown as healthy. It might take some time, but if you have configured everything properly, it should show healthy shortly after creation.
Step 7: Create Private hosted zone in Route 53
The next step is to setup the private hosted zone and point it to application load balancer. Select the Route 53 service. Click on Hosted zones → Create hosted zone. Follow the below steps to create the hosted zone:
a. Domain name → us-east-1.customdomain.aws
b. Type → Private hosted zone
c. Region → us-east-1
d. VPC ID → VPC ID where you have configured all your resources.
Once the hosted zone is created, click on Create record and enter the following details:
a. Record name → test_api
b. Record Type → A
c. Alias → Enable alias so that you can select the load balancer
d. Route traffic → Alias to application and classic load balancer
e. Region → us-east-1
f. Select the load balancer from the dropdown. (It will begin with dualstack.internal…)
Leave the Routing policy and Evaluate target health as default and click on create records.
Step 8: Configure API Gateway Custom domain names
Select the API Gateway service and click on Custom domain names in left navigation pane. Click create in right side view and enter the details as below:
a. Domain name → Provide the domain name here. Note that this must match the domain name you gave while creating SSL certificate in step 5.
b. TLS version → 1.2
c. Endpoint type → Regional
d. ACM certificate → select the certificate which was created in step 5.
Once the domain name is created, select the domain name and click on API mappings tab. In the API mappings window, select the API and the stage from the dropdown and click save. Leave the Path field empty. This way if you create resources in the API, you can access all the resources with the same domain name and path suffix.
Once configured, make sure to deploy the API again else you will not be able to invoke the API with custom domain name.
That’s it. All the configuration is now complete and you should now be able to test the API will the domain name test_api.us-east-1.customdomain.aws only from within the VPC.
Its a round about way of doing things, but it does reduce the headache of using the cryptic API names and also helps in DR strategy.
It was quite a long journey for me to get this working. I hope this helps others. Do leave a comment if you are struck somewhere and I will be ready to help you out.