Amazon API gateway is a very useful service to build comprehensive RESTful API with Lambda functions. It provides most common API gateway functions like authorisation, rate limit, routing etc. Also it provides high availability and auto scaling capability that you don’t need to take care, AWS will take care for you. So it’s an awesome service for you to build your API. As the high availability and auto scaling capability, the public IPs are managed by AWS and it just exposes an AWS assigned domain (e.g. n701ul6c02.execute-api.us-east-1.amazonaws.com) or you can map a custom domain to the API gateway. It’s pretty good for general cases as well.
But I just have a client who requires to whitelist the outgoing traffic to the API gateway due to their company policy. They need to know what exactly IPs are assigned to the API gateway and whitelist those IPs. Otherwise, the outgoing API requests will be blocked. As mentioned before, Amazon API gateway does not have static IPs (AWS assigned IPs will change from time to time) and we cannot assign elastic IPs to it (just like the application load balancer). So how can we deal with this issue? Is there any way to assign static IPs to the Amazon API gateway?
After doing some researches and asking the AWS support, it does not have a way to assign static IPs to the Amazon API gateway. But we can do it in a “tricky way”- combining the API gateway with network load balancer and VPC endpoint:
The trick is to make use of assigning elastic IPs to NLB (network load balancer). Then set the target group of NLB pointing to the IPs of VPC endpoint for API gateway. Now we can call the API by elastic IPs assigned to NLB and whitelist those elastic IPs!
Here are the detailed steps for the whole setup:
Create API gateway
- Open the API Gateway console
- Click Create API and choose REST API Private.
3. Input the API name, choose the VPC and click Create API
4. After creating the gateway, you need to create a resource policy to allow access to the API from inside the VPC. (https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-resource-policies-examples.html#apigateway-resource-policies-source-vpc-example ).
In the left navigation pane, choose Resource Policy. Copy & paste the below snippet and Replace {{vpceID}} with the ID of your VPC endpoint.
5. Create some resources and endpoint using Mock for testing after all setup
6. Click Actions > Deploy API. Choose [New Stage], name the stage demo and Choose Deploy (Remember to deploy the API after making any changes e.g. Resource policy, adding endpoints)
The API gateway setup is done, then we can move on to the VPC endpoint setup.
Create VPC endpoint
1. Open the Amazon VPC console.
2. In the left navigation pane, choose Endpoints, Create Endpoint.
3. For Service category, keep it set to “AWS Services”.
4. For Service Name, search Service Name by entering “api”, select “com.amazonaws.{region}.execute-api” in the search result.
5. For VPC, select the VPC and private subnets that the API gateway would like to be provisioned in.
6. For Enable DNS Name, keep it checked as Enabled for this endpoint. And for Security Group, create or select a security group that allows for HTTPS access to the endpoint for the entire VPC IP address range (explicitly set the CIDR of the VPC IPs).
7. For Policy, can simply select the Full Access (this is the policy to control the actions that you can do to the target AWS service through endpoint -https://docs.aws.amazon.com/vpc/latest/userguide/vpc-endpoints-access.html#vpc-endpoint-policies )
8. Choose Create Endpoint.
So far so good, we have finished the VPC endpoint setup. Then we move to the last component — Network load balancer.
Create Network load balancer
1. Open the Amazon EC2 console.
2. In the left navigation pane, choose Elastic IPs, Click Allocate Elastic IP address to create EIPs (You need to create several IPs and the number of IPs is depended on how many AZs you assign to the API gateway).
These EIPs will be used in later step and these are the IPs for you to whitelist.
3. In the left navigation pane, choose Load Balancers, Create Load Balancers.
4. Choose Network Load Balancer, enter the Name, select internet-facing and ipv4
5. Select the Load Balancer Protocol of the listener, we assume to use HTTPS so we choose the TLS as the protocol and 443 as the port
6. Select the VPC and Availability Zones, select to use EIPs which are created in step 2. Click Next:Configure Security Settings button.
7. In Configure Security Settings, we can either select a ACM/IAM certification or upload a SSL for the HTTPS. The Security policy and ALPN Policy are to control the acceptable TLS version and HTTP version, we just leave them as default. Click Next:Configure Routing button to next step.
8. In Configure Routing, create a new Target group, enter the Name, select IP as Target type, select TLS as Protocol. Select HTTPS as Health checks Protocol and the path keep as / first (you need to create a corresponding endpoint in API gateway for this health check). Click Next:Register Targets button to next step.
9. In Register Targets, you need to input the VPC endpoint IPs. You can go back to the VPC endpoint console and check the IPs in the Subnets tab
10. Input VPC endpoint IP and click Add to list. After adding all endpoint IPs, click Next:Review button to next step
11. Review NLB settings and click Create button
First test after the setup
Cool. All components are done. So let’s have a test to call the API through the NLB’s domain (e.g. nlb-api-gw-08a8fac87e384cb4.elb.us-east-1.amazonaws.com). Use curl to test it and you may have the below error:
Oh, yes, we don’t have the SSL cert for the domain amazon.com in NLB, so we have this error. Okay, we skip this error by adding param -k to curl first and see whether our setup between NLB, VPC endpoint and API gateway is success or not. Let’s try the command: curl -k https://nlb-api-gw-08a8fac87e384cb4.elb.us-east-1.amazonaws.com/prod. Oh, error again! It returns forbidden.
So what’s going on? Is there any problem during the setup? It’s a bit tricky here. Since VPC endpoint and API gateway do not have a one-to-one relation, which means the request goes through the VPC endpoint and looks for the API gateway with request domain (e.g. nlb-api-gw-08a8fac87e384cb4.elb.us-east-1.amazonaws.com), that’s the NLB domain instead of the API gateway domain. Therefore, we can add a param -H to curl to specific the host header as API gateway domain: curl -k -H “Host: n701ul6c02.execute-api.us-east-1.amazonaws.com” https://nlb-api-gw-08a8fac87e384cb4.elb.us-east-1.amazonaws.com/prod
Excellent! we finally get the mock response.
For this behaviour, we better setup a custom domain in API gateway and create a DNS CNAME record of custom domain for pointing to the NLB.
Custom domain for API gateway
- Let’s go back to the API gateway console. In the left navigation pane, choose Custom domain names
- Click Create, enter domain, select minimum TLS version, Endpoint type as Regional and select the ACM certification of the domain you entered (should be the same domain cert that you used in NLB)
- After creating the domain, click the domain and click the API mappings on the right side. Click Configure API mappings
4. Select API and Stage you created before and click Save
Awesome! Finally, we need to add the DNS record to point the custom domain to the NLB. After that, we can have the test again. In this case, I use Route53 to manage DNS records and it’s easier to add the record for pointing to NLB: Create a simple routing record, select Alias to Network Load Balancer , Region and the NLB.
Let’s try again the test with curl: curl https://api-gw-poc.labecloud.com/ (no need to include the stage path /prod since we have the API mappings)
Now we can call the API through the NLB. At last, we can use nslookup to see which IPs are mapped to the custom domain:
It shows that the custom domain is pointing to the EIPs which we created before. Now we can whitelist these IPs to achieve the goal for whitelisting the API gateway!
Hope you guys enjoy this topic and please leave me comments if you have any questions or wanna to have further discussion on this topic!