This is a preview release. Do not use it in production environments.
Download the release bundle from Download Edge-Native Defender (Preview). New to Edge-Native Defender? Start with Edge-Native Defender overview.
At a glance
| Deployment | One CloudFormation stack in your AWS account, attached to the cache behaviors you choose on your existing CloudFront distribution. One installer does both. |
| Added latency | Defender's own decision takes about 0.4 ms. The end-to-end figure for this release is being measured. |
| Cost | Nothing from Cequence for the infrastructure. You pay AWS for Lambda, a small DynamoDB table, an SQS queue and the CloudFront requests involved. |
| If something fails | If Cequence is unreachable, Defender keeps enforcing its last policies and holds analytics in a queue. If Defender cannot decide a request, it forwards it to your origin. |
| Upgrades | Run upgrade from the new bundle with the same config file. Roll back by running upgrade from the previous bundle. |
Deployment architecture
Defender runs in your AWS account as a Lambda Web Function: a long-running function with its own HTTPS endpoint. The cache behaviors you choose use it as their origin. Defender decides each request, then hands it on to your origin. Your distribution, domains and origin stay as they are, and your traffic does not leave your AWS account.
There are two ways to place Defender, called patterns:
BEFORE
client ---> CloudFront ---------------------------------------> your origin
AFTER, relay (the default)
client ---> CloudFront ---> Defender ---> CloudFront ----------> your origin
| (/__cq-origin/* behavior)
+---> policy table, queue (in your account)
<---> your Cequence tenant, in the
background
AFTER, direct
client ---> CloudFront ---> Defender --------------------------> your origin
-
Relay (
CEQUENCE_PATTERN=relay, the default). Defender hands the request back to CloudFront, which fetches your origin on a/__cq-origin/*behavior you add, with that origin's own settings. Works with any distribution, and is required when an inspected behavior's origin is an origin group, an S3 origin, an origin signed by origin access control, or a VPC origin. It needs three edits to your distribution before you install (step 2 below). -
Direct (
CEQUENCE_PATTERN=direct). Defender fetches your origin itself. Nothing to build first, but each inspected behavior must use a plain custom origin.
Beside Defender, in the same stack, a publisher function fetches your policies from Cequence and writes them to a policy table (DynamoDB, with a copy in each region Defender runs in), which Defender reads every 2 seconds. Analytics go to a queue (SQS), and a consumer function sends them to Cequence. Your client secret is kept in Secrets Manager and is read only by the publisher and the consumer, never by the function every request reaches.
What stays the same. Only the cache behaviors you name change, and only
three settings on each: the origin (a Defender origin that forwards to the
origin the behavior used before), the origin request policy (the AWS managed
AllViewerExceptHostHeader; your origin still receives every viewer header,
with Host set to your origin's own name), and the viewer-request function (a
small CloudFront Function that passes the viewer's Host to Defender). Each
setting is recorded before it is changed, and uninstall puts it back exactly.
Your origins and other behaviors are not touched. Only your distribution can
reach Defender's endpoint: it accepts only requests CloudFront signs for your
distribution.
What Defender does with a request. A request a policy blocks is answered by Defender and never reaches your origin. Every other request is forwarded whole, at any size, and the response returned to your client as your origin sent it. Defender inspects a copy of each body, up to your tenant's capture settings. CloudFront answers cache hits itself, so Defender sees cache misses only: use a caching-disabled cache policy on behaviors where Defender should see every request.
What is sent to Cequence. For each request: its headers and URL, the response status and headers, and the inspected body copies, masked first with your tenant's Sensitive Data rules. Your traffic filters decide whether a request is reported at all.
Installation
Prerequisites
- An existing CloudFront distribution in the account you install into. The installer never creates one.
-
Inspected behaviors Defender can stand in front of. Each must use a cache
policy (not legacy cache settings), must not already run a viewer-request
CloudFront Function, and must not include
Hostin its cache key. Under direct, each must also use a plain custom origin. -
Lambda Web Functions available to your account in the region the stack
goes in (
us-east-1unless you choose otherwise). -
The AWS CLI v2,
python3andcurlon the machine you install from, with credentials that can manage CloudFormation, Lambda Web Functions, CloudFront, S3, Secrets Manager, DynamoDB, SQS, EventBridge and IAM, and read CloudWatch Logs. Cequence never receives your AWS credentials. - Your tenant's name, client ID and client secret.
1. Unpack the bundle and fill in the config
In the unpacked defender-for-aws bundle, check its integrity and copy the
example config, which every command reads:
sha256sum -c SHA256SUMS cp defender.conf.example defender.conf
Set the three required keys:
| Key | What it is |
CEQUENCE_DISTRIBUTION_ID |
the distribution to attach to, such as E1234567890ABC (not a domain name) |
CEQUENCE_TENANT |
your tenant name, such as acme.1 -- not a URL, and check the trailing number |
CEQUENCE_CLIENT_ID |
your client ID |
The client secret never goes in the file. Export it; the installer stores it in Secrets Manager in your account:
export CEQUENCE_CLIENT_SECRET=PUT_YOUR_SECRET_HERE
Optional keys worth knowing (every key is in the bundle's CONFIGURATION.md):
| Key | Default | What it does |
CEQUENCE_PATTERN |
relay |
relay or direct
|
CEQUENCE_AWS_INSPECTED_PATHS |
the default behavior | cache behaviors to attach to, such as /api/*; each must already exist |
CEQUENCE_EXCLUDED_ROUTES |
none | paths Defender must not see, such as /api/health/*; a behavior is created for each, copied from the one it is carved out of |
CEQUENCE_EDGE_REGIONS |
all five | regions Defender runs in; one region runs it there only, so choose the one nearest your origin |
CEQUENCE_AWS_REGION |
us-east-1 |
where the stack, secret, publisher, queue and consumer live; keep it the same for the life of the install |
CEQUENCE_NAMESPACE |
prod |
names everything the install owns; use a different one per environment |
CEQUENCE_DIAGNOSTICS |
no |
yes serves the status page and x-end-echo report; see step 4 |
2. Relay only: prepare your distribution
Skip this under direct. Under relay, make these three edits to the same
distribution before you install (./bin/defenderctl-aws steps prints them):
-
Add a loop origin: an origin pointing at the distribution's own
CloudFront domain (such as
dXXXX.cloudfront.net), HTTPS only, with Origin path/__cq-origin. -
Add a cache behavior
/__cq-origin/*targeting your real origin, with the settings that origin needs (origin group, origin access control, VPC origin, Origin Shield, origin request policy), a caching-disabled cache policy, and no Lambda@Edge association. - Point each behavior you want inspected at the loop origin.
Install then puts Defender's relay function on /__cq-origin/*: it admits
only requests Defender forwarded, so that path is not a way around Defender. A
relayed request cannot loop back into Defender.
3. Check, install and attach
./bin/defenderctl-aws validate ./bin/defenderctl-aws preflight ./bin/defenderctl-aws install ./bin/defenderctl-aws status
validate checks defender.conf only, with no AWS calls. preflight checks
your account, every inspected behavior, your Cequence tenant and the bundle, and
changes nothing. install creates the stack cequence-defender-<namespace>-web,
stores the secret, deploys the code, then attaches Defender to your behaviors.
status shows what is deployed and which behaviors actually reach Defender.
CloudFront then takes a few minutes to deploy the change to your distribution.
4. Check it before you go live
- Send a few requests through an inspected behavior, then run
./bin/defenderctl-aws verify. Every line should beok: a request went through Defender (each response it handles carries anx-cequence-timingheader), the publisher is reaching your tenant, Defender loaded your policies, and the queue is draining. - Publish a test block policy that matches only a header you choose. Send a request with that header and check it is blocked; send it without and check it reaches your origin. Remove the test policy afterwards.
- If you installed with
CEQUENCE_DIAGNOSTICS=yes,verifyalso reads Defender's status page. Set it back tonoand runupgrade: the status page is readable by anyone who can reach an inspected route.
Upgrades and rollback
- Unpack the new bundle and copy in the same
defender.conf. - Export
CEQUENCE_CLIENT_SECRET, then run:./bin/defenderctl-aws upgrade ./bin/defenderctl-aws verify
upgrade takes the same path as install: it deploys the new code to the same
stack and re-attaches every behavior. Your distribution keeps pointing at the
same Defender endpoint, which moves to the new code; any effect on requests in
flight during that switch is being measured. Change CEQUENCE_EDGE_REGIONS by
at most one region per upgrade.
To roll back, run upgrade the same way from the previous release's bundle.
This works back to 0.19.0, the first release on Lambda Web Functions.
Performance and sizing
| Defender's decision | about 0.4 ms |
| Added latency, end to end | being measured |
| Request bodies | forwarded whole; checked intact from 5 bytes to 6 MB |
| Policy copies reaching each region | 0.4 to 0.7 s on average, at most about 1.3 s |
Measured on test installs on 14 October 2026; the policy-copy times are DynamoDB's replication figures over 30 minutes of publishes. There is nothing to size: AWS runs as many copies of the function as your traffic needs. Under direct, running Defender in the region nearest your origin keeps that leg short.
Cost
Cequence charges nothing for the infrastructure. AWS charges your account, at its published rates, for:
- Lambda: the Defender function's invocations and duration, per inspected request (cache misses only); the publisher, which runs every minute, one at a time, at 1 GB of memory; and the consumer, at 512 MB, as analytics arrive.
- DynamoDB: the policy table, on-demand, with a copy in each region Defender runs in.
- SQS: the analytics queue and its dead-letter queue.
-
CloudFront: a CloudFront Function run on each inspected request; under
relay, also the second CloudFront request on
/__cq-origin/*and the relay function there. - Small fixed items: one Secrets Manager secret, an S3 bucket for the code, and CloudWatch Logs kept 30 days. An excluded path never reaches the function and is not billed for it.
Availability
- If Cequence is slow or unreachable, your traffic is unaffected. No request waits on Cequence: Defender keeps enforcing the policies in its table, and analytics wait in the queue (kept four days) until Cequence is reachable again.
- If Defender cannot decide a request, it forwards it to your origin uninspected. If AWS itself throttles the function or cannot start it, the client receives that error; see Known limits.
-
If you need Defender off the path, run
./bin/defenderctl-aws uninstall. It restores every behavior exactly as it was and waits for CloudFront to deploy that, which takes a few minutes. To take only some paths off, add them toCEQUENCE_EXCLUDED_ROUTESand runupgrade. - A fresh install blocks nothing until your tenant's first policy publish arrives.
Known limits
- Every policy action is enforced:
block,add-header,challenge,rate-limitandredirect. A client that cannot complete a challenge, such as an API client, receives the challenge page, so scope challenge policies to paths browsers use. - JA3 and JA4 fingerprints do not reach Defender on CloudFront, so policies keyed on them do not match.
- Rate limits are counted by each running copy of the function. Under heavy traffic AWS runs several copies, and together they admit up to that many times the authored rate.
- If AWS throttles the function (429), sheds load (503) or a new copy fails to start, that error goes to the client; CloudFront cannot retry it at your origin on a behavior that accepts POST.
- A request has 30 seconds end to end through Defender. An origin that takes longer is answered with 502.
- Defender runs in five regions:
us-east-1,us-east-2,us-west-2,eu-west-1andap-northeast-1. Requests are served from the one nearest the CloudFront location that received them. - Policies decide on the request. Responses are reported, not enforced on.
- Traffic that reaches your origin without going through this distribution is not inspected. Restrict your origin with IP allowlisting or a secret origin custom header; Defender passes your origin's custom headers through.
If something is wrong
-
Nothing is inspected. No behavior is attached, or CloudFront has not
finished deploying.
statusreports each behavior; if one points at a different endpoint, runupgrade. Requests CloudFront served from cache are never inspected. -
preflightrefuses a behavior. See Prerequisites. If it says/__cq-origin/*or the loop origin is missing, make the step 2 edits, or setCEQUENCE_PATTERN=direct. - The publisher has not published, or cannot reach your tenant. Check the client ID, the secret and the tenant name, including its trailing number.
More detail is in the bundle's README.md and CONFIGURATION.md. Opening a
ticket? Attach the output of ./bin/defenderctl-aws debug: it is read-only and
shows credentials by their first and last four characters only.
Removing it
./bin/defenderctl-aws uninstall
It asks you to type the namespace to confirm. It puts every attached behavior
back as it was, removes the Defender origins and any behaviors it created for
CEQUENCE_EXCLUDED_ROUTES, waits for CloudFront to deploy that, then deletes
the stack. Under relay it also restores the /__cq-origin/* behavior's
function; the loop origin and that behavior are yours to keep or remove. Your
distribution and its DNS are never deleted.