Enable custom names for your internal API’s, with CDK Example
AWS API Gateway Private is the ideal way to front our internal applications and services, but there’s one frustrating limitation — you cannot assign a custom domain name to a private API like you do with one that is public facing.
This leads to internal API’s with less than friendly names like:
Or if you need the name to resolve for remote users (VPN or on-prem over Direct Connect), then it would look like this:
Either way, it’s a pain to remember! What’s worse if it’s redeployed for any reason the name will change — ok for services part of your CI/CD pipeline that know about the update, but not so good for users or applications out of the loop.
The solution for now is to put an Application Load Balancer (ALB) in front of the API and access it using the hostname of the ALB instead. Adds a little cost to the scenario, but in some cases it will be worth it. You can use host and path based routing on the ALB to access many API’s, and even use the same ALB to access web apps on EC2/ECS/Fargate in smaller environments or test accounts.
There’s a few tricks to it though, so here’s what you need to do (with a CDK example at the end)…
I’m not going into detail of how to create and configure API’s here, just how to access them using an internal ALB and custom domain name.
You will need a working API or two, and the internal API VPC Endpoints to access it.
The key trick with API Gateway itself is to add a Custom Domain Name and mapping it to your internal APIs.
This is not intuitive, because Custom domains can not be created with a Private endpoint type:
That’s ok — using the Regional endpoint type will work. You will also need a matching certificate from ACM.
Next, map the Custom domain to your internal API stages as you would an external API:
Note the path(s) you use here will be needed later in the ALB Rules.
And that’s it. You can still access the APIs using the unfriendly endpoint URL’s, but accessing it directly using the custom name won’t work yet.
Application Load Balancer
Next we create and configure a load balancer. Again I’m not going into all the detail here, just the parts relevant to the API and custom domain.
First, create the ALB and attach it to the same subnets as your API VPC Endpoints.
Add a Listener for HTTPS and attach your certificate. The default action should be a Fixed Response with a 400 or 500 error.
Next we need a Target Group
First, get the IP Addresses of the API VPC Endpoint:
Then create a new Target Group:
We need to configure the Health Check Settings. API Gateway will send a 403 response to health checks so we have to include that:
Add the IP Addresses of the VPC Endpoint and add to pending:
Go back to the Load Balancer, and to Listeners. We need to edit the HTTPS Listener to add the new targets:
Edit the Listener and Add a New Rule with Path based routing:
Note I have added the paths mapped above for both of my test API’s here — we can forward to multiple API’s using the same ALB and Rule. The leading slash is required.
Save the Rule and we are done.
You can now access the API’s using the hostname of the ALB, for example:
will be forwarded to the API with a domain path mapping of api-priv.mydomain.com => test-api1
In my environments I’m deploying the ALB’s and configuration using AWS CDK. I’ve created a demo to show how to create an Application Load Balancer and internal private API Gateways with a custom domain name.
The demo is self-contained and will deploy into the AWS default VPC by default. Check out the Readme for more detail. All you will need to test is VPN access to your VPC — I’ll add another article on that soon.
Aside from the tricks above, the other issue automating this with CloudFormation and CDK is that there is no export for the IP addresses attached to the VPC Endpoints. I use a CloudFormation custom resource to workaround it, and it turns out that’s pretty easy using CDK. If you are interested in the generic CloudFormation version let me know.