DEV Community

desawsume
desawsume

Posted on

Making use of Lambda@Edge outside of us-east-1 in CDK

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>)
)
Enter fullscreen mode Exit fullscreen mode

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>),
)
Enter fullscreen mode Exit fullscreen mode

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
            )
            ]
        )
    }
)
Enter fullscreen mode Exit fullscreen mode

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')
                ]
            )
Enter fullscreen mode Exit fullscreen mode

Error -

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

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

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

Image description

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

Top comments (0)