Skip to content

AWS CloudFront

This module is for AWS CloudFront distributions, using the AWS CloudFront Lambda@Edge service.

Supported Runtimes

Peakhour supports Lambda runtimes until they reach their deprecation date. You can find the list of supported runtimes in this AWS documentation.

Peakhour supports the following Lambda runtimes:

Language Supported runtimes
Node.js nodejs18.x, nodejs20.x, nodejs22.x
Python python3.9, python3.10, python3.11, python3.12, python3.13

Installation

Prerequisites

  • Your Peakhour API key, available in your Peakhour account.
  • Your domain configured to use Peakhour.

AWS IAM permissions

To associate your Lambda@Edge function with your CloudFront distribution and to record logs, you need to create IAM permissions and roles.

  1. Go to the Identity and Access Management (IAM) page, in the Policies tab.
  2. Click on the Create policy button.
  3. Select JSON in the Policy editor, and paste the following permissions:

    View required IAM policy
    {
        "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "VisualEditor0",
            "Effect": "Allow",
            "Action": [
                "iam:CreateServiceLinkedRole",
                "lambda:GetFunction",
                "cloudfront:UpdateDistribution",
                "lambda:EnableReplication"
            ],
            "Resource": "*"
        },
        {
          "Effect": "Allow",
          "Action": [
            "logs:CreateLogGroup",
            "logs:CreateLogStream",
            "logs:PutLogEvents"
          ],
          "Resource": [
            "*"
          ]
        }
        ]
    }
    
  4. Click Next, enter a name for this policy, and click Save.

  5. Go to the IAM page, in the Role tab.
  6. Click Create role.
  7. Select the Trusted entity type to AWS service, select the Use case to Lambda, and click Next.
  8. Select the IAM policy created in step 4 and click Next.
  9. Enter a name for this role, and click Create role.
  10. Click on the Trust relationships tab and Edit trust policy.
  11. Paste the following trusted service principals to assume function execution role for your Lambda@Edge:

    {
      "Version": "2012-10-17",
      "Statement": [
        {
          "Effect": "Allow",
          "Principal": {
            "Service": [
              "lambda.amazonaws.com",
              "edgelambda.amazonaws.com"
            ]
          },
          "Action": "sts:AssumeRole"
        }
      ]
    }
    

Configuration of the CloudFront distribution

If you don't already have one, refer to this AWS documentation to create a CloudFront distribution.

Create a custom error 403 response

This disables the caching of responses with a 403 HTTP code.

  1. Go to your CloudFront distribution page in the Error pages tab, and click Create custom error response.
  2. In the Create custom error response page, set the following properties:
    1. Select HTTP code 403.
    2. Set minimal TTL 0.
    3. Check No for Customise error response.
  3. Click Create custom error response.

Configure the distribution's default behaviour

This defines the default behaviour of the CloudFront distribution.

  1. Go to your CloudFront distribution page in the Behaviours tab, and edit the default behaviour.
  2. In the Cache key and origin requests section, select Cache policy and origin request policy and set the Origin request policy to AllViewerExceptHostHeader.
  3. Click Save changes.

Configuration of the AWS Lambda@Edge function

In this section, you will create and configure the AWS Lambda@Edge function to intercept incoming requests and validate them with our service.

Note: It is possible to call and configure the Lambda@Edge function through an existing one. Refer to the advanced configuration section to use an existing Lambda@Edge function.

  1. Connect to your AWS console and go to the Lambda@Edge homepage.
  2. Create a new Lambda@Edge function.

    Important: The function must be created in the us-east-1 region. AWS automatically selects the us-east-1 region when you access the Lambda@Edge portal. Please do not change the region.

  3. Click Create function, then select Author from scratch.

  4. In the Basic information section:
    1. Enter a name for your Lambda function, e.g. Peakhour-WAF-{YOUR WEBSITE NAME}.
    2. Select Node.js 20.x or Python 3.12 for the runtime.
    3. Click Create function.
  5. In the Code source tab, choose Upload a file from Amazon S3 and paste the URL for the selected module.

    https://s3.amazonaws.com/peakhour-lambda-edge/peakhour-lambda-edge-latest.zip

    https://s3.amazonaws.com/peakhour-lambda-edge/peakhour-lambda-edge-py-latest.zip

  6. Open the peakhour.js file (for the Node.js runtime) or peakhour.py (for the Python runtime).

  7. Replace YOUR_PEAKHOUR_API_KEY with your own Peakhour API key, available in your Peakhour account. You will also need to enter your domain name.
  8. Scroll down to the Runtime settings tab, click Edit.
  9. In the Runtime settings page:
    • Enter the handler name in the Handler field. === "Node.js" peakhour.handler === "Python" peakhour.lambda_handler
    • Click Save.
  10. In the Configuration tab and General configuration menu, click Edit.
  11. In the Edit basic settings page:
    • Set Timeout to 1 sec.
    • Select an existing role with the required permissions.
    • Click Save.
  12. Click Actions and select Deploy to Lambda@Edge.
  13. In the Deploy to Lambda@Edge window, provide the following configuration:
    • Select the CloudFront distribution that will send events to the Lambda function.
    • Select the default Cache behaviour (*).
    • Select Viewer Request for CloudFront Event.
    • Do not check the Include body box.
    • Check the Confirm deploy to Lambda@Edge box.
    • Click Deploy.

Note: Protection is not operational when the Lambda function is associated with origin request. CloudFront will cache requests, even if caching is completely disabled. Most requests will be executed by the AWS caching mechanism, with modified headers (like user-agent: Amazon CloudFront), and will not be intercepted by the Peakhour module. If there is already another function associated with the viewer request event, refer to the use of an existing lambda function to merge them.

Congratulations! You can now see your traffic in your Peakhour dashboard.

You can refer to the recommended configuration below to enhance the protection of your CloudFront distribution.

Disable CloudFront caching for requests protected by Peakhour

If you are caching dynamic requests (not javascript, css, images) at the CloudFront level and these requests are protected by Peakhour, you must change your backend origin to ask CloudFront not to cache these requests if they contain a set-cookie in the response.

By default, CloudFront will cache HTTP requests even if the backend returned a cookie. This can lead to unexpected bot detection issues. Your backend/origin needs to return this header: Cache-Control: no-cache="Set-Cookie".

You can find more information about this CloudFront behaviour in AWS Documentation, in the Disable caching of Set-Cookie headers section.

If you were caching files that were also protected by Peakhour, you may want to invalidate the cache by following this CloudFront documentation.

Include Client Hints and Fetch Metadata in request headers

Client Hints and Fetch Metadata can be collected by the Peakhour module to enhance detection.

For these values to be defined by the browser, an Accept-CH header must be sent by the origin. You can achieve this by using a response header policy.

  1. Go to the CloudFront distribution that you want to configure.
  2. In the Cache key and origin requests section, on the Response headers policy part click Create response headers policy to enable HTTP Client hints.
  3. In the Create response headers policy tab, set the following:
    • On the Details section, set the response headers policy's name: Accept-CH-and-Vary.
    • On the Custom headers section, click Add header.
    • Set the following values for the new custom headers:
      • For the Client Hint:
        • Name: Accept-CH.
        • Value: Sec-CH-UA,Sec-CH-UA-Mobile,Sec-CH-UA-Platform,Sec-CH-UA-Arch,Sec-CH-UA-Full-Version-List,Sec-CH-UA-Model,Sec-CH-Device-Memory.
        • Check Yes for the Origin override.
      • For the Fetch Metadata:
        • Name: Vary
        • Value: Sec-Fetch-Dest,Sec-Fetch-Mode,Sec-Fetch-Site,Sec-Fetch-User.
        • Check Yes for the Origin override.
    • Click Create.
  4. Back on the CloudFront distribution page, refresh the response headers policy list and select your Accept-CH-and-Vary custom header.
  5. Click Save changes.

Associate the Lambda@Edge with non-default distribution behaviours

By default, the Lambda@Edge is associated with the default behaviour of the distribution you selected, meaning that requests going through other behaviours, which are ranked higher, will not be protected.

  1. Go to the CloudFront distribution console that you want to configure.
  2. Click on Behaviours.
  3. Select one of the behaviours you want to protect, and click Edit.
  4. Associate the Lambda@Edge function on the Viewer Request and copy the Peakhour Lambda@Edge ARN, which includes the version number.
  5. Click Save changes.

Advanced configuration

Settings

By default, the configuration is located in the first code block of the peakhour.js (or peakhour.py) file.

Refer to the list below for the possible configuration settings.

Setting Description Required Default
PEAKHOUR_API_KEY Your Peakhour API key, found in your Peakhour Account. Yes
PEAKHOUR_DOMAIN Your domain name as configured in your Peakhour account. Yes
PEAKHOUR_TIMEOUT The request timeout to Peakhour API, in milliseconds. Optional 300
PEAKHOUR_URI_REGEX_INCLUDE Regular expression to include URIs in the Peakhour analysed traffic. Optional
PEAKHOUR_URI_REGEX_EXCLUDE Regular expression to exclude URIs from the Peakhour analysed traffic. Optional List of excluded static assets
PEAKHOUR_USE_X_FORWARDED_HOST Use the X-Forwarded-Host header instead of Host when the application is behind a reverse proxy/load balancer. Optional false

Note: It is not possible to use environment variables in Lambda@Edge due to an AWS limitation - see Restrictions on edge functions. However you can still follow the steps to configure the module from another function file and override a configuration depending on AWS Secrets Manager for instance.

Protect only a part of a CloudFront Distribution

To protect only a part of a CloudFront Distribution, select one of the possibilities below:

  • Option 1: Set an exclusion based on file extension. Modify the value PEAKHOUR_URI_REGEX_EXCLUDE inside peakhour.js (or peakhour.py) to exclude hits to the Peakhour API. In this case, the Lambda@Edge function is still executed (and billed) at the Amazon infrastructure level.
  • Option 2: Set an exclusion based on the path. Define a behaviour in your CloudFront Distribution and attach the Lambda@Edge only to the needed paths. In this case, there is no Lambda execution at the Amazon infrastructure level.
Advanced: Use an existing Lambda@Edge function (only supported with Node.js)

Calling and configuring the module can be done from another file.

The following example explains how to update a handler in an index.js file.

  1. Import the Peakhour code as mentioned above.
  2. Import the Peakhour module inside your index.js file:

    const peakhour = require("./peakhour.js");
    
  3. Configure the Peakhour module inside your index.js file:

    // Configure Peakhour module
    const configuration = {
      apiKey:               'YOUR_PEAKHOUR_API_KEY',
      domain:               'your-domain.com',
      timeout:              300,
      uriPatternInclusion:  null,
      uriPatternExclusion:  /\.(avi|flv|mka|mkv|mov|mp4|mpeg|mpg|mp3|flac|ogg|ogm|opus|wav|webm|webp|bmp|gif|ico|jpeg|jpg|png|svg|svgz|swf|eot|otf|ttf|woff|woff2|css|less|js|map)$/i
    };
    peakhour.configure(configuration);
    

    Note: Update the configuration values (apiKey and domain are mandatory). Other keys are shown with their default values.

  4. Update your handler from the index.js file to execute the Peakhour protection:

    exports.handler = (event, context, callback) => {
      // Call Peakhour handler
      peakhour.handler(event, context, callback);
      // [...]
    }
    
    1. Ensure that the handler configured for this Lambda@Edge is index.handler in the Runtime settings section.

Upgrade

To update the code of the Lambda@Edge and publish a new version, apply the following steps:

  1. Select the lambda function to update.
  2. Store the active configuration of the module (List of possible settings).
  3. Click Upload from then Amazon S3 location.
  4. Paste the right S3 location depending on the runtime used for the lambda and click Save.

    https://s3.amazonaws.com/peakhour-lambda-edge/peakhour-lambda-edge-latest.zip

    https://s3.amazonaws.com/peakhour-lambda-edge/peakhour-lambda-edge-py-latest.zip

  5. Replace YOUR_PEAKHOUR_API_KEY with your Peakhour API key.

  6. Restore other specific configurations stored during Step 2.
  7. Click Actions and Deploy to Lambda@Edge to deploy this up-to-date version.
  8. Select the CloudFront distribution and click Deploy.

FAQ

How can I integrate Peakhour on a multi-account architecture?

If you have multiple CloudFront distributions deployed on different AWS accounts, one Lambda@Edge function per account is required.

You must repeat the configuration of the CloudFront distribution and the configuration of the Lambda@Edge function section for each of your distributions.

Can I integrate Peakhour on CloudFront Functions?

It is not possible to set up Peakhour inside CloudFront Functions as they do not provide network access to call third-party APIs. See Restrictions on CloudFront Functions.