Making use of Lambda@Edge outside of us-east-1 in CDK
Published: 2022-07-04 04:58:06

If you are deploying Lambda@Edge functions and CloudFront at us-east-1 it is straightforward to get all the resources stood up properly

## Background

ap-southeast-2 is my home region, 
us-east-1 is where I deploy CDN and other Global resources. 

CloudFront got deployed from a stack in ap-southeast-2, as my OAI and S3 will need to be in my home region (Even though my CDN comes from the ap-southeast stack, but it will get stay in N.Virginia region without problem)

Note: Lambda@Edge functions must be created in the us-east-1 region, regardless of the region of the CloudFront distribution and stack

When I look closer, if you deploy the Edge function in us-east-1, you can take advantage of using the normal lambda construct,

```
func = lambda_.Function(self, "EdgeFunction",
    runtime=lambda_.Runtime.NODEJS_12_X,
    handler="index.handler",
    code=lambda_.Code.from_asset(<path_of_your_lambda@edge function>)
)
```

If you have the stack structures like me, you would need to  upload ARN or relevant reference to the SSM and let the resources passing from region to region

Thumb up to below method

> EdgeFunction


```
edge_lambda_function = cloudfront.experimental.EdgeFunction(self, "edge_lambda_function",
    runtime=lambda_.Runtime.NODEJS_12_X,
    handler="index.handler",
    code=lambda_.Code.from_asset(<path_of_your_lambda@edge function>),
)
```

So now, on the same stack, you can reference it in the main menthod.


```
cdn_distribution = cloudfront.Distribution(
self, 
"cdn_distribution",
default_behavior=cloudfront.BehaviorOptions(origin=my_origin),
    additional_behaviors={
        "images/*": cloudfront.BehaviorOptions(
            origin=my_origin,
            edge_lambdas=[cloudfront.EdgeLambda(
                function_version=edge_lambda_function.current_version,
                event_type=cloudfront.LambdaEdgeEventType.VIEWER_REQUEST,
                include_body=True
            )
            ]
        )
    }
)
```


## Problem

When using the CloudFront EdgeFunction with a role specified attached to the function, 

```
edge_lambda_role = iam.Role(
               self,
                "edge-lambda-iam-role",
             assumed_by=iam.CompositePrincipal(
                    iam.ServicePrincipal('lambda.amazonaws.com'),
                    iam.ServicePrincipal('edgelambda.amazonaws.com')
                ),
                managed_policies=[
                    iam.ManagedPolicy.from_aws_managed_policy_name('service-role/AWSLambdaBasicExecutionRole')
                ]
            )
```

Error - 

```
Adding this dependency ("edge-lambda-stack-xxxxxxxxxxxxxxxxxxxxxxxxx/edge-fucntion/Resource" depends on "cloudfront/edge-iam-role/Resource") would create a cyclic reference.
```

This is the most tricky part, and took me a while to understand what's going on.


## Solution
 
After some research, someone mentioned:

> The created us-east-1 stack must have a dependency on the "main" stack, as the main stack can't be created first; doing so would mean the function ARN isn't available to read and that the Distribution would not deploy correctly. Creating the role in the main stack certainly leads to a circular dependency.

So I have to remove it, and let the Lambda@Edge construct to create it on the fly (I think it does better than the IAM role we defined, I will explain that in a bit)

Under the hood, the EdgeFunction method does this:
1. create the IAM role, which will have enough permission to do all the magic but it is not permissive

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nzesgil5ag9mtdjj1k72.png)
 

2. a custom resource also upload the version arn to param store (CloudFront want the version arn instead of function arn)

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bk5k8ehq2rd0snpc7rmj.png)


It took me 2 hours to get this all going, enjoy finding the solution and also hope this you find helpful as well