The Lambda@Edge integration acts as a proxy between consumer applications and backend APIs or applications. This function can be used on CloudFront, which accelerates the distribution of static and dynamic web content. By acting as a proxy, the Lambda@Edge function intercepts incoming requests and responses on CloudFront, collates the data, and sends it to the Cequence Unified API Protection (UAP) platform.
API Call Flow
The following diagram traces the logic flow of an API call.
- CloudFront receives a request from downstream. When the response is not in the Edge cache, Cloudfront sends the request to the upstream origin.
- The Lambda@Edge custom integration component intercepts the origin request with the Origin Request trigger.
- Lambda@Edge sends the request upstream from the Origin Request trigger.
- Lambda@Edge receives the response from Upstream at the Origin Request trigger.
- The Lambda@Edge function sends the response without triggering Origin Response from Cloudfront.
- Cloudfront sends the response back to downstream from CloudFront.
- Lambda@Edge generates a transaction structure in the expected JSON format, fetches an access token if needed, and sends the transaction to the Cequence Bridge. Cequence Bridge forwards the transaction to the Cequence UAP platform.
Prerequisites
Before you begin, confirm that your environment meets these prerequisites.
- NodeJS release 18.0.0
- Terraform CLI v1.10.5 on darwin_arm64
- Access to the AWS CLI
- Working APIs deployed on AWS API Gateway or EC2, or APIs routed by AWS LoadBalancers
- AWS CloudFront Distribution configured to route requests to an Origin
- AWS CLI User with Access Key and Secret with an attached policy named cequence_tf_iam_policy_for_lambda_at_edge. The policy must have permissions to manage CloudFront Distribution, Lambda, IAM, & CloudWatch.
- Cequence Bridge deployed
AWS CLI user privileges
Setting up the Amazon CloudFront integration requires the use of an AWS CLI user account with an access key, secret, and below privileges. These restricted permissions gets applied to resources that are created by Terraform.
Cequence policy for Lambda@Edge
{ "Statement": [ { "Action": [ "lambda:CreateFunction", "lambda:GetFunction", "lambda:DeleteFunction", "lambda:UpdateFunctionCode", "lambda:UpdateFunctionConfiguration", "lambda:ListFunctions", "lambda:GetFunctionConfiguration", "lambda:AddPermission", "lambda:RemovePermission", "lambda:ListVersionsByFunction", "lambda:PublishVersion", "lambda:CreateAlias", "lambda:UpdateAlias", "lambda:DeleteAlias", "lambda:GetAlias", "lambda:GetFunctionCodeSigningConfig", "lambda:EnableReplication*", "lambda:ListAliases" ], "Effect": "Allow", "Resource": "arn:aws:lambda:us-east-1:*:function:*" }, { "Action": [ "cloudfront:UpdateDistribution", "cloudfront:TagResource", "cloudfront:UntagResource", "cloudfront:ListTagsForResource", "cloudfront:ListDistributions", "cloudfront:GetDistributionConfig", "cloudfront:GetDistribution" ], "Effect": "Allow", "Resource": "*" }, { "Action": [ "iam:CreateRole", "iam:GetRole", "iam:DeleteRole", "iam:PutRolePolicy", "iam:GetRolePolicy", "iam:DeleteRolePolicy", "iam:AttachRolePolicy", "iam:DetachRolePolicy", "iam:ListAttachedRolePolicies", "iam:ListRolePolicies", "iam:ListInstanceProfilesForRole" ], "Effect": "Allow", "Resource": "arn:aws:iam::*:role/*" }, { "Action": [ "s3:ListBucket", "s3:GetObject", "s3:PutObject", "s3:DeleteObject" ], "Effect": "Allow", "Resource": [ "arn:aws:s3:::*" ] }, { "Action": [ "logs:CreateLogGroup", "logs:CreateLogStream", "logs:PutLogEvents", "logs:DescribeLogGroups", "logs:DeleteLogGroup", "logs:PutRetentionPolicy", "logs:ListTagsForResource" ], "Effect": "Allow", "Resource": "arn:aws:logs:*:*:*" }, { "Action": "iam:PassRole", "Condition": { "StringEquals": { "iam:PassedToService": [ "lambda.amazonaws.com", "edgelambda.amazonaws.com", "cloudfront.amazonaws.com" ] } }, "Effect": "Allow", "Resource": "arn:aws:iam::*:role/*" }, { "Action": "iam:CreateServiceLinkedRole", "Condition": { "StringEquals": { "iam:AWSServiceName": [ "cloudfront.amazonaws.com", "lambda.amazonaws.com", "edgelambda.amazonaws.com" ] } }, "Effect": "Allow", "Resource": [ "arn:aws:iam::*:role/aws-service-role/cloudfront.amazonaws.com/AWSServiceRoleForCloudFront", "arn:aws:iam::*:role/aws-service-role/lambda.amazonaws.com/AWSServiceRoleForLambda", "arn:aws:iam::*:role/aws-service-role/edgelambda.amazonaws.com/AWSServiceRoleForLambdaEdge" ] } ], "Version": "2012-10-17" }
Note: If you have more than 500 CloudFront distributions, request an increase from AWS Support. When you have only one Cequence Lambda@Edge function, the maximum number of distributions follows the Lambda limits.
Installing the Lambda@Edge integration
There are two methods of using Terraform to install Lambda@Edge.
Select a method
- Select a CloudFront Distribution from a command-line prompt: An interactive method used when you have no more than two CloudFront Distributions to integrate.
- Configure an AWS S3 Bucket: Use this approach when you're integrating more than two CloudFront Distributions and you have a list of known and curated CloudFront Distributions available.
Installing Lambda@Edge from the command line
- Download the compressed archive file.
- At the command line, extract the archive file.
- From the cequence directory, run the following command to make the scripts executable.
-
chmod +x ./scripts/*.sh
- Make a copy of the cequence/scripts/.env.sample file.
Name the copy .env. - Edit the copy to add the UAP Tenant configuration details.
The final configuration matches the following example.
tf_auto_approve=false cequence_client_id=<client_id> cequence_client_secret=<client_secret> cequence_auth_endpoint=https://auth.<subdomain>.cequence.ai/auth/realms/<subdomain>/protocol/openid-connect/token # Populate the Cequence Bridge URL
cequence_edge_endpoint=https://<cequence-bridge-fqdn-or-ip-address>/api-transactions # Log values supported are trace, debug or info cequence_log_level=debug use_config_from_s3=false
#If the Value of use_config_from_s3 is false, no need to populate the below two attributes s3_bucket_name=cequence-config-ACCOUNT_ID s3_file_name=cequence-config.json - From the scripts/ directory, run the following command to invoke Terraform.
./setup-tf.sh
A list of Cloudfront Distributions appears. - Select a set of Cloudfront distributions with the spacebar, then press S.
- Terraform saves a list of distributions. After installation, the Lambda@Edge integration is active for those distributions.
Terraform lists the changes that it will implement. - When Terraform prompts for a value, type Yes.
Terraform creates artefacts. - Note the values of the lambda_at_edge_function_arn and lambda_at_edge_function_name lines in the Terraform output. These values are used during validation.
The ARN has the format "arn:aws:lambda:<aws region>:<ID number>:function:cequence-cf-lambda-edge-<ID>".
The function name is the element of the ARN after function:, in the form "cequence-cf-lambda-edge-<ID>".
Lambda@Edge is now installed. Proceed to Validating the plugin installation and enabling the integration.
Installing Lambda@Edge by configuring an AWS S3 bucket
This method defines the CloudFront Distributions in a JSON configuration file.
- Download the compressed archive file.
- At the command line, extract the archive file.
- In the cequence/scripts directory, create a file named cequence-config.json that lists CloudFront Distributions. After installation, the Lambda@Edge integration is active for those distributions. The following sample illustrates the format for defining CloudFront Distributions.
-
[
{
"distributionId": "E1D3UM66TAFJW8"
},
{
"distributionId": "EWVFK89YQW4KF"
}
] - From the cequence directory, run the following command to make the scripts executable.
-
chmod +x ./scripts/*.sh
- Make a copy of the cequence/scripts/.env.sample file.
Name the copy .env. - Edit the copy to add the UAP Tenant configuration details.
The final configuration matches the following example.
tf_auto_approve=false cequence_client_id=<client_id> cequence_client_secret=<client_secret> cequence_auth_endpoint=https://<domain-name>/auth/realms/cequence/protocol/openid-connect/token # Populate the Cequence Bridge URL
cequence_edge_endpoint=https://<cequence-bridge-fqdn-or-ip-address>/api-transactions # Log values supported are trace, debug or info cequence_log_level=debug use_config_from_s3=true
# If the Value of use_config_from_s3 is false, no need to populate the below two attributes s3_bucket_name=cequence-cloudfront-distribution-config s3_file_name=cequence-config.json - From the scripts/ directory, run the following command to invoke Terraform.
./setup-tf.sh
Terraform lists the changes that it will implement. - When Terraform prompts for a value, type Yes.
Terraform creates artefacts. - Note the values of the lambda_at_edge_function_arn and lambda_at_edge_function_name lines in the Terraform output. These values are used during validation.
The ARN has the format "arn:aws:lambda:<aws region>:<ID number>:function:cequence-cf-lambda-edge-<ID>".
The function name is the element of the ARN after function:, in the form "cequence-cf-lambda-edge-<ID>".
Lambda@Edge is now installed. Proceed to Validating the plugin installation and enabling the integration.
Validating the plugin installation and enabling the integration
Once Terraform has finished, validate that the plugin has installed and is operating correctly.
- Log in to CloudFront.
- Navigate to the CloudFront distribution > Select the Distribution ID > Behaviors tab. Select a behavior and click Edit.
The behavior details page appears. - At the bottom of the behavior details page, confirm that Lambda@Edge appears in the Function associations - optional pane, and that the pane contains the ARN for the lambda function.
The ARN for the lambda function is available from Terraform output during installation. - Close the behavior details page to return to the CloudFront Distribution selection page.
- Select the same CloudFront distribution, then select the Tags tab.
- Confirm that the cequence-enabled tag is present and that the value of the tag is true.
- Navigate to the US-EAST-1 AWS region, then to Lambda > Functions.
A list of functions appears. - Confirm that the Cequence lambda function appears on the list.
- Click the Cequence lambda function.
The lambda function details page appears. - Confirm that the .env file has the correct entries.
The file listing of the function, include .env, is in the Code tab of the lambda function details page. - Run the following command to invoke the API using the CloudFront Distribution endpoint.
curl https://<your-cloudfront-distribution>.cloudfront.net/test/rest-echo/get
Go to the Cequence UAP platform dashboard and examine CloudWatch logs to confirm that the lambda function is operating properly.
Uninstall the Cequence plugin
To remove the Cequence plugin, run the rollback-tf.sh script from the cequence/scripts directory.
Troubleshooting
Problem: "All Distribution IDs have tags. Nothing to do." error when the ./setup-tf.sh script runs.
Resolution: Confirm that a CloudFront distribution without a Cequence tag exists.
Problem: Invoking the API over the CloudFront Endpoint after the plugin is installed generates a 503 Error.
Resolution:
- From the CloudFront Distribution with the Cequence plugin enabled, click View Metrics.
- From Lambda@Edge, select the Errors tab.
An errors chart appears. - Click the colored dot to display the region where the error originates.
The Orange dot in the example image represents the us-east-2 Ohio region. - At the bottom of the page, click the radio button of the Lambda function, then click Metrics.
- From the function logs drop-down, select the region of the error.
CloudWatch logs appear. - Examine the CloudWatch logs for errors or issues.
- Verify the .env file has the correct contents. If you change any values in the .env file, click Deploy.
CEQUENCE_AUTH_URL="https://<domain-name>/auth/realms/cequence/protocol/openid-connect/token" CEQUENCE_BRIDGE_URL="https://<domain-name>/api-transactions" CEQUENCE_CLIENT_ID="<client_id>" CEQUENCE_CLIENT_SECRET="<client_secret>" CEQUENCE_MAX_RETRIES=5 CEQUENCE_INITIAL_DELAY=1000 #debug or info are supported CEQUENCE_LOG_LEVEL="debug" CEQUENCE_DISABLED=false
- Scroll to the top right and click Deploy to Lambda@Edge.
- Select the existing CloudFront trigger on this function and click Deploy.
Observe the deployment status while deployment and replication take place. - After Deployment Status updates to Enabled, invoke the API calls from curl or postman and verify the transactions on The Cequence UAP platform dashboard.
Problem: Environment Variables are not supported by Lambda@Edge Functions.
Resolution: According to Amazon's documentation, environment variables are supported.
Known Limitations
- Lambda@Edge has 1 MB response size limit. Do not enable distributions that primarily serve content over this size. While responses are still made, performance time is extended. As a best practice, choose distributions that primarily serve APIs and not static content.
- CloudFront does not process all content types. The following content types are not processed by Lambda@Edge:
- application/xml (Method: POST)
- application/soap+xml (Method: POST)
- application/html (Method: POST)
- Request than 8KB in length return a 403 Forbidden error.
- Response, timeouts and keep-alive timeout for custom origins have the following limitations.
- The response generated by a lambda function has a hard size limit of 1 MB, including headers and body.
- When using Lambda@Edge functions to set the response timeout or keep-alive timeout for distribution origins, confirm that the origin supports the specified value.
- Response and keep-alive timeout quotas for custom origins have the following limitations.
- For response timeout, the default is 30 seconds.
- For keep-alive timeout, the default is 5 seconds.
- Either quota supports integer values from 1 to 60 seconds. To request an increase, create a case in the AWS Support Center Console. After receiving the timeout increase, update the distribution origins to have the required response timeout and keep-alive timeout values. A quota increase for the account doesn't automatically update the origins.
- When deploying Lambda@Edge with terraform, deploy only numbered versions, not $LATEST or aliases.
More Quotas Limitations on Lambda@Edge
- An AWS account's Cloudfront Distributions can have up to 500 Lambda@Edge functions in total, and no more than 100 functions in a given distribution. You can request an increase in this limit from AWS.
- Up to 500 CloudFront Distributions can be associated.
- The maximum compressed size of a Lambda function and any included libraries is 50MB.
- The concurrency limit for Lambda@Edge requests per second in a given AWS region is 10,000.
For further reading, visit Quotas - Amazon CloudFront.
Lambda features not supported by Lambda@Edge
- Lambda runtime management configurations other than Auto (default)
- Configuration of your Lambda function to access resources inside your VPC
- Lambda function dead letter queues
- Lambda environment variables (except for reserved environment variables)
- Lambda functions with Managing AWS Lambda dependencies with layers
- Using AWS X-Ray
- Lambda provisioned concurrency
- Create a Lambda function using a container image
- Lambda functions that use the arm64 architecture
- Lambda functions with more than 512 MB of ephemeral storage
- Capturing Lambda function logs in JSON structured format
- Controlling the log level granularity of Lambda function logs
- Setting which Amazon CloudWatch log group Lambda sends logs to
- Using a customer managed key to encrypt your .zip deployment packages
When deploying a CloudFront distribution, the gRPC option can't be enabled because it doesn't support Lambda@Edge.