Envoy Gateway supports two types of Wasm extensions within the EnvoyExtensionPolicy API: HTTP Wasm Extensions and Image Wasm Extensions.
Packaging a Wasm extension as an OCI image is beneficial because it simplifies versioning and distribution for users.
Additionally, users can leverage existing image toolchain to build and manage Wasm images.
This document describes how to build OCI images which are consumable by Envoy Gateway.
Wasm Image Formats
There are two types of images that are supported by Envoy Gateway. One is in the Docker format, and another is the standard
OCI specification compliant format. Please note that both of them are supported by any OCI registries. You can choose
either format depending on your preference, and both types of images are consumable by Envoy Gateway EnvoyExtensionPolicy API.
Build Wasm Docker image
We assume that you have a valid Wasm binary named plugin.wasm. Then you can build a Wasm Docker image with the Docker CLI.
First, we prepare the following Dockerfile:
$ cat Dockerfile
FROM scratch
COPY plugin.wasm ./
Note: you must have exactly one COPY instruction in the Dockerfile in order to end up having only one layer in produced images.
Then, build your image via docker build command
$ docker build . -t my-registry/mywasm:0.1.0
Finally, push the image to your registry via docker push command
$ docker push my-registry/mywasm:0.1.0
Build Wasm OCI image
We assume that you have a valid Wasm binary named plugin.wasm, and you have buildah installed on your machine.
Then you can build a Wasm OCI image with the buildah CLI.
First, we create a working container from scratch base image with buildah from command.
$ buildah --name mywasm from scratch
mywasm
Then copy the Wasm binary into that base image by buildah copy command to create the layer.
This task provides instructions for configuring Dynamic Modules.
Dynamic Modules are a critical extension mechanism that allows functionality to be loaded directly into the Envoy proxy process at runtime, typically as shared object files (.so). This approach enables customized filtering and request processing without requiring a full recompile of the core Envoy binary, streamlining deployments and upgrades.
Envoy Gateway is able to load dynamic modules from the local filesystem using EnvoyExtensionPolicy. This example demonstrates it’s working by loading the Coraza Web Application Firewall (WAF) using Built On Envoy development toolkit. The module’s full documentation can be found on the Coraza WAF extension page.
Prerequisites
Follow the steps below to install Envoy Gateway and the example manifest. Before
proceeding, you should be able to query the example backend using HTTP.
Expand for instructions
Install the Gateway API CRDs and Envoy Gateway using Helm:
Gateway API CRD compatibility
This command installs Gateway API CRDs. If your Kubernetes provider already manages compatible Gateway API CRDs for the cluster,
use the provider-managed Gateway API CRD install steps
instead.
The entire configuration can also be specified directly on the Gateway instead by using spec.envoyProxy.
Configuration
Create a new EnvoyExtensionPolicy resource to configure the dynamic module for an entire Gateway or per HTTPRoute.
This EnvoyExtensionPolicy targets the Gateway “eg” created with the quickstart. It loads the Coraza WAF extension with its configuration.
cat <<EOF | kubectl apply -f -
apiVersion: gateway.envoyproxy.io/v1alpha1
kind: EnvoyExtensionPolicy
metadata:
name: waf-extension
spec:
targetRefs:
- group: gateway.networking.k8s.io
kind: Gateway
name: eg
dynamicModule:
- name: composer
filterName: coraza-waf
config:
directives:
- Include @coraza.conf
- SecRuleEngine On
- SecResponseBodyAccess Off
- Include @crs-setup.conf
- Include @owasp_crs/*.conf
EOF
Save and apply the following resource to your cluster:
---apiVersion:gateway.envoyproxy.io/v1alpha1kind:EnvoyExtensionPolicymetadata:name:waf-extensionspec:targetRefs:- group:gateway.networking.k8s.iokind:Gateway# or e.g. HTTPRoutename:egdynamicModule:- name:composerfilterName:coraza-wafconfig:directives:- Include @coraza.conf- SecRuleEngine On- SecResponseBodyAccess Off- Include @crs-setup.conf- Include @owasp_crs/*.conf
Verify the Envoy Extension Policy configuration:
kubectl get envoyextensionpolicy/waf-extension -o yaml
Testing
Ensure the GATEWAY_HOST environment variable from the Quickstart is set. If not, follow the
Quickstart instructions to set the variable.
Checkout the Developer Guide to get involved in the project.
3 - Envoy Patch Policy
This task explains the usage of the EnvoyPatchPolicy API.
Note: This API is meant for users extremely familiar with Envoy xDS semantics.
Also before considering this API for production use cases, please be aware that this API
is unstable and the outcome may change across versions. Use at your own risk.
Introduction
The EnvoyPatchPolicy API allows user to modify the output xDS
configuration generated by Envoy Gateway intended for EnvoyProxy,
using JSON Patch semantics.
Motivation
This API was introduced to allow advanced users to be able to leverage Envoy Proxy functionality
not exposed by Envoy Gateway APIs today.
Security Warning
Security Warning
Enabling EnvoyPatchPolicy may lead to complete security compromise of your system.
Users with EnvoyPatchPolicy permissions can inject arbitrary configuration to proxies,
leading to high Confidentiality, Integrity and Availability risks.
Injected configuration may include arbitrary code executed by the proxy without any isolation. Such code may be used
to launch SSRF attacks, as well as allow users to gain access to proxy credentials as described in CVE-2026-22771.
With such access, users can fetch the complete proxy configuration, including secrets and cluster network topology.
When enabling EnvoyPatchPolicy, additional security measures should be taken by admins to reduce security risks, including:
Using K8s RBAC to restrict access to EnvoyPatchPolicy.
Disabling envoy extensions which are not needed with envoy command line options.
Implementing Kubernetes network policies that restrict traffic from the proxy pod only to relevant targets.
Use admission control tools to validate EnvoyPatchPolicy resources, ensuring that only approved patches admitted.
Audit EnvoyPatchPolciy resources periodically, and audit logEnvoyPatchPolicy API server operations.
Quickstart
Prerequisites
Follow the steps below to install Envoy Gateway and the example manifest. Before
proceeding, you should be able to query the example backend using HTTP.
Expand for instructions
Install the Gateway API CRDs and Envoy Gateway using Helm:
Gateway API CRD compatibility
This command installs Gateway API CRDs. If your Kubernetes provider already manages compatible Gateway API CRDs for the cluster,
use the provider-managed Gateway API CRD install steps
instead.
The default installation of Envoy Gateway installs a default EnvoyGateway configuration and attaches it
using a ConfigMap. In the next step, we will update this resource to enable EnvoyPatchPolicy.
After updating the ConfigMap, you will need to wait the configuration kicks in. You can force the configuration to be reloaded by restarting the envoy-gateway deployment.
Starting from v1.5, Envoy Gateway uses version 2 of the xDS name scheme when generating xDS resources.
Because EnvoyPatchPolicy relies on specific xDS resource names, it’s important to use the correct naming format when authoring a patch policy.
Use EnvoyProxy’s Local Reply Modification feature to return a custom response back to the client when
the status code is 404
Apply the configuration
cat <<EOF | kubectl apply -f -
apiVersion: gateway.envoyproxy.io/v1alpha1
kind: EnvoyPatchPolicy
metadata:
name: custom-response-patch-policy
namespace: default
spec:
targetRef:
group: gateway.networking.k8s.io
kind: Gateway
name: eg
type: JSONPatch
jsonPatches:
- type: "type.googleapis.com/envoy.config.listener.v3.Listener"
# The listener name is of the form <GatewayNamespace>/<GatewayName>/<GatewayListenerName>
name: default/eg/http
operation:
op: add
path: "/default_filter_chain/filters/0/typed_config/local_reply_config"
value:
mappers:
- filter:
status_code_filter:
comparison:
op: EQ
value:
default_value: 404
runtime_key: key_b
status_code: 406
body:
inline_string: "could not find what you are looking for"
EOF
Save and apply the following resource to your cluster:
---apiVersion:gateway.envoyproxy.io/v1alpha1kind:EnvoyPatchPolicymetadata:name:custom-response-patch-policynamespace:defaultspec:targetRef:group:gateway.networking.k8s.iokind:Gatewayname:egtype:JSONPatchjsonPatches:- type:"type.googleapis.com/envoy.config.listener.v3.Listener"# The listener name is of the form <GatewayNamespace>/<GatewayName>/<GatewayListenerName>name:default/eg/httpoperation:op:addpath:"/default_filter_chain/filters/0/typed_config/local_reply_config"value:mappers:- filter:status_code_filter:comparison:op:EQvalue:default_value:404runtime_key:key_bstatus_code:406body:inline_string:"could not find what you are looking for"
When mergeGateways is enabled, there will be one Envoy deployment for all Gateways in the cluster.
Then the EnvoyPatchPolicy should target a specific GatewayClass.
cat <<EOF | kubectl apply -f -
apiVersion: gateway.envoyproxy.io/v1alpha1
kind: EnvoyPatchPolicy
metadata:
name: custom-response-patch-policy
namespace: default
spec:
targetRef:
group: gateway.networking.k8s.io
kind: GatewayClass
name: eg
type: JSONPatch
jsonPatches:
- type: "type.googleapis.com/envoy.config.listener.v3.Listener"
# The listener name is of the form <GatewayNamespace>/<GatewayName>/<GatewayListenerName>
name: default/eg/http
operation:
op: add
path: "/default_filter_chain/filters/0/typed_config/local_reply_config"
value:
mappers:
- filter:
status_code_filter:
comparison:
op: EQ
value:
default_value: 404
runtime_key: key_b
status_code: 406
body:
inline_string: "could not find what you are looking for"
EOF
Save and apply the following resource to your cluster:
---apiVersion:gateway.envoyproxy.io/v1alpha1kind:EnvoyPatchPolicymetadata:name:custom-response-patch-policynamespace:defaultspec:targetRef:group:gateway.networking.k8s.iokind:GatewayClassname:egtype:JSONPatchjsonPatches:- type:"type.googleapis.com/envoy.config.listener.v3.Listener"# The listener name is of the form <GatewayNamespace>/<GatewayName>/<GatewayListenerName>name:default/eg/httpoperation:op:addpath:"/default_filter_chain/filters/0/typed_config/local_reply_config"value:mappers:- filter:status_code_filter:comparison:op:EQvalue:default_value:404runtime_key:key_bstatus_code:406body:inline_string:"could not find what you are looking for"
Edit the HTTPRoute resource from the Quickstart to only match on paths with value /get
$ curl --header "Host: www.example.com" http://$GATEWAY_HOST/find
Handling connection for8888could not find what you are looking for
Customize VirtualHost by name
Use EnvoyProxy’s include_attempt_count_in_response feature to include the attempt count as header in the downstream response.
Apply the configuration
cat <<EOF | kubectl apply -f -
apiVersion: gateway.envoyproxy.io/v1alpha1
kind: EnvoyPatchPolicy
metadata:
name: include-attempts
namespace: default
spec:
targetRef:
group: gateway.networking.k8s.io
kind: Gateway
name: eg
type: JSONPatch
jsonPatches:
- type: "type.googleapis.com/envoy.config.route.v3.RouteConfiguration"
# The RouteConfiguration name is of the form <GatewayNamespace>/<GatewayName>/<GatewayListenerName>
name: default/eg/http
operation:
op: add
# Every virtual_host that ends with 'www_example_com' (using RegEx Filter)
jsonPath: "..virtual_hosts[?match(@.name, '.*www_example_com')]"
# If the property does not exists, it can not be selected with jsonPath
# Therefore the new property must be set in path
path: "include_attempt_count_in_response"
value: true
EOF
Save and apply the following resource to your cluster:
---apiVersion:gateway.envoyproxy.io/v1alpha1kind:EnvoyPatchPolicymetadata:name:include-attemptsnamespace:defaultspec:targetRef:group:gateway.networking.k8s.iokind:Gatewayname:egtype:JSONPatchjsonPatches:- type:"type.googleapis.com/envoy.config.route.v3.RouteConfiguration"# The RouteConfiguration name is of the form <GatewayNamespace>/<GatewayName>/<GatewayListenerName>name:default/eg/httpoperation:op:add# Every virtual_host that ends with 'www_example_com' (using RegEx Filter)jsonPath:"..virtual_hosts[?match(@.name, '.*www_example_com')]"# If the property does not exists, it can not be selected with jsonPath# Therefore the new property must be set in pathpath:"include_attempt_count_in_response"value:true
The Status subresource should have information about the status of the resource. Make sure
Accepted=True and Programmed=True conditions are set to ensure that the policy has been
applied to Envoy Proxy.
apiVersion:gateway.envoyproxy.io/v1alpha1kind:EnvoyPatchPolicymetadata:annotations:kubectl.kubernetes.io/last-applied-configuration:| {"apiVersion":"gateway.envoyproxy.io/v1alpha1","kind":"EnvoyPatchPolicy","metadata":{"annotations":{},"name":"custom-response-patch-policy","namespace":"default"},"spec":{"jsonPatches":[{"name":"default/eg/http","operation":{"op":"add","path":"/default_filter_chain/filters/0/typed_config/local_reply_config","value":{"mappers":[{"body":{"inline_string":"could not find what you are looking for"},"filter":{"status_code_filter":{"comparison":{"op":"EQ","value":{"default_value":404}}}}}]}},"type":"type.googleapis.com/envoy.config.listener.v3.Listener"}],"priority":0,"targetRef":{"group":"gateway.networking.k8s.io","kind":"Gateway","name":"eg","namespace":"default"},"type":"JSONPatch"}}creationTimestamp:"2023-07-31T21:47:53Z"generation:1name:custom-response-patch-policynamespace:defaultresourceVersion:"10265"uid:a35bda6e-a0cc-46d7-a63a-cee765174bc3spec:jsonPatches:- name:default/eg/httpoperation:op:addpath:/default_filter_chain/filters/0/typed_config/local_reply_configvalue:mappers:- body:inline_string:could not find what you are looking forfilter:status_code_filter:comparison:op:EQvalue:default_value:404type:type.googleapis.com/envoy.config.listener.v3.Listenerpriority:0targetRef:group:gateway.networking.k8s.iokind:Gatewayname:egtype:JSONPatchstatus:conditions:- lastTransitionTime:"2023-07-31T21:48:19Z"message:EnvoyPatchPolicy has been accepted.observedGeneration:1reason:Acceptedstatus:"True"type:Accepted- lastTransitionTime:"2023-07-31T21:48:19Z"message:successfully applied patches.reason:Programmedstatus:"True"type:Programmed
Offline
You can use egctl x translate to validate the translated xds output.
Caveats
This API will always be an unstable API and the same outcome cannot be guaranteed
across versions for these reasons
The Envoy Proxy API might deprecate and remove API fields
Envoy Gateway might alter the xDS translation creating a different xDS output
such as changing the name field of resources.
4 - Envoy Gateway Extension Server
This task explains how to extend Envoy Gateway using an Extension Server. Envoy Gateway
can be configured to call an external server over gRPC with the xDS configuration before
it is sent to Envoy Proxy. The external server can modify the provided configuration
programmatically using any semantics supported by the xDS API.
Using an extension server allows vendors to add xDS configuration that Envoy Gateway itself
doesn’t support with a very high level of control over the generated xDS configuration.
Note: Modifying the xDS configuration generated by Envoy Gateway may break functionality
configured by native Envoy Gateway means. Like other cases where the xDS configuration
is modified outside of Envoy Gateway’s control, this is risky and should be tested thoroughly,
especially when using the same extension server across different Envoy Gateway versions.
Introduction
One of the Envoy Gateway project goals is to “provide a common foundation for vendors to
build value-added products without having to re-engineer fundamental interactions”. The
Envoy Gateway Extension Server provides a mechanism where Envoy Gateway tracks all provider
resources and then calls a set of hooks that allow the generated xDS configuration to be
modified before it is sent to Envoy Proxy. See the design documentation for full details.
Security Warning
Security Warning
Enabling an Extension Server may lead to complete security compromise of your system.
Users that control the Extension Server can inject arbitrary configuration to proxies,
leading to high Confidentiality, Integrity and Availability risks.
Injected configuration may include arbitrary code executed by the proxy without any isolation. Such code may be used
to launch SSRF attacks, as well as allow users to gain access to proxy credentials as described in CVE-2026-22771.
With such access, users can fetch the complete proxy configuration, including secrets and cluster network topology.
When enabling Extension Server, additional security measures should be taken by admins to reduce security risks, including:
Using K8s RBAC to restrict access to the Envoy Gateway Configuration as well as the Extension Server deployment.
Disabling envoy extensions which are not needed with envoy command line options.
Implementing Kubernetes network policies that restrict traffic from the proxy pod only to relevant targets.
Extension Hooks Overview
Envoy Gateway provides several extension hooks that are called at different stages of the xDS translation process. These hooks allow extensions to modify various aspects of the generated xDS configuration:
Available Hooks
Hook Type
Hook Method Name
Purpose
Resources Modified
Execution Context
Route
PostRouteModifyHook
Modify individual routes
Single envoy.config.route.v3.Route
Per-route, only for routes with extension filters
Cluster
PostClusterModifyHook
Modify clusters for custom backends
Single envoy.config.cluster.v3.Cluster
Per-cluster, only for custom backend clusters
VirtualHost
PostVirtualHostModifyHook
Modify virtual hosts and add custom routes
Single envoy.config.route.v3.VirtualHost
Per-virtual-host
HTTPListener
PostHTTPListenerModifyHook
Modify HTTP listeners
Single envoy.config.listener.v3.Listener
Per-listener
Translation
PostTranslateModifyHook
Global modification of all xDS resources
All clusters, secrets, listeners, and routes
Once per translation cycle
Hook Execution Order
The hooks are executed in the following order during xDS translation:
Route Processing Phase
Route hook (PostRouteModifyHook): Called for each route that has extension filters attached
Cluster hook (PostClusterModifyHook): Called for each cluster generated from custom backend references
Virtual Host Processing Phase
VirtualHost hook (PostVirtualHostModifyHook): Called for each virtual host after all routes are processed
Listener Processing Phase
HTTPListener hook (PostHTTPListenerModifyHook): Called for each HTTP listener after virtual hosts are configured
Final Translation Phase
Translation hook (PostTranslateModifyHook): Called once with all generated clusters, secrets, listeners, and routes
Hook Details
Route Hook (PostRouteModifyHook)
When called: After each individual route is generated from an HTTPRoute with extension filters
Input: Single route, hostnames, and extension resources from the HTTPRoute
Use cases: Add virtual host-level configuration, inject additional routes
HTTPListener Hook (PostHTTPListenerModifyHook)
When called: After listener is fully configured with all virtual hosts
Input: Complete HTTP listener and associated extension policies
Output: Modified listener
Use cases: Add listener filters, modify listener configuration, add authentication
Translation Hook (PostTranslateModifyHook)
When called: After all individual resources are generated and processed
Input: All clusters, secrets, listeners, and routes, plus extension policies
Output: Complete set of modified resources
Use cases: Global resource injection, cross-resource modifications, cleanup operations
Configuration
Extensions must specify which hooks they want to use in the extensionManager.hooks configuration:
extensionManager:hooks:xdsTranslator:post:- Route # Enable route modification hook- VirtualHost # Enable virtual host modification hook- HTTPListener # Enable HTTP listener modification hook- Cluster # Enable cluster modification hook- Translation # Enable global translation hook# Configure which resources to include in PostTranslateModifyHook# Default: true for clusters and secrets (for backward compatibility)# Default: false for listeners and routes (for backward compatibility)translation:listener:includeAll:trueroute:includeAll:true
This task sets up an example extension server that adds the Envoy Proxy Basic Authentication
HTTP filter to all the listeners generated by Envoy Gateway. The example extension server
includes its own CRD which allows defining username/password pairs that will be accepted by
the Envoy Proxy.
Note: Envoy Gateway supports adding Basic Authentication to routes using a SecurityPolicy.
See this task for the preferred way to configure Basic
Authentication.
Quickstart
Prerequisites
Follow the steps below to install Envoy Gateway and the example manifest. Before
proceeding, you should be able to query the example backend using HTTP.
Expand for instructions
Install the Gateway API CRDs and Envoy Gateway using Helm:
Gateway API CRD compatibility
This command installs Gateway API CRDs. If your Kubernetes provider already manages compatible Gateway API CRDs for the cluster,
use the provider-managed Gateway API CRD install steps
instead.
The above command should succeed with status code 200.
Build and run the example Extension Server
Build and deploy the example extension server in the examples/extension-server folder into the cluster
running Envoy Gateway.
Build the extension server image
Note: The provided Makefile builds an image with the name extension-server:latest. You may need to create
a different tag for it in order to allow Kubernetes to pull it correctly.
make image
Publish the extension server image in your docker repository
Configure Envoy Gateway to use the Extension Server
Add the following fragment to Envoy Gateway’s configmap:
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: ConfigMap
metadata:
name: envoy-gateway-config
namespace: envoy-gateway-system
data:
envoy-gateway.yaml: |
apiVersion: gateway.envoyproxy.io/v1alpha1
kind: EnvoyGateway
provider:
type: Kubernetes
gateway:
controllerName: gateway.envoyproxy.io/gatewayclass-controller
extensionManager:
# Envoy Gateway will watch these resource kinds and use them as extension policies
# which can be attached to Gateway resources.
policyResources:
- group: example.extensions.io
version: v1alpha1
kind: ListenerContextExample
hooks:
# The type of hooks that should be invoked
xdsTranslator:
post:
- HTTPListener
service:
# The service that is hosting the extension server
fqdn:
hostname: extension-server.envoy-gateway-system.svc.cluster.local
port: 5005
EOF
After updating Envoy Gateway’s configmap, restart Envoy Gateway.
Multiple extension servers
Envoy Gateway also supports chaining multiple extension servers. Use the
extensionManagers field (plural) instead of extensionManager:
A few nuances apply when multiple extension managers are configured:
Sequential chaining. Hooks are invoked in the order the servers are
declared. Each server sees the output of the previous one, so mutations
compose.
Resource isolation. Each server only receives the extension resources
whose GVK it declares under resources, policyResources, or
backendResources. In the example above a FooFilter is sent to ext-a
but not to ext-b.
failOpen is per server. Setting failOpen: true on a server causes
Envoy Gateway to skip that server in the chain when its hook returns an
error (or when its gRPC connection cannot be established), while still
invoking the remaining servers.
Unique name required. Every entry in extensionManagers must have a
distinct name. Names surface in error messages as
extension "<name>": <error>.
Mutually exclusive with the singular form.extensionManager and
extensionManagers cannot both be set.
Testing
Get the Gateway’s address:
exportGATEWAY_HOST=$(kubectl get gateway/eg -o jsonpath='{.status.addresses[0].value}')
The extension server adds the Basic Authentication HTTP filter to all listeners configured by
Envoy Gateway. Initially there are no valid user/password combinations available. Accessing the
example backend should fail with a 401 status:
$ curl -v --header "Host: www.example.com""http://${GATEWAY_HOST}/example"...
> GET /example HTTP/1.1
> Host: www.example.com
> User-Agent: curl/7.81.0
> Accept: */*
>* Mark bundle as not supporting multiuse
< HTTP/1.1 401 Unauthorized
< www-authenticate: Basic realm="http://www.example.com/example"
< content-length: 58
< content-type: text/plain
< date: Mon, 08 Jul 2024 10:53:11 GMT
<
...
User authentication failed. Missing username and password.
...
Add a new Username/Password combination using the example extension server’s CRD:
This task provides instructions for configuring external processing.
External processing calls an external gRPC service to process HTTP requests and responses.
The external processing service can inspect and mutate requests and responses.
Envoy Gateway introduces a new CRD called EnvoyExtensionPolicy that allows the user to configure external processing.
This instantiated resource can be linked to a Gateway and HTTPRoute resource.
Prerequisites
Follow the steps below to install Envoy Gateway and the example manifest. Before
proceeding, you should be able to query the example backend using HTTP.
Expand for instructions
Install the Gateway API CRDs and Envoy Gateway using Helm:
Gateway API CRD compatibility
This command installs Gateway API CRDs. If your Kubernetes provider already manages compatible Gateway API CRDs for the cluster,
use the provider-managed Gateway API CRD install steps
instead.
Create a new EnvoyExtensionPolicy resource to configure the external processing service. This EnvoyExtensionPolicy targets the HTTPRoute
“myApp” created in the previous step. It calls the GRPC external processing service “grpc-ext-proc” on port 9002 for
processing.
By default, requests and responses are not sent to the external processor. The processingMode struct is used to define what should be sent to the external processor.
In this example, we configure the following processing modes:
The empty request field configures envoy to send request headers to the external processor.
The response field includes configuration for body processing. As a result, response headers are sent to the external processor. Additionally, the response body is streamed to the external processor.
kubectl get envoyextensionpolicy/ext-proc-example -o yaml
Because the gRPC external processing service is enabled with TLS, a BackendTLSPolicy needs to be created to configure
the communication between the Envoy proxy and the gRPC auth service.
Checkout the Developer Guide to get involved in the project.
6 - Lua Extensions
This task provides instructions for extending Envoy Gateway with Lua extensions.
Lua extensions allow you to extend the functionality of Envoy Gateway by running custom code against HTTP requests and responses,
without modifying the Envoy Gateway binary. These comparatively light-weight extensions are written in the Lua scripting language using APIs defined here.
Envoy Gateway allows the user to configure Lua extensions using the EnvoyExtensionPolicy CRD.
This instantiated resource can be linked to a Gateway or HTTPRoute resource. If linked to both, the resource linked to the route takes precedence over those linked to Gateway.
Warning
Lua scripts execute inside the Envoy proxy process without strong sandboxing. While Envoy Gateway
sanitizes scripts and restricts the available Lua API surface, the Lua runtime is inherently less
isolated than a dedicated extension process.
When enabling Lua extensions, admins should take additional measures to reduce risk, including:
Using K8s RBAC to restrict who can create or modify EnvoyExtensionPolicy resources with Lua scripts.
Using AdmissionControl tools (e.g. OPA Gatekeeper, Kyverno) to validate and review Lua scripts before they are admitted.
Auditing EnvoyExtensionPolicy resources periodically, and enabling AuditLog for API server operations on these resources.
Not enabling Lua when it is not needed by omitting the enableLua field or setting it to false in the EnvoyGateway configuration.
Enable Lua
Lua extensions are disabled by default. To enable Lua, set enableLua: true in the EnvoyGateway configuration:
Follow the steps below to install Envoy Gateway and the example manifest. Before
proceeding, you should be able to query the example backend using HTTP.
Expand for instructions
Install the Gateway API CRDs and Envoy Gateway using Helm:
Gateway API CRD compatibility
This command installs Gateway API CRDs. If your Kubernetes provider already manages compatible Gateway API CRDs for the cluster,
use the provider-managed Gateway API CRD install steps
instead.
Inline Lua: The extension defines the Lua script as an inline string.
ValueRef Lua: The extension points to an in-cluster ConfigMap resource that contains the Lua script in it’s data.
The following example demonstrates how to configure an EnvoyExtensionPolicy to attach a Lua extension to a HTTPRoute.
This Lua extension adds a custom header x-lua-custom: FOO to the response.
Lua Extension - Inline
This EnvoyExtensionPolicy configuration defines the Lua script as an inline string.
Save and apply the following resource to your cluster:
---apiVersion:gateway.envoyproxy.io/v1alpha1kind:EnvoyExtensionPolicymetadata:name:lua-inline-testspec:targetRefs:- group:gateway.networking.k8s.iokind:HTTPRoutename:backendlua:- type:Inlineinline:| function envoy_on_response(response_handle)
response_handle:headers():add("x-lua-custom", "FOO")
end
Verify the EnvoyExtensionPolicy status:
kubectl get envoyextensionpolicy/lua-inline-test -o yaml
Lua Extension - ValueRef
This EnvoyExtensionPolicy configuration defines the Lua extension in a ConfigMap resource.
Save and apply the following resources to your cluster:
---apiVersion:gateway.envoyproxy.io/v1alpha1kind:EnvoyExtensionPolicymetadata:name:lua-valueref-testspec:targetRefs:- group:gateway.networking.k8s.iokind:HTTPRoutename:backendlua:- type:ValueRefvalueRef:name:cm-lua-valuerefkind:ConfigMapgroup:v1---apiVersion:v1kind:ConfigMapmetadata:name:cm-lua-valuerefdata:lua:| function envoy_on_response(response_handle)
response_handle:headers():add("x-lua-custom", "FOO")
end
Verify the EnvoyExtensionPolicy status:
kubectl get envoyextensionpolicy/lua-valueref-test -o yaml
Lua Extension - FilterContext
The filterContext field allows you to pass key/value pairs to a shared Lua script, so it can be parameterized differently per route.
The Lua script accesses these values via the filterContext() stream handle API.
This example uses a shared ConfigMap Lua script that reads a configurable header name from filter context and copies its value to the authorization header.
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: ConfigMap
metadata:
name: cm-lua-shared-auth
data:
lua: |
function envoy_on_request(request_handle)
local ctx = request_handle:filterContext()
local token = request_handle:headers():get(ctx:get("token_header"))
if token and token ~= "" then
request_handle:headers():replace("authorization", "Bearer " .. token)
end
end
---
apiVersion: gateway.envoyproxy.io/v1alpha1
kind: EnvoyExtensionPolicy
metadata:
name: lua-filter-context-test
spec:
targetRefs:
- group: gateway.networking.k8s.io
kind: HTTPRoute
name: backend
lua:
- type: ValueRef
valueRef:
name: cm-lua-shared-auth
kind: ConfigMap
group: v1
filterContext:
token_header: x-api-key
EOF
Save and apply the following resources to your cluster:
---apiVersion:v1kind:ConfigMapmetadata:name:cm-lua-shared-authdata:lua:| function envoy_on_request(request_handle)
local ctx = request_handle:filterContext()
local token = request_handle:headers():get(ctx:get("token_header"))
if token and token ~= "" then
request_handle:headers():replace("authorization", "Bearer " .. token)
end
end---apiVersion:gateway.envoyproxy.io/v1alpha1kind:EnvoyExtensionPolicymetadata:name:lua-filter-context-testspec:targetRefs:- group:gateway.networking.k8s.iokind:HTTPRoutename:backendlua:- type:ValueRefvalueRef:name:cm-lua-shared-authkind:ConfigMapgroup:v1filterContext:token_header:x-api-key
A different route can reuse the same ConfigMap with different filter context values:
Checkout the Developer Guide to get involved in the project.
7 - OPA Sidecar with Unix Domain Socket
This task demonstrates how to deploy an Open Policy Agent (OPA) sidecar inside Envoy Proxy pods created by Envoy Gateway, with Envoy Proxy communicating with OPA over a Unix Domain Socket.
The setup provides these advantages over running OPA as its own Kubernetes service:
Using a sidecar ensures that the OPA is always on the same worker node as Envoy Proxy. This reduces latency and simplifies access control.
Using a Unix Domain Socket avoids TCP/TLS overhead while improving security by avoiding network exposure and reduces latency.
This production-ready approach uses Envoy Gateway’s extension APIs to configure Envoy Proxy’s external authorization and standard Kubernetes API objects to configure OPA’s Envoy External Authorization gRPC plugin.
Note: In this diagram, the Unix Domain Socket is shown outside of the Proxy and OPA containers, but it is actually mounted to both containers.
The example flow on this page will use Envoy to authenticate JWTs and OPA to validate the ISS claim on the JWT. If the ISS matches a configured env var value then requests will be allowed.
Note that the OPA sidecar with Unix Domain Sockets pattern does not require that JWTs be used. Also, simple ISS claim validation could be done more easily using the “authentication” property of the SecurityPolicy spec, but using OPA allows for more complex logic to be applied. See JWT Claim-Based Authorization to see how to use the SecurityPolicy “authentication” property.
Prerequisites
Follow the steps below to install Envoy Gateway and the example manifest. Before
proceeding, you should be able to query the example backend using HTTP.
Expand for instructions
Install the Gateway API CRDs and Envoy Gateway using Helm:
Gateway API CRD compatibility
This command installs Gateway API CRDs. If your Kubernetes provider already manages compatible Gateway API CRDs for the cluster,
use the provider-managed Gateway API CRD install steps
instead.
The above command should succeed with status code 200.
Steps overview
Enable the Backend extension API so Envoy can reference a Unix Domain Socket.
Create an OPA policy in a ConfigMap and mount it into an OPA sidecar in the Envoy pods.
Configure the Envoy Proxy pods to have an OPA sidecar
Configure a SecurityPolicy that delegates authorization to OPA via the Unix Domain Socket Backend. For demonstration purposes we’ll also configure JWT authentication.
Create an HTTPRoute that requires protection
Test the configuration
Step 1: Enable the Backend extension API
Enable the Backend API in your Envoy Gateway ConfigMap to allow Envoy to reference Unix Domain Sockets by setting the “enableBackend” property to “true” in the “envoy-gateway-config” ConfigMap:
OLD_CONFIG=$(kubectl get cm envoy-gateway-config -n envoy-gateway-system -o jsonpath='{.data.envoy-gateway\.yaml}')NEW_CONFIG=$(echo"$OLD_CONFIG"| sed "s/extensionApis: {}/extensionApis:\n enableBackend: true/")kubectl create configmap envoy-gateway-config -n envoy-gateway-system \
--from-literal=envoy-gateway.yaml="$NEW_CONFIG"\
--dry-run=client -o yaml | kubectl apply -f -
Ignore the kubectl warning. It happens because kubectl apply expects a “receipt” (the last-applied-configuration annotation) to be present on the resource so it can track changes over time. If the ConfigMap was originally created using kubectl create (without --save-config) or by a Helm chart, that receipt is missing. kubectl is simply telling you that it’s adding that receipt now.
Restart the Envoy Gateway deployment to apply the updated configuration:
The Envoy Proxy pod will be restarted later in this guide.
Step 2: Create the OPA policy
Create a ConfigMap with a Rego policy that OPA will load. This example reads the “ALLOWED_ISS” environment variable and compares it to the JWT ISS claim, allowing the request only if they match.
On MacOS you can apply that by copying it and running pbpaste | kubectl apply -f -.
In this policy we extract a x-jwt-iss header from the request. That header is not automatically available on ext_authz filter requests. We will configure Envoy to add that header from the decoded JWT. That configuration happens in the SecurityPolicy in step 4.
Step 3: Configure the Envoy Proxy pods to have an OPA sidecar
Create an EnvoyProxy resource that mounts the OPA policy ConfigMap, shares a Unix Domain Socket between Envoy and OPA, and configures the “ext_authz” filter order so OPA receives JWT headers from the JWT authentication filter.
apiVersion:gateway.envoyproxy.io/v1alpha1kind:EnvoyProxymetadata:name:egnamespace:envoy-gateway-systemspec:# Ensure ext_authz runs after jwt_authn so that OPA sees the JWT-derived headers# configured in the SecurityPolicy in step 4filterOrder:- name:envoy.filters.http.ext_authzafter:envoy.filters.http.jwt_authnprovider:type:Kuberneteskubernetes:envoyDeployment:patch:type:StrategicMergevalue:spec:template:spec:volumes:# Shared Unix Domain Socket volume for communication between Envoy# and OPA. This will be mounted in both containers.- name:opa-unix-socketemptyDir:{}# OPA Rego policy file from ConfigMap. This will be mounted# in the OPA container.- name:opa-policyconfigMap:name:opa-policycontainers:# Add the Unix Domain Socket volume to the existing envoy# proxy container named "envoy".- name:envoyvolumeMounts:# Mount the Unix Domain Socket volume in the Envoy container- name:opa-unix-socketmountPath:/shared/opa# Create the OPA sidecar container- name:opa# OPA image tag format:# - "x.y.z": OPA version# - "envoy": includes OPA's Envoy External Authorization gRPC plugin# - "5": plugin version# - "static": static build (no glibc dependency, smaller image)image:openpolicyagent/opa:1.10.1-envoy-5-staticargs:- "run"- "--server"# In addition to listening on the Unix Domain Socket, we'll listen# on port 8181 for k8s probes- "--addr=0.0.0.0:8181"# Configure OPA's Envoy external authorization plugin to listen on a Unix Domain Socket- "--set=plugins.envoy_ext_authz_grpc.addr=unix:///shared/opa/opa.sock"# In the OPA policy we defined the policy as being in a# "envoy.authz" package and set the "allow" variable# based on the policy decision. Here we tell the plugin# to check that value.- "--set=plugins.envoy_ext_authz_grpc.query=data.envoy.authz.allow"- "--ignore=.*"# You can set log-level to "debug" for detailed request logging- "--log-level=error"# Tell OPA where to find the policy file- "/policy/policy.rego"env:# Environment variable used by the OPA policy to validate the JWT issuer- name:ALLOWED_ISSvalue:"https://example.com"ports:# Port for health checks only; gRPC server listens on the Unix Domain Socket- name:httpcontainerPort:8181protocol:TCPvolumeMounts:# Mount the Unix Domain Socket volume in the OPA container- name:opa-unix-socketmountPath:/shared/opa# Mount the OPA Rego policy from ConfigMap- name:opa-policymountPath:/policyreadOnly:truelivenessProbe:httpGet:path:/healthport:8181initialDelaySeconds:5periodSeconds:10timeoutSeconds:3failureThreshold:3readinessProbe:httpGet:path:/health?bundle=trueport:8181initialDelaySeconds:5periodSeconds:5timeoutSeconds:3failureThreshold:3securityContext:# Use the same user ID as the Envoy container (65532) so both containers can access the socket# The user ID was found by running "docker pull docker.io/envoyproxy/gateway:v<version> && docker inspect docker.io/envoyproxy/gateway:v<version>"runAsUser:65532allowPrivilegeEscalation:falseresources:# Adjust as necessaryrequests:cpu:100mmemory:128Milimits:memory:512Mi
This patch adds an OPA sidecar container to the Envoy pods, creates a shared Unix Domain Socket at /shared/opa/opa.sock, and configures OPA to listen only on this socket instead of TCP. It sets an ALLOWED_ISS property that OPA will use to validate the request. We purposefully set the wrong value here so we can see the response when the wrong ISS is used. We’ll set it to the correct value later.
Tell Envoy Gateway to use this EnvoyProxy spec by patching the GatewayClass.
This will cause the Envoy Proxy pod to be replaced with the new config.
Step 4: Connect Envoy to OPA with a SecurityPolicy and Backend
Create a Unix Domain Socket SecurityPolicy and a Backend that authenticates JWTs, maps the ISS claims to the x-jwt-iss header, and delegates authorization to OPA.
apiVersion:gateway.envoyproxy.io/v1alpha1kind:SecurityPolicymetadata:name:opa-jwt-authz# The SecurityPolicy must be in the same namespace as the HTTPRoutes that it# will apply tonamespace:defaultspec:targetSelectors:- group:gateway.networking.k8s.iokind:HTTPRoutematchLabels:auth:opa-jwtjwt:providers:- name:my-jwt-validator# Verify that the JWT is signed with the correct keyremoteJWKS:uri:https://raw.githubusercontent.com/envoyproxy/gateway/refs/heads/main/examples/kubernetes/jwt/jwks.json# Add the JWT ISS claim to request to the headers sent to OPA. Note: this only works# for string claims, not arrays. For example, the "aud" claim cannot be passed# this way because the JWT spec defines it as an array.claimToHeaders:- header:x-jwt-issclaim:iss# Delegate authorization to an external program after JWT verificationextAuth:grpc:backendRefs:# Reference the OPA Unix Domain Socket backend, which is the next API object in this code block- group:gateway.envoyproxy.iokind:Backendname:opa-unix-socket# Headers to send to OPA for authorization decisions. This should match the# "claimToHeaders" values above.headersToExtAuth:- x-jwt-iss---apiVersion:gateway.envoyproxy.io/v1alpha1kind:Backendmetadata:name:opa-unix-socket# The Backend must be in the same namespace as the SecurityPolicynamespace:defaultspec:endpoints:# This configures Envoy proxy to send external auth requests to the Unix Domain Socket- unix:path:/shared/opa/opa.sock
Step 5: Configure route to use the OPA authorization
Attach the policy by labeling routes that require authorization. This HTTPRoute uses the backend service installed in the Quick Start:
exportGATEWAY_HOST=$(kubectl get gateway/eg -o jsonpath='{.status.addresses[0].value}')exportENVOY_SERVICE=$(kubectl get svc -n envoy-gateway-system --selector=gateway.envoyproxy.io/owning-gateway-namespace=default,gateway.envoyproxy.io/owning-gateway-name=eg -o jsonpath='{.items[0].metadata.name}')exportVALID_TOKEN="eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6ImI1MjBiM2MyYzRiZDc1YTEwZTljZWJjOTU3NjkzM2RjIn0.eyJpc3MiOiJodHRwczovL2Zvby5iYXIuY29tIiwic3ViIjoiMTIzNDU2Nzg5MCIsInVzZXIiOnsibmFtZSI6IkpvaG4gRG9lIiwiZW1haWwiOiJqb2huLmRvZUBleGFtcGxlLmNvbSIsInJvbGVzIjpbImFkbWluIiwiZWRpdG9yIl19LCJwcmVtaXVtX3VzZXIiOnRydWUsImlhdCI6MTUxNjIzOTAyMiwic2NvcGUiOiJyZWFkIGFkZCBkZWxldGUgbW9kaWZ5In0.P36iAlmiRCC79OiB3vstF5Q_9OqUYAMGF3a3H492GlojbV6DcuOz8YIEYGsRSWc-BNJaBKlyvUKsKsGVPtYbbF8ajwZTs64wyO-zhd2R8riPkg_HsW7iwGswV12f5iVRpfQ4AG2owmdOToIaoch0aym89He1ZzEjcShr9olgqlAbbmhnk-namd1rP-xpzPnWhhIVI3mCz5hYYgDTMcM7qbokM5FzFttTRXAn5_Luor23U1062Ct_K53QArwxBvwJ-QYiqcBycHf-hh6sMx_941cUswrZucCpa-EwA3piATf9PKAyeeWHfHV9X-y8ipGOFg3mYMMVBuUZ1lBkJCik9f9kboRY6QzpOISARQj9PKMXfxZdIPNuGmA7msSNAXQgqkvbx04jMwb9U7eCEdGZztH4C8LhlRjgj0ZdD7eNbRjeH2F6zrWyMUpGWaWyq6rMuP98W2DWM5ZflK6qvT1c7FuFsWPvWLkgxQwTWQKrHdKwdbsu32Sj8VtUBJ0-ddEb"
If Envoy is not running behind a load balancer, then you’ll have to start port forwarding whenever the Envoy Proxy pod is reconfigured and the proxy pods are replaced:
Test with a valid JWT that has the wrong ISS claim
Earlier, we configured the “ALLOWED_ISS” env var on the proxy pods to be “https://example.com”, but the JWT in the “VALID_TOKEN” env var has an ISS claim of “https://foo.bar.com”.
This task explains how to configure Envoy Gateway to defer Envoy proxy and rate
limit infrastructure management to a remote service of your own. With the Remote
infrastructure provider, Envoy Gateway translates Gateway API resources into its
into an infrastructure IR format and forwards it over gRPC to a provider you
operate. The provider is then responsible for reconciling the data plane.
This is the right choice when the built-in Kubernetes infrastructure provider
doesn’t fit your environment. Common cases include running proxies in a
different cluster from the control plane, deploying onto a non-Kubernetes
substrate (VMs, an internal scheduler, etc.), or imposing custom organizational
rules on how proxy workloads are shaped.
Note: Most users should use the built-in Kubernetes infrastructure provider.
The Remote provider is an extension point; running it means owning the lifecycle
of every proxy and rate limit deployment yourself.
Security Warning
Security Warning
The remote infrastructure
provider is a privileged component. It receives the complete Infrastructure IR
for every Gateway managed by Envoy Gateway and is trusted to faithfully
reconcile it. A compromised or misconfigured provider can stop creating proxies,
deploy proxies with attacker-controlled configuration, or expose the data plane
to networks it shouldn’t reach.
When deploying a remote infrastructure provider, you should:
Run the provider as a sidecar of envoy-gateway, or otherwise on a private
channel that is not reachable from untrusted networks. The reference
deployment uses a Unix domain socket on a shared volume.
Restrict the provider’s permissions to the minimum needed to manage the proxy
data plane.
Audit the provider on the same cadence as Envoy Gateway itself; bumping Envoy
Gateway may change the IR shape.
How it works
When the Remote provider is enabled, Envoy Gateway defers infrastructure
management using an gRPC client to send updates to your provider. For every
reconcile that mutates a proxy or rate limit deployment, Envoy Gateway issues a
corresponding RPC carrying the IR as structured protobuf data.
The service contract is defined in proto/remoteinfra/service.proto:
The proxy RPCs carry the IR as a structured Infra message that mirrors
internal/ir/infra.go, including proxy metadata (labels, annotations, and the
owner reference) and each metric sink’s destination (endpoints and upstream
TLS). Most fields are typed protobuf fields; the proxy config (an EnvoyProxy
resource) is the only field carried as JSON-encoded bytes, because that CRD
schema is large and evolves independently of this contract. The rate limit RPCs
are parameterless. The provider is expected to be idempotent — Envoy Gateway
calls the CreateOrUpdate RPCs every time the desired state changes and may
retry on transient errors.
Configuration
The Remote provider is selected under provider.custom.infrastructure in the
EnvoyGateway config. The service field is required and uses the standard
[ExtensionService] shape, so you can reach the provider over a Unix socket, a
hostname, or an IP.
When TLS is configured, Envoy Gateway verifies the server certificate against
the CA in the referenced Secret. Add clientCertificateRef if your provider
requires mTLS.
Rate limit service address
The Remote provider tells Envoy Gateway what rate limit infrastructure to
stand up via the CreateOrUpdateRateLimitInfra RPC, but Envoy proxies still
need to know where to send rate limit checks. Set rateLimit.url on the
EnvoyGateway config to the address your provider exposes. The value must be a
grpc:// URL with an explicit host and port:
If rateLimit.url is unset, Envoy Gateway falls back to the address of the
Service the Kubernetes infrastructure manager would have created.
Quickstart
This walks through deploying the example provider in examples/remote-infra as
a native sidecar of the envoy-gateway Deployment, communicating over a Unix
domain socket. The example provider reconciles a Deployment and a Service
per Gateway and is intended as a starting point — not a production-ready
provider.
Prerequisites
Follow the steps below to install Envoy Gateway and the example manifest. Before
proceeding, you should be able to query the example backend using HTTP.
Expand for instructions
Install the Gateway API CRDs and Envoy Gateway using Helm:
Gateway API CRD compatibility
This command installs Gateway API CRDs. If your Kubernetes provider already manages compatible Gateway API CRDs for the cluster,
use the provider-managed Gateway API CRD install steps
instead.
The above command should succeed with status code 200.
Build and load the example provider image
The example lives in examples/remote-infra/ and ships with a Makefile target
that builds a multi-arch image tagged envoyproxy/gateway-remote-infra:latest.
make -C examples/remote-infra docker-buildx
If you’re running on kind, load the image into the cluster so the sidecar can
pull it:
The provider needs to share a volume with envoy-gateway so they can talk over
a UDS, and it needs to start before envoy-gateway does. Native sidecars give
us both for free on Kubernetes 1.29+.
cat <<'EOF' | kubectl patch deployment envoy-gateway -n envoy-gateway-system --patch-file /dev/stdin
apiVersion: apps/v1
kind: Deployment
metadata:
name: envoy-gateway
namespace: envoy-gateway-system
spec:
template:
spec:
securityContext:
runAsNonRoot: true
runAsUser: 65532
runAsGroup: 65532
# fsGroup ensures the shared emptyDir is group-owned by 65532 so the
# non-root sidecar can create the UDS socket file in it.
fsGroup: 65532
volumes:
- name: remote-infra-socket
emptyDir: {}
containers:
- name: envoy-gateway
volumeMounts:
- name: remote-infra-socket
mountPath: /var/run/remote-infra
initContainers:
- name: remote-infra
image: envoyproxy/gateway-remote-infra:latest
imagePullPolicy: IfNotPresent
restartPolicy: Always
args:
- --socket-path=/var/run/remote-infra/server.sock
env:
- name: NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
# Gates startup of envoy-gateway: it will not start until the UDS
# socket exists.
startupProbe:
exec:
command: ["test", "-S", "/var/run/remote-infra/server.sock"]
periodSeconds: 1
failureThreshold: 30
volumeMounts:
- name: remote-infra-socket
mountPath: /var/run/remote-infra
EOF
Switch Envoy Gateway to the Remote provider
Patch the envoy-gateway-config ConfigMap to dial the sidecar over the shared
socket:
You should see Creating proxy infra [...] lines as Gateways are reconciled.
The example provider creates a Deployment and Service for each Gateway in
the same namespace as Envoy Gateway; check them with:
kubectl get deploy,svc -n envoy-gateway-system -l app.kubernetes.io/managed-by=envoy-gateway
Writing your own provider
The example in examples/remote-infra/ is a useful starting point but only
renders a Deployment and a Service. A production-grade provider will
typically need to:
Be idempotent. Envoy Gateway calls CreateOrUpdate whenever the IR
changes, which in practice can be many times per second during churn. The
example uses a server-side apply pattern; you should do the same or its
equivalent for your data plane.
Plan for IR evolution. The IR is JSON for forward-compatibility, but new
fields will be added as Envoy Gateway evolves. Design your provider to ignore
unknown fields rather than fail on them.
Communicate data plane status. Envoy Gateway needs metadata about your
data plane, such as the DNS address to find the fleet at. Make sure your
provider communicates that information back via a Service object. The example
infra server provides a basic example.
The IR types are defined in internal/ir/. The ir.Infra value Envoy Gateway
sends is documented by the Go types ir.ProxyInfra and ir.RateLimitInfra.
9 - Wasm Extensions
This task provides instructions for extending Envoy Gateway with WebAssembly (Wasm) extensions.
Wasm extensions allow you to extend the functionality of Envoy Gateway by running custom code against HTTP requests and responses,
without modifying the Envoy Gateway binary. These extensions can be written in any language that compiles to Wasm, such as C++, Rust, AssemblyScript, or TinyGo.
Envoy Gateway introduces a new CRD called EnvoyExtensionPolicy that allows the user to configure Wasm extensions.
This instantiated resource can be linked to a Gateway and HTTPRoute resource.
Prerequisites
Follow the steps below to install Envoy Gateway and the example manifest. Before
proceeding, you should be able to query the example backend using HTTP.
Expand for instructions
Install the Gateway API CRDs and Envoy Gateway using Helm:
Gateway API CRD compatibility
This command installs Gateway API CRDs. If your Kubernetes provider already manages compatible Gateway API CRDs for the cluster,
use the provider-managed Gateway API CRD install steps
instead.
The above command should succeed with status code 200.
Configuration
Envoy Gateway supports two types of Wasm extensions:
HTTP Wasm Extension: The Wasm extension is fetched from a remote URL.
Image Wasm Extension: The Wasm extension is packaged as an OCI image and fetched from an image registry.
The following example demonstrates how to configure an EnvoyExtensionPolicy to attach a Wasm extension to an EnvoyExtensionPolicy .
This Wasm extension adds a custom header x-wasm-custom: FOO to the response.
HTTP Wasm Extension
This EnvoyExtensionPolicy configuration fetches the Wasm extension from an HTTP URL.