Active-active API Gateway: a step-by-step guide with terraform code

Rosina Garagorry
Globant
Published in
7 min readSep 15, 2022

Application infrastructure and disaster recovery strategies vary, depending on the needs of each company. What’s the point of having rugged code when you don’t have a rugged infrastructure? Adopting an active-active strategy, though more expensive than other strategies such as pilot light or warm stand by; ensures that our customers are not affected by failures in our primary site, and they are always served by the region with the least latency. Here we will explain the step-by-step of deploying an active-active API gateway and share some useful code.

The following sections will be reviewed in this article:

  • Architecture
  • Deployment of needed resources
  • Conclusions

Architecture

The infrastructure we will deploy:

The flow would be as follows:

  • The users go to our-site
  • Route53 redirects to the region with the least latency or if one of the regions is down, toe the one that’s working
  • HTTP API authenticates the user against a third-party OAuth
  • If the user is correctly authenticated, it will redirect to the load balancer
  • The load balancer will check against the WAF rules if it is allowed to proceed
  • If allowed to proceed, the user will be directed to the corresponding application

Since Amazon Cognito doesn’t support active-active API Gateway configuration, we are using a custom solution that provides a JSON Web Token (JWT) for authentication. This custom solution pushed us towards deciding to implement an HTTP API instead of a Rest Api. We could have used the JWT authorizer with a Lambda, but we preferred this approach that’s more straightforward. Besides, HTTP apis are cheaper than their Rest counterparts (for an AWS comparison between APIs, you can refer to the official documentation here).

Deploying resources

  1. Create a hosted zone

Unless you already have your hosted zone where you want to create your records, you should create one. To do so, go to your AWS console, Route53 and click on create hosted zone:

In your domain name, you’ll need to indicate the domain name for your hosted zone. A domain name is the suffix that all your subdomains will have. Example, if your domain name is my-domain.com, then you will be able to create subdomains such as cool.my-domain.com and supercool.my-domain.com. Also, you need to mark your hosted zone as Public, since we want the zone to be publicly accessible.

When creating a hosted zone, AWS automatically creates two records: one of type NS and another one of type SOA. NS stands for nameserver, and refers to the servers that contain your DNS. SOA stands for Start of Authority and has all the administrative information associated with the domain name, such as your name and contact information (this is related to RFC 1035 rules, you can read more here).

2. Create API and API records

Once you have created your hosted zone, first you need to create your custom domain name and the API you’d like to expose. Therefore, you should go to API gateway console.

3. Create a domain name, that matches the suffix of your hosted zone

When creating your domain name, you will have to indicate: its name, the minimum TLS version, the endpoint configuration and if it has an ACM certificate, you will have to select it.

4. Create HTTP API

When creating an HTTP API, you will be required to:

  • Add an integration
  • Indicate the HTTP API name
  • Configure routes
  • Add a VPC link

In a few words, how does this work? The user will make a request to your {yourcustomdomainname}/{api}. In this example, it could be: devops.cool.my-domain.com/learn-api . Note that your custom domain name ends with the domain name of the hosted zone we created in the first instance.

When you create the integration, you are indicating where the api should redirect the request. In our case, we redirect traffic to an already existing application load balancer. If using a ACM certificate, it’s important in the integration to make sure that the HTTPS hostname and in the parameter mapping the hostname match those of the certificate. Otherwise, it will throw an unauthorized error.

The routes of an api specify the path. Following our example, maybe y I would like my api to expose different paths such as “aws-courses” and “gcp-courses”, In that case, my api would have two routes, one for each path; being available at:

  • devops.cool.my-domain.com/learn-api/aws-courses
  • devops.cool.my-domain.com/learn-api/gcp-courses

Each route also has a method. Possible methods are POST, PUT, PATCH, GET, DELETE. If you would like the user to be able to use any of these methods, you can indicate ANY as a method for that specific route.

The VPC link is vital, since without it the api won’t be able to access the resources to which it should be redirecting.

If you would like to know more about how api works, you can find more information on this article.

IMPORTANT: Since we are deploying an active-active configuration, make sure that the custom domain name and your routes are deployed in different regions but named the same. In our example, both custom domain names should be “devops.cool.my-domain.com” and both api routes should be the same.

In our case, we needed to implement a custom authorizer. Adding an authorizer to an api can be done from the AWS Api Gateway console, as shown below:

Where it says name, you should put the name you want for your authorizer. In case, you leave $request.header.Authorization it means that the authorization token should be included in the request. The issuer URL is the authorization server endpoint, and the audience is the client IDs registered. If, when executing the request with a token, the token doesn’t match any of the audiences listed, the api will return an authorization error.

5. Create route53 CNAME records

Once you have set up your api gateway, set up your DNS record for your api gateway. Here is the confusing part.

Step one: create a latency record for your custom domain names

Step two: create a CNAME record for your application load balancer.

Let’s go in depth into each of these steps.

Step one is setting up the latency records, one for each of the regions you want to work on. Each latency record should have the same exactly name; however, they will be pointing to their corresponding api gateway. Therefore, when a user makes a request to your custom domain name, route53 will redirect the user to the region with the least latency.

Once having done this, you need to proceed into step two. For each of your services behind your application load balancer, make sure you have a DNS record of type CNAME. In this way, the application load balancer will be able to redirect traffic to it.

Optional: configure WAF

Configuring a WAF ALC is optional, but is always recommended. Configuring this has two important aspects. The first is setting the rules, these could match by IP, location, etc. And the second one is associating the WAF ACL with the resources, it should apply its rules. If you want to save WAF logs into Kinesis Data Firehose , please bear in mind that its name should begin with aws-waf-logs (see official documentation here).

Conclusions

Configuring an active-active api might be useful as both, a disaster recovery strategy and so ensure users get redirected to the region with the least latency. The configuration of this kind of api requires setting the identical api configuration in two different regions, and then creating the route53 resources to redirect traffic to them. Adding an authorizer to the api and WAF ACL to the application load balancer is not compulsory, but is definitely a good practice doing so.

Bonus

Instead of doing this from the console, you can also do it using Terraform. We have uploaded the modules we have used to create all these resources (except the hosted zone that was created manually from the console) in this terraform repository.

Acknowledgements

This solution was designed by Ivan Fernandez , so all credits should go to him. I merely wrote the modules to implement the solution under his guidance and decided to write this article to make sure I understood the process.

--

--