Use AWS CloudFront Functions for URI Rewrites

for ('at the edge') sub-millisecond execution time.

Use AWS CloudFront Functions for URI Rewrites

With just over one week to move a customer application from one data center into our managed service environment, I was provided with a new (to me) requirement. The requirement was to configure URI redirects for their web application. This didn't seem like a huge concern at the immediate request. I figured I'd just put a couple of listener rules on the Application Load Balancer (ALB) and call it good doing what all DevOps engineers do...

image.png

That was before I received the spreadsheet with almost 60 (known) redirects. More potentially to come.

What to do?

I didn't want to make an already complicated solution more complicated.

I knew I had limits to the number of rules allowed in Load Balancer Listeners.

I wasn't interested in adding or modifying any Lambda@Edge functions managing my Content Security Policies.

Fortunately for me, right at the time of receiving this new requirement, AWS Announced CloudFront Functions.

What is/are CloudFront Functions?

...a new serverless edge compute capability. You can use this new CloudFront feature to run JavaScript functions across 225+ CloudFront edge locations in 90 cities across 47 countries.... ( read the full announcement here ).

How could CloudFront Functions help me?

Aside from the rule limits imposed on me by ALB Listeners such as:

  • 100 total rules per ALB
  • 5 conditions per rule
  • 5 wildcards per rule
  • 5 weighted target groups per rule

I would have had to use wildcards to make some of the rewrites work. You can use your imagination and the following example to see how this may not produce a favorable outcome.

Use case example

Imagine a website like AllRecipies wanting to redirect certain recipes to new or improved names.

Consider Homemade Mac and Cheese served here: allrecipes.com/recipe/11679/homemade-mac-an..

Let's say for example sake the 11679 in that URI is a catalog of recipes. AllRecipies may want to redirect anything that isn't a successful hit to a different catalog of recipes. So they use a wildcard like: allrecipes.com/recipe/11679/* to push all requests to allrecipies.com/summer21

What happens is now allrecipes.com/recipe/11679/homemade-MOUSE-.. successfully redirects with a 200 response instead of going to a 404 Page Not Found.

NOTE: oddly enough, AllRecipes is actually doing some magic to forward that URL to the correct recipe.

Using CloudFront Functions for URI Rewrites

Being under the gun to come up with a solution, I immediately took a stab at CloudFront Functions. I'm honestly not sure how I got this to work after the first attempt, so I'm interested in getting anyone's feedback on this implementation.

To accommodate an unknown amount of future requests for rewrites, I tweaked and implemented the example provided in the CloudFront Functions Introduction Blog.

My implementation

function handler(event) {
  var request = event.request;
  var rewrites = [
    ['/summer21','/recipies?year=2021&season=summer'],
    ['/recipies/homemade-mouse-and-cheese/', '/recipies/homemade-mac-and-cheese/'],
    ['/recipies/camping/grilling', '/recipies?activities=camping&with=grill']
  ]

  for (var arrayIndex in rewrites){
    if (request.uri == rewrites[arrayIndex][0]) {
      var newUri = rewrites[arrayIndex][1];

      var response = {
        statusCode: 301,
        statusDescription: 'Permanently moved',
        headers: {
          "location": { "value": newUri }
        }
      }
      return response;
    }
  }
  return request;
}

Making the solution more robust

This CloudFront Function appears to be working as expected. This example allows you to redirect any URI pattern and forward it to a new path or include a search query for client or server-side functionality. All while using JavaScript at the Edge. Without a doubt, this could be modified to further accommodate query strings in the request.

I typically like to deploy my solutions via CloudFormation specifically because this is for a customer; however, at the time of this post and the function implementation, the CloudFormation Team has not released an update to the User Guide for creating this as a managed resource in CloudFormation. I am told it should be released soon. Once I have the information, I will try to get back here and provide a CloudFormation Template in an update.

Until then, if you are looking to try this out or implement CloudFront Functions in your own environment, I encourage you to checkout this blog post by a fellow AWS Community Builder.

Please do not hesitate to comment below how you decide to implement CloudFront Functions, this specific function, or better yet how I can make this specific function even better.