Search code examples
amazon-web-servicesamazon-s3amazon-cloudfrontcdnaws-cdn

multiple prefix of single S3 bucket mapping to single CloudFront distribution


I've two scenarios

  1. Single S3 bucket will hold data for multiple environments
  2. Single S3 bucket which will holds data for single environment

In both these scenarios bucket will be private and public to CloudFront only

Where I want to restrict access to S3 resources, other than files prefix/folder.

I want to allow access by CloudFront to only files prefix

  • which can be at nested level (Scenario 1 -> env1/{files}/images/image1.jpg)
  • or at root level (Scenario 2 -> {files}/images/image1.jpg)
  • any other prefix/folder than /files/ should be restricted

Bucket scenarios :

Scenario 1 (common bucket for multiple environments)

 bucket1.s3.{region}.amazonaws.com
 ├── env1
 │  ├── files
 |       ├── images
 │           ├── image1.jpg
 │           ├── image2.jpg
 │
 ├── env2
 │  ├── files
 |       ├── images
 │           ├── image1.jpg
 │           ├── image2.jpg
 ├── env3
 │  ├── files
 |       ├── images
 │           ├── image1.jpg
 │           ├── image2.jpg

Scenario 2 (bucket dedicated to environment)

 bucket2.s3.{region}.amazonaws.com
 |── files
 |  |── images
 │      ├── image1.jpg
 │      ├── image2.jpg

I want to setup common (or individual) CloudFront distribution with configuration for both the scenarios

where

 Origin: {bucketname}.s3.{region}.amazonaws.com
 Behaviors
    Path pattern 1: /*/files*    (scenario 1 : common bucket for multiple environments))
    Path pattern 2: files/*      (scenario 2 : bucket dedicated to environment)

but it seems origin path as /*/files* or files/* is not working, with above behaviors

Do we have any way to setup such kind of Origin and Behaviors in CloudFront distribution to achieve mentioned behavior?


Solution

  • CloudFront functions can solve this problem https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/cloudfront-functions.html

    They can run on each viewer request, which we can't run on Origin request/response like Lambda@Edge function, but lambda functions are not suitable for such scenario where CDN need to return resources with minimum latency.

    To filter all request on CDN, we can associate function with Default(*) pattern on distribution's default behaviors

    where below function can decide on which folder path is allowed or restricted as part of URI

    function handler(event) {
        var request = event.request;
        var uri = request.uri;
        var folderPrefix = "/files/";
    
        if(uri.indexOf(folderPrefix) > -1){
            console.log("files prefix found");
            return request;
        }else{
            console.log("other folders are not allowed");
            var response = {
                statusCode: 403,
                statusDescription: 'Access Denied'
            }
            return response;
        }
    }