CloudFront Integration Workflow
The CloudFront integration lets you deploy Monocle without changing your application code.
This is the no-code setup path for customers who serve traffic through Amazon CloudFront. Once configured, Monocle can analyze traffic on the hosts and paths you choose and surface results in the dashboard.
Blocking is only applied when policy-based enforcement is enabled.
How it works
The CloudFront integration deploys three pieces into your AWS account, all named monocle-*:
- A CloudFront Function on the viewer-request path that runs Monocle's checks
- A KeyValueStore that holds the integration's configuration
- A Lambda@Edge function (in
us-east-1) that verifies challenge responses
Monocle manages these through a cross-account IAM role that you create in your account. Every AssumeRole call requires the External ID shown in the Monocle dashboard (a standard confused-deputy defence), and no long-lived credentials are ever exchanged.
You can use the integration to:
- Assess traffic without adding code to your site
- Choose which hosts and paths Monocle should run on
- Configure a block response
- Redeploy when plugin updates are available
- Remove the integration when it is no longer needed
Before you begin
You need access to:
- An AWS account with a CloudFront distribution serving your traffic
- Permission to create IAM roles in that account (or to run a CloudFormation stack that creates one)
Create a Monocle app
To start the CloudFront integration:
- Create a new Monocle app.
- Enter the app name.
- Choose CloudFront as the integration type.
- Continue to the Connect AWS step.
The Connect AWS step shows the two values every setup path needs:
- Spur's AWS account ID, which goes in the role's trust policy
- Your app's External ID, which the trust policy must require on every AssumeRole call
Create the access role with CloudFormation
The fastest path is the Launch CloudFormation stack button in the Connect AWS step. It opens your AWS console with the stack pre-filled (Spur's account ID and your External ID are already set as parameters), so you just click Create stack.
When the stack finishes, copy the RoleArn value from the stack's Outputs tab and paste it into the Monocle dashboard.
If you prefer not to use CloudFormation, create the role manually as described below. Both paths produce an identical role.
Create the access role manually
Step 1: Create the role with a custom trust policy
- In the AWS console, go to IAM, then Roles, then Create role.
- Choose Custom trust policy.
- Paste the following, replacing
SPUR_ACCOUNT_IDandEXTERNAL_IDwith the values shown in the Monocle dashboard's Connect AWS step:
{"Version": "2012-10-17","Statement": [{"Effect": "Allow","Principal": { "AWS": "arn:aws:iam::SPUR_ACCOUNT_ID:root" },"Action": "sts:AssumeRole","Condition": {"StringEquals": { "sts:ExternalId": "EXTERNAL_ID" }}}]}
The External ID condition is required. Without it, the Monocle dashboard cannot assume the role, and validation will fail.
Step 2: Attach the permissions policy
Skip the managed-policy screen and finish creating the role, then add this as an inline policy (or create it as a customer-managed policy and attach it). Replace YOUR_ACCOUNT_ID with your own AWS account ID:
{"Version": "2012-10-17","Statement": [{"Sid": "Distributions","Effect": "Allow","Action": ["cloudfront:ListDistributions","cloudfront:GetDistribution","cloudfront:GetDistributionConfig","cloudfront:UpdateDistribution"],"Resource": "*"},{"Sid": "EdgeFunction","Effect": "Allow","Action": ["cloudfront:CreateFunction","cloudfront:UpdateFunction","cloudfront:PublishFunction","cloudfront:DescribeFunction","cloudfront:DeleteFunction","cloudfront:GetFunction"],"Resource": "arn:aws:cloudfront::YOUR_ACCOUNT_ID:function/monocle-*"},{"Sid": "KeyValueStore","Effect": "Allow","Action": ["cloudfront:CreateKeyValueStore","cloudfront:DescribeKeyValueStore","cloudfront:DeleteKeyValueStore","cloudfront:ListKeyValueStores","cloudfront:UpdateKeyValueStore"],"Resource": "*"},{"Sid": "KeyValueStoreData","Effect": "Allow","Action": ["cloudfront-keyvaluestore:DescribeKeyValueStore","cloudfront-keyvaluestore:ListKeys","cloudfront-keyvaluestore:GetKey","cloudfront-keyvaluestore:PutKey","cloudfront-keyvaluestore:DeleteKey","cloudfront-keyvaluestore:UpdateKeys"],"Resource": "*"},{"Sid": "VerifyLambda","Effect": "Allow","Action": ["lambda:CreateFunction","lambda:DeleteFunction","lambda:GetFunction","lambda:PublishVersion","lambda:UpdateFunctionCode","lambda:UpdateFunctionConfiguration","lambda:EnableReplication*"],"Resource": "arn:aws:lambda:us-east-1:YOUR_ACCOUNT_ID:function:monocle-*"},{"Sid": "ServiceLinkedRoles","Effect": "Allow","Action": "iam:CreateServiceLinkedRole","Resource": ["arn:aws:iam::YOUR_ACCOUNT_ID:role/aws-service-role/replicator.lambda.amazonaws.com/*","arn:aws:iam::YOUR_ACCOUNT_ID:role/aws-service-role/logger.cloudfront.amazonaws.com/*"]},{"Sid": "LambdaRole","Effect": "Allow","Action": ["iam:CreateRole","iam:DeleteRole","iam:GetRole","iam:PassRole","iam:AttachRolePolicy","iam:DetachRolePolicy"],"Resource": "arn:aws:iam::YOUR_ACCOUNT_ID:role/monocle-*"}]}
What each statement is for:
- Distributions: list your distributions (for the picker) and update the one you choose to attach or detach Monocle's function associations.
- EdgeFunction, KeyValueStore, KeyValueStoreData: create and manage Monocle's own CloudFront Function and its configuration store. Everything Monocle creates is named
monocle-*, and the mutating function actions are scoped to those names. - VerifyLambda: manage the challenge-verification Lambda@Edge function, scoped to
monocle-*inus-east-1(the only region Lambda@Edge deploys from). Redeploys update the function in place because an @Edge function attached to a distribution cannot be deleted and recreated. - ServiceLinkedRoles: the first Lambda@Edge association in an AWS account makes AWS create two service-linked roles. This one-time permission is scoped to exactly those two roles.
- LambdaRole: create the Lambda's
monocle-*execution role and attach it.iam:PassRoleis scoped tomonocle-*so the integration can never grant itself an unrelated role.
Step 3: Validate the role
- Name the role (for example
MonocleAccess) and finish creating it. - Copy the role's ARN from the IAM console.
- Paste the ARN into the Monocle dashboard's Connect AWS step and validate.
Validation actually assumes the role with your External ID and lists your distributions, so a green check means the trust policy, External ID, and permissions all work.
Choose a distribution and protected hosts
- Pick the CloudFront distribution that serves your traffic. A distribution can host one Monocle app.
- Choose the hosts to protect from the distribution's own hostnames (its
*.cloudfront.netdomain and aliases) and the paths Monocle should run on (for example/*or/login*).
Configure the block response and deploy
- Configure what visitors see when your policy returns a Block decision (an HTML response or a redirect). You can change this at any time from the Monocle CloudFront admin page.
- Deploy. Monocle provisions the function, KeyValueStore, and Lambda, then attaches them to your distribution. The distribution propagates the change over a few minutes.
Blocking requires policy-based enforcement. Without a policy, Monocle assesses traffic but does not block.
Updates and removal
- When a new plugin version is available, the admin page shows an update prompt; redeploying updates the edge functions in place.
- Removing the integration detaches Monocle from your distribution and deletes the
monocle-*resources it created. Your distribution keeps serving traffic throughout. - Deleting the CloudFormation stack (or the manually created role) after removal revokes Spur's access entirely.