Using [email protected] to modify incoming requests with CloudFront and S3

By | June 25, 2020

CloudFront is typically used to map to static apps in S3. These apps can be based on JS technologies such as Angular, React and Vue. However, in some cases you may want multiple static apps or special requests behaviors to occur with the request before calling the S3 bucket to serve the app.

The AWS solution for this is called [email protected] It will allow you to transform the request in anyway needed before calling S3.

In this setup, we have two apps under one bucket. The bucket is called:

somewebsite.com

The primary app is in the root of the bucket, with the secondary app located in the /chain subfolder. When requests come in with the /chain URI, they need to call the index.js so the secondary application is invoked with this happens. This is initially configured in CloudFront.

The CloudFront origin is the bucket mentioned above. The CloudFront behavior is where [email protected] gets implemented. When editing the Default Behavior you will see this configuration setting:

[email protected] can only be configured in Us-east-1 so the lambda being used points to that region. Also, when referencing the ARN, the version number must be specified. Aliases are not supported.

The full Lambda ARN referenced in the screen shot above is:

arn:aws:lambda:us-east-1:272128128266:function:LambdaRequestModifier:26

The Lambda does the following in order to ensure the request gets transformed properly.

var LOGGER = {
    // tslint:disable-next-line: no-console
    console: console.log,
};
exports.handler = function (event, context, callback) {
    var request = event.Records[0].cf.request;
    var uri = request.uri;
    var queryString = request.querystring;

    // Setup the two different origins
    LOGGER.console('pre request', uri, queryString);
    var originA = 'somewebsite.com.s3.amazonaws.com';
    // const originB = 'someotherwebsite.cocm.s3.amazonaws.com';
    if (uri === '/chain') {
        LOGGER.console('Chain request', uri);
        // LOGGER.console('Route to old store app', originB);
        // headers.host = [{ key: 'host', value: originB }];
        request.uri = uri.replace('/chain', '/chain/index.html');
        // origin.s3.domainName = originB;
    }
    else {
        LOGGER.console('Non chain request', uri);
        LOGGER.console('Route to new store app', originA);
        // headers.host = [{ key: 'host', value: originA }];
        // request.uri = '/index.html';
        // origin.s3.domainName = originA;
    }
    LOGGER.console('Req uri', request.uri);
    LOGGER.console('Req query string', queryString);
    callback(null, request);
};
//# sourceMappingURL=index.js.map

You can see from the code above, we first grab the request, the URI and the query string from the request object provided by Lambda. The bucket origin is also mapped to the S3 bucket hosting both apps. When the URI is equal to /chain, we replace the URI with /chain/index.html to ensure the index file of the secondary app gets invoked, otherwise we simply leave the request alone. We then return the potentially modified request object in the callback function which ensures the appropriate application gets invoked.

This properly demonstrates how [email protected] can used to modify anything about an incoming request for static apps that use CloudFront as a front end.