---
title: "CloudFront Embedder Guide"
description: "This document describes how to apply DoveRunner watermark embedder with Lambda@Edge for service sites using the Amazon CloudFront CDN."
---
> For the complete documentation index, see [llms.txt](https://docs.doverunner.com/llms.txt).

This document describes how to apply DoveRunner watermark embedder with Lambda@Edge for service sites using the Amazon CloudFront CDN.

:::caution[Region requirement]
The Lambda@Edge function **must be created in the US East (N. Virginia) `us-east-1` region** — this is a hard AWS requirement for Lambda@Edge, not a DoveRunner-specific choice. If you create the function in another region, you cannot associate it with CloudFront and will need to delete it and start over in `us-east-1`.
:::

```mermaid
sequenceDiagram
    participant A as End user
    participant C as Cloud Front CDN
    A ->> C: Start playback of Session URL (request segments)
    Note right of C: Watermark embedder 
    C -->> C: Segments mixing by Session URL
    C ->> A: Send mixed segments
    Note right of A: Playback of mixed content
```

## Set up CloudFront Embedder using AWS CDK
This AWS CDK sample contains the source code which generates the aws resources needed to set up the CloudFront embedder.

[**CloudFront Embedder CDK sample**](https://github.com/inka-pallycon/fwm-cdn-embedder-generator)


## Set up CloudFront Embedder yourself
CloudFront Embedder files needed for setting up Lambda@Edge can be downloaded from the [Sample download page](https://docs.doverunner.com/content-security/forensic-watermarking/getting-started/fwm-downloads/).

:::note 

The content of this document may become outdated due to future updates from AWS. If there is a part different from the actual AWS console UI or there is a broken link to AWS guide document, please contact us through the [Help Desk](https://support.doverunner.com).

:::

## Tutorial Video

This video is a tutorial about how to embed Forensic Watermarking using CloudFront Embedder.

[Video: YouTube](https://www.youtube.com/watch?v=TyZ2X8tIaHQ)

> **Learn it in DoveRunner Lab**: Step-by-step lesson [Watermark embedding](https://lab.doverunner.com/academy/courses/getting-started-forensic-watermarking/watermark-embedding)

## Lambda@Edge User Guide

If you are unfamiliar with using Lambda@Edge with Amazon CloudFront CDN, it is recommended to make yourself familiar with the usage by referring to the AWS online documents below before proceeding to the next step.

  - [Get started creating and using Lambda@Edge functions](https://docs.aws.amazon.com/en_us/AmazonCloudFront/latest/DeveloperGuide/lambda-edge-how-it-works.html)
  - [Tutorial: Creating a simple Lambda@Edge function](https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/lambda-edge-how-it-works-tutorial.html)

## Create IAM Permissions and Roles

First, you need to create the required IAM permissions and execution role to configure Lambda@Edge. In the `IAM` service screen of the AWS console, create the permissions and roles as follows by refer to the [AWS guide](https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/lambda-edge-permissions.html).

 - Create a role by adding the permissions `lambda:GetFunction`, `lambda:EnableReplication*`, `iam:CreateServiceLinkedRole`, `cloudfront:UpdateDistribution`, and `cloudfront:CreateDistribution`.

> To add permission, you must first specify the target service (Lambda). Also, to add `lambda:EnableReplication*` permission, first add `lambda:EnableReplication` permission and then modify the JSON code.

> The policy editor shows a warning for `iam:CreateServiceLinkedRole` with `"Resource": "*"`. Optionally, scope the resource to `arn:aws:iam::*:role/aws-service-role/replicator.lambda.amazonaws.com/*`.

 - Add log-related permission to collect Lambda access log into cloudwatch logs.
    ```json
    {
        "Effect": "Allow",
        "Action": [
            "logs:CreateLogGroup",
            "logs:CreateLogStream",
            "logs:PutLogEvents"
        ],
        "Resource": "arn:aws:logs:*:*:*"
    }
    ```

 - Add the following roles to the `Trust Relationship` tab of the created Role.
    ```json
    { 
        "Version": "2012-10-17",
        "Statement": [
            {
                "Effect": "Allow",
                "Principal": { 
                    "Service": [
                        "lambda.amazonaws.com", 
                        "edgelambda.amazonaws.com" 
                    ] 
                }, 
                "Action": "sts:AssumeRole"
            } 
        ] 
    }
    ```

## Create Lambda@Edge function

- Go to the `Lambda` service in the AWS console and click the `Create function` button.
- Select `US East (N. Virginia)` as the AWS Region in the upper right corner of the console. (Lambda@Edge must be created in the Virginia Region to use it.)

### 1. Function name and Runtime settings

- `Function Name`: Enter any name to identify the function. (e.g. fwm-cf-embedder)
- `Runtime`: Select `Node.js 22.x`. The embedder sample uses a callback-style handler, which Node.js 24.x runtimes no longer support, so do not keep a newer default runtime.
- `Architecture`: Use `x86_64`. In `Additional settings`, leave the `ARM64 architecture` toggle off.

### 2. Set the execution role

- In `Additional settings`, turn on `Custom execution role`. In the `Configure custom execution role` panel, select the IAM role created in the previous step and click `Save`.
- Click the `Create function` button at the bottom of the screen to create a Lambda@Edge function.

### 3. Upload and edit sample code

- Click `Update > Update from a .zip file` on the `Code source` screen to upload the CloudFront Embedder zip file downloaded from the [Sample Download Page](https://docs.doverunner.com/content-security/forensic-watermarking/getting-started/fwm-downloads/).

- Check the uploaded sample code and modify the following items.

> Please be aware that if you modify a source other than those listed below, an error may occur.

- In the `config.json` source, set the value of the corresponding variables as below.

| Name | Required | Description |
|:---|:---|:-----------|
| `aesKey` | True     | Enter the site key value provided by the DoveRunner console site. |
| `type` | True     | Enter `unlabeled_a_variant` if preprocessed A/B version segments are stored together in one folder (B version files have a `b.` prefix), and enter `directory_prefix` if they are packaged in separate `0` and `1` folders. Check the output folder in your storage before you set this value. Content preprocessed with the T&P service is stored in separate `0` and `1` folders, so use `directory_prefix`. If the value does not match the folder structure, S3 returns `403 AccessDenied`. (default: `unlabeled_a_variant`) |
| `availableInterval` | True     | The URL requested for watermarking contains a timestamp value. This item is the value for checking the validity of the timestamp. If set to `0`, the timestamp validity period is not checked. The sample `config.json` sets `60000`. (Unit: minutes) |
| `prefixFolder` | True    | Set the name of the parent folder where the A/B version contents are stored<br/> - For contents packaged with old version packaging service: `dldzkdpsxmdnjrtm` <br/> - For contents packaged with the new T&P service: `wm-contents`<br/>The default value is `["dldzkdpsxmdnjrtm", "wm-contents"]`, which supports both cases. |
| `wmtPublicKey`      | False    | Set when using the wmt token type. Use the Akamai public key issued from the DoveRunner site. It can be requested the helpdesk. |
| `wmtPassword`       | False    | Set when using the wmt token type. Use the Akamai password issued from the DoveRunner site. It can be requested the helpdesk. |

> The `syncSkipBit` option added in embedder 2.10.0 (see `RELEASE.md` in the zip file) is not a `config.json` setting. The embedder reads it from the session URL payload (`sync_skip_bit`) and uses `-1` if it is not set, so you do not need to configure it.

- After saving, click `Publish new version` of `Action` button to create version.

- Copy the ARN containing the generated version. It is displayed in the upper right corner.
    - e.g. `arn:aws:lambda:us-east-1:{account no.}:function:{lambda name}:{version}`

> You can also associate the version with a distribution from the Lambda console with `Actions` > `Capabilities` > `Deploy to Lambda@Edge`.

## Configure CloudFront

You can apply Lambda@Edge to an existing CloudFront distribution or to a new one. The distribution creation wizard has no function association step, so in both cases you associate the function after the distribution is created.

### Create a distribution

If you already have a distribution that serves the watermarked content, skip to [Apply Lambda@Edge](#apply-lambdaedge).

Select the `CloudFront` menu in the AWS console, click `Create distribution`, and complete the wizard steps below.

1. `Choose a plan`: Select `Pay as you go`.
2. `Get started`: Enter a name for the distribution.
3. `Specify origin`: Select the S3 bucket where the A/B version content is stored. Keep `Allow private S3 bucket access to CloudFront` selected. CloudFront creates an origin access control (OAC) and adds the required statement to the bucket policy automatically.
4. `Enable security`: AWS WAF security protections are enabled by default and incur additional charges. Choose whether to enable them for your service.
5. `Review`: Check the settings and create the distribution.

### Apply Lambda@Edge

Connect to the AWS console, select the `CloudFront` menu and select the distribution to apply Lambda@Edge.

#### 1. Set Behaviors

- Select the `Behaviors` tab, select the `Default (*)` behavior, and click the `Edit` button.

- In `Function associations`, configure `Viewer request`.
	- Function type : select `Lambda@Edge`
	- Function ARN : input the ARN copied during Lambda@Edge creation process.

- Click the `Save changes` button.

#### 2. Finish configuration

In the distribution list, `Status` stays `Enabled`, and `Last modified` shows `Deploying` while the change is deployed. When `Last modified` shows a date, Lambda@Edge is applied and all settings are completed.

> For more information about Lambda@Edge, please refer to [CloudFront guide](https://docs.aws.amazon.com/ko_kr/AmazonCloudFront/latest/DeveloperGuide/lambda-at-the-edge.html) from AWS.

### Configure CORS

If the player runs on a different origin from the CloudFront distribution, the distribution must return CORS headers. Attach a custom response headers policy to the behavior where Lambda@Edge is associated.

- In `Policies` > `Response headers`, create a response headers policy and enable `Cross-origin resource sharing (CORS)`. Set `Access-Control-Allow-Origin`, `Access-Control-Allow-Headers`, and `Access-Control-Allow-Methods` for your player (e.g. `All origins`, `All headers`, `All methods`), and select `Origin override`.
- In the `Edit` screen of the behavior, select the policy as `Response headers policy` and click `Save changes`.

:::caution
The managed `Managed-SimpleCORS` policy can return responses without `Access-Control-Allow-Origin` to requests that carry `Cache-Control: no-cache` (e.g. a browser reload or DevTools with the cache disabled). The browser then blocks the response with a CORS error and playback fails. Use a custom policy with `Origin override` selected instead.
:::

## Troubleshooting

| Response | Cause | Action |
|:---|:---|:---|
| `503` with `X-Cache: LambdaExecutionError from cloudfront` | The Lambda@Edge function failed to run. A runtime the embedder sample does not support (e.g. `Node.js 24.x`) causes this error. | Change the runtime to `Node.js 22.x` in `Configuration` > `Runtime settings` > `Edit`, publish a new version, and associate the new version ARN with the behavior. |
| `403 AccessDenied` returned by S3 (`Server: AmazonS3`) | The segment path rewritten by the embedder does not exist in the bucket. The usual cause is a `type` value in `config.json` that does not match the folder structure. S3 returns `403` instead of `404` because CloudFront does not have `s3:ListBucket` permission. | Check the folder structure, set `type` again, publish a new version, and associate the new version ARN with the behavior. |