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.
Running Envoy yourself, outside Kubernetes? See Defender for Envoy.
Watch the install on Tetrate Enterprise Gateway (3½ minutes): downloading the release, the Secret, helm install, pointing the Gateway at Defender, allowed and blocked requests, and the gateway Envoy's own counters. Istio and kgateway follow the same steps with their own setting in step 3.
At a glance
| Deployment | One Helm install, or a set of manifests you apply, plus one setting on your Gateway. No new service to run, no routing changes. |
| Added latency | About 0.2 ms at the median on Envoy Gateway and Istio, where Defender runs inside the gateway's Envoy; about 1.3 ms on kgateway, where it runs beside it in the same pod. |
| Cost | Some extra CPU and memory in each gateway pod, which scales with the gateway. Nothing from Cequence for the infrastructure. |
| If something fails | Your APIs stay up. If Cequence is unreachable, Defender keeps enforcing its last policies; if Defender cannot run, the gateway forwards requests without it. |
| Upgrades |
helm upgrade with the new release's filter or image; helm rollback to go back. Policy changes never need an upgrade. |
Deployment architecture
Defender runs on the Kubernetes gateways built on Envoy, including those from Tetrate and Solo.io. It joins the Gateway you choose, in every one of its pods, so it grows and shrinks with the gateway's own replicas.
| Your product | Built on | How Defender attaches |
| Tetrate Enterprise Gateway, Envoy Gateway | Envoy Gateway | A filter inside the gateway's Envoy, added by an EnvoyExtensionPolicy
|
| Gloo Mesh, Tetrate Service Bridge, Istio | Istio (Gateway API gateways) | A filter inside the gateway's Envoy, added by a WasmPlugin
|
| Gloo Gateway, kgateway | kgateway | The defender-extproc container beside Envoy in each gateway pod, which the gateway calls on localhost |
BEFORE
client ---> gateway pod [ Envoy ] ------------------------> your backends
AFTER: Envoy Gateway and Istio
client ---> gateway pod [ Envoy + Defender filter ] ------> your backends
|
+---> your Cequence tenant: policies in,
analytics out, in the background
AFTER: kgateway and Gloo Gateway
client ---> gateway pod [ Envoy ] ------------------------> your backends
| localhost
v
[ defender-extproc ]
|
+---> your Cequence tenant: policies in,
analytics out, in the background
What stays the same. Your routes, backends, listeners and other policies.
Defender is added through the Gateway's own extension resources and one
parametersRef on the Gateway; remove that reference to undo it.
What Defender does with a request. It decides each request from a policy set already held in the gateway pod, so no request waits on Cequence. A blocked request is answered by the gateway and never reaches your backend. An allowed request is forwarded byte for byte, and your client receives the response byte for byte: Defender inspects a copy of each body, up to your tenant's capture settings, and never changes what it forwards.
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. Your client secret is read from a Kubernetes Secret and never appears in Defender's configuration, the gateway's Deployment or its logs.
Installation
Prerequisites
- One of these gateways, at the version Defender is tested with:
- Envoy Gateway 1.9 (Tetrate Enterprise Gateway).
- Istio 1.31, with Gateway API gateways (Gloo Mesh, Tetrate Service Bridge).
- kgateway 2.4 (Gloo Gateway).
- Helm 3, if you install with Helm. No chart repository is needed: the chart is
in the bundle, at
charts/defender-for-envoy. - Outbound HTTPS from the gateway pods to
edge.<tenant>.cequence.cloudandauth.<tenant>.cequence.cloud. On Envoy Gateway and Istio, also todownloads.cequence.ai, where the gateway pods download the filter at start and check it against its sha256. - Your tenant's name (such as
acme.1), client ID and client secret. - On kgateway, credentials from Cequence to pull the
defender-extprocimage from Cequence's registry.
The bundle's defender.conf.example names the two release-specific values:
-
ENVOY_WASM_PATH: the filter's download URL, for Envoy Gateway and Istio. Its file name is the filter's sha256, so the URL ends in/<sha256>.wasm. -
ENVOY_EXTPROC_IMAGE: thedefender-extprocimage, for kgateway.
1. Create the Secret
In the namespace where the gateway pods run: for Envoy Gateway, by default
envoy-gateway-system; for Istio and kgateway, the Gateway's own namespace.
kubectl -n <namespace> create secret generic defender-client --from-literal=client-secret="$CEQUENCE_CLIENT_SECRET"
If your Envoy Gateway runs gateway pods in the Gateway's namespace, create the
Secret there, and set proxyNamespace (Helm) or --proxy-namespace
(render-k8s) to it.
2. Install Defender
With Helm. From the bundle folder, in the Gateway's namespace:
helm install defender-for-envoy ./charts/defender-for-envoy -n <Gateway's namespace> \ --set platform=<envoy-gateway, istio or kgateway> \ --set gateway.name=<gateway name> \ --set tenant.slug=<tenant name, such as acme.1> \ --set tenant.clientId=<client id> \ --set filter.url=<ENVOY_WASM_PATH> --set filter.sha256=<the sha256 in that URL>
The chart derives your tenant's hosts from tenant.slug: for acme.1,
https://edge.acme.1.cequence.cloud and
https://auth.acme.1.cequence.cloud/auth/realms/cequence/protocol/openid-connect/token.
Set tenant.edgeUrl and tenant.authUrl only if Cequence gives you other
addresses.
On kgateway, set extproc.image=<ENVOY_EXTPROC_IMAGE> instead of the two
filter settings, and name your image pull secret with
--set "extproc.imagePullSecrets[0].name=<pull secret>".
If Cequence has given you access to its chart repository, you can install from
there instead: helm repo add cequence <chart repository URL> --username <token user> --password <token>,
then use cequence/defender-for-envoy in place of ./charts/defender-for-envoy.
Without Helm. Copy the bundle's defender.conf.example to defender.conf,
fill in CEQUENCE_TENANT and CEQUENCE_CLIENT_ID, then write the manifests and
apply them. No client secret is needed here; the gateway pods read it from the
Secret.
./bin/defenderctl-envoy render-k8s --platform <envoy-gateway, istio or kgateway> --gateway <namespace>/<gateway name> kubectl apply -f defender-<platform>/
On kgateway, add your image pull secret to the gateway pods
(podTemplate.imagePullSecrets in the GatewayParameters it writes).
Both ways produce the same resources.
3. Point your Gateway at Defender
Both ways of installing print the setting to add to your Gateway:
| Platform | spec.infrastructure.parametersRef |
| Envoy Gateway | { group: gateway.envoyproxy.io, kind: EnvoyProxy, name: defender } |
| Istio | { group: "", kind: ConfigMap, name: defender-gateway-options } |
| kgateway | { group: gateway.kgateway.dev, kind: GatewayParameters, name: defender } |
The platform restarts the gateway pods with Defender added. If your Gateway
already names parameters of its own, merge Defender's into them instead; the
bundle's KUBERNETES.md says what each one adds.
4. Check it before you go live
- Install with diagnostics on (
--set diagnostics=true, orCEQUENCE_DIAGNOSTICS=yesindefender.conf) on a test Gateway, and request/__end/statusthrough it.policies_loadedshows your tenant's policy count. - Send a request that one of your policies blocks, and check it is blocked.
On Envoy Gateway,
kubectl -n envoy-gateway-system rollout status deploy -l gateway.envoyproxy.io/owning-gateway-name=<gateway name>says when the gateway pods have restarted with Defender, and Defender's EnvoyExtensionPolicy reportsAccepted:kubectl -n <Gateway's namespace> get envoyextensionpolicy defender -o jsonpath='{.status.ancestors[0].conditions[?(@.type=="Accepted")].status}'. The gateway Envoy's own counters show both kinds of request: port-forward a gateway pod's admin port (kubectl -n envoy-gateway-system port-forward pod/<pod> 19000:19000) and openhttp://127.0.0.1:19000/stats?filter=downstream_rq_[24]xx. Blocks count as 4xx on the Gateway's listener. - Turn diagnostics off again (
helm upgrade ... --reuse-values --set diagnostics=false, or render and apply again without it). The status page is readable by anyone who can reach the Gateway.
Upgrades and rollback
Each release has its own filter URL and defender-extproc image, in the new
bundle's defender.conf.example. With Helm, keep your other settings and change
only those:
helm upgrade defender-for-envoy ./charts/defender-for-envoy -n <Gateway's namespace> --reuse-values \ --set filter.url=<new ENVOY_WASM_PATH> --set filter.sha256=<the sha256 in that URL>
On kgateway, use --set extproc.image=<new ENVOY_EXTPROC_IMAGE> instead.
To roll back, helm history defender-for-envoy -n <Gateway's namespace> lists
the revisions, and helm rollback defender-for-envoy <revision> -n <Gateway's namespace>
returns to one.
Without Helm, set ENVOY_WASM_PATH (or ENVOY_EXTPROC_IMAGE) in
defender.conf from the new bundle, run the new bundle's render-k8s and
apply. To roll back, do the same with the previous values.
During the upgrade, the platform replaces the gateway pods, as it does for any change to the Gateway's parameters. Run two or more gateway replicas so the Gateway keeps serving while they roll. Each new pod forwards requests until it has loaded your policies, and analytics not yet sent from an old pod are lost. Policy changes never need an upgrade: Defender picks them up while it runs.
Performance and sizing
| At 1,000 requests a second | Envoy Gateway and Istio | kgateway |
| Added latency, median | about 0.2 ms (0.73 to 0.95 ms) | about 1.3 ms (0.73 to 2.0 ms) |
| Added latency, 95th percentile | about 1.4 ms (1.9 to 3.3 ms) | about 5.9 ms (1.9 to 7.8 ms) |
| Added CPU | about 0.7 core, in the gateway's Envoy | 0.66 core in the Defender container, and about 0.4 core more in the gateway's Envoy |
| Added memory per gateway pod | about 150 MiB | about 190 MiB in the Defender container |
Measured on a 4 vCPU host at 1,000 requests a second, with a policy set of about 6,000 policies, analytics and masking on, and 1 KB responses; the Envoy Gateway and Istio column is the same filter measured in Envoy. Cost scales with request rate; more policies, larger bodies or more Sensitive Data rules raise it.
On kgateway the Defender container requests 250m CPU and 256 MiB by default
(extproc.resources in the chart). Do not limit its CPU below what your traffic
needs: a throttled Defender delays every request.
Cost
Cequence charges nothing for the infrastructure. Defender runs in your existing gateway pods, using the CPU and memory in "Performance and sizing" above; there is no separate service, load balancer or licence to add on your side.
Availability
- If Cequence is slow or unreachable, your traffic is unaffected. Defender keeps enforcing the policies it last received, and checks for new ones every 10 seconds. It holds a bounded backlog of analytics and sends it once Cequence is reachable again; a long outage can drop some.
- If Defender itself cannot run, the gateway forwards requests without it. On Envoy Gateway and Istio, the filter is installed fail-open: if it cannot load, the gateway's Envoy skips it. On kgateway, if the Defender container does not answer within 1 second, the request is forwarded uninspected.
-
If you need Defender to stop acting at once, change the policies in your
Cequence tenant to a non-blocking action; gateway pods pick it up within about
10 seconds and keep reporting. To take Defender off the path entirely, remove
the
parametersReffrom your Gateway; the pods restart without it. - A fresh install blocks nothing until your tenant's first policy publish arrives.
Known limits
-
blockandadd-headerpolicies are enforced.challenge,rate-limitandredirectpolicies are reported but not applied: the request is forwarded. - On Envoy Gateway and Istio, a policy that matches on the request body can block the request but cannot add a header to it. On kgateway it can do both.
- On kgateway, request bodies reach your backend with
Transfer-Encoding: chunkedand noContent-Length; HTTP/1.1 backends must accept chunked bodies. - Envoy Gateway allows one
EnvoyExtensionPolicyper Gateway. If yours has one, Defender's filter must be added to it;KUBERNETES.mdin the bundle says how. - Istio's classic ingress gateway and sidecars are not covered yet.
- Defender sees the request as the gateway has normalised it. Envoy Gateway
merges duplicate slashes in the path by default, so a policy written for
//does not match; setpath.disableMergeSlashes: truein aClientTrafficPolicyif you need the slashes kept. - Changing Defender's settings or version restarts the gateway pods; policy changes do not.
- Defender is tested on the open-source Envoy Gateway, Istio and kgateway these products are built on.
If something is wrong
Requests keep flowing in every case below: Defender forwards when it cannot decide.
| Symptom | What to check |
| Gateway pods do not start | The Secret is missing from the namespace where the pods run (step 1) |
policies_loaded stays at 0 |
Outbound HTTPS from the gateway pods to your tenant's hosts, and the client ID and secret |
| kgateway pods cannot pull the Defender image | The image pull secret for Cequence's registry is missing from the gateway pods |
| Nothing is enforced and there is no status page | The Gateway's parametersRef (step 3) is not set, or names a different resource |
helm install stops naming tenant.slug, filter.url, filter.sha256 or extproc.image
|
That value is missing; the release values are in the bundle's defender.conf.example
|
| Every client looks like one address | Set clientIpHeader (Helm) or ENVOY_CLIENT_IP_HEADER to the header your load balancer writes; the default is x-envoy-external-address
|
defenderctl-envoy status --platform <platform> --gateway <namespace>/<gateway name>
lists Defender's resources on the Gateway. If you contact support, send the
output of /__end/status, which contains no credentials. Full troubleshooting
and every setting are in the bundle's KUBERNETES.md.
Removing it
- Remove the
parametersReffrom your Gateway, or point it back at what it named before. The pods restart without Defender. - With Helm,
helm uninstall defender-for-envoy -n <Gateway's namespace>. Without Helm,defenderctl-envoy render-k8s --delete --platform <platform> --gateway <namespace>/<gateway name>prints thekubectl deletecommands for what it added; it runs nothing itself. - Delete the
defender-clientSecret, and ask Cequence to disable the client credential or rotate its secret.
Your routes and backends were never changed, so nothing else needs undoing.