Leveraging EnvoyPatchPolicy to Extend the Capabilities of Envoy Gateway

Learn how to use EnvoyPatchPolicy to dynamically modify xDS resources in Envoy Gateway, including practical examples such as customizing local replies. Based on Envoy Gateway v1.3.2.

Copyright
This is an original article by Jimmy Song. You may repost it, but please credit this source: https://jimmysong.io/en/blog/leveraging-envoypatchpolicy-to-extend-the-capabilities-of-envoy-gateway/
Click to show the outline

Note: This blog is based on Envoy Gateway v1.3.2.

Envoy Gateway offers a rich set of functionalities built on top of Envoy Proxy. However, there may be instances where you need to leverage Envoy Proxy’s features that are not exposed in the Envoy Gateway API. Enter the EnvoyPatchPolicy API, introduced since Envoy Gateway v0.5.0, which allows you to customize xDS resources generated by Envoy Gateway. This blog will guide you through enabling the API and implementing a fascinating feature – local reply modification inspired by Envoy Proxy.

We’ll start by outlining the prerequisites before diving into the details of EnvoyPatchPolicy. Then we’ll walk you through enabling the API, customizing response rules, and testing your implementation.

Remember that the API might remain unstable across versions due to potential changes in the Envoy Proxy API or Envoy Gateway’s xDS translation. But with EnvoyPatchPolicy, you can dynamically shape your Envoy Gateway’s behavior, unlocking the platform’s full potential.

Prerequisites

Before diving into EnvoyPatchPolicy, ensure you have installed Envoy Gateway and the example manifest. To get started, you should be able to query the example backend using HTTP. Follow these commands:

# Install Envoy Gateway and the example manifest
helm install eg oci://docker.io/envoyproxy/gateway-helm --version v1.3.2 -n envoy-gateway-system --create-namespace
kubectl wait --timeout=5m -n envoy-gateway-system deployment/envoy-gateway --for=condition=Available
kubectl apply -f https://github.com/envoyproxy/gateway/releases/download/v1.3.2/quickstart.yaml -n default
export ENVOY_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}')
kubectl -n envoy-gateway-system port-forward service/${ENVOY_SERVICE} 8888:80 &

Enabling EnvoyPatchPolicy

By default, EnvoyPatchPolicy is disabled. To enable it, you need to take a few manual steps. We’ll mount the envoy-gateway-config ConfigMap in the previously created Envoy Gateway and execute the following commands:

cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: ConfigMap
metadata:
  name: envoy-gateway-config
  namespace: envoy-gateway-system
data:
  envoy-gateway.yaml: |
    apiVersion: config.gateway.envoyproxy.io/v1alpha1
    kind: EnvoyGateway
    provider:
      type: Kubernetes
    gateway:
      controllerName: gateway.envoyproxy.io/gatewayclass-controller
    extensionApis:
      enableEnvoyPatchPolicy: true
EOF

# Restart Envoy Gateway Pod to remount the ConfigMap
kubectl rollout restart deployment envoy-gateway -n envoy-gateway-system

Customizing Responses

You can use the EnvoyPatchPolicy API to modify the generated Envoy xDS resources by Envoy Gateway. But now it only supports the JSONPatch type.

Envoy allows you to customize the local response content it sends back. You can define a list of mappers to specify how these responses should be modified. Each mapper includes a filter and various rewrite rules, such as a status_code rule for altering response codes, a headers_to_add rule for manipulating HTTP headers, a body rule for changing the response body, and a body_format_override rule for specifying the response body format. Envoy processes these mappers in the order specified until the first match is found, applying all applicable rewrite rules.

Let’s leverage Envoy Proxy’s Local Reply Modification feature to send a custom response to the client when the status code is 404.

The following diagram shows the architecture of this demo.

image
Local Reply Modification with EnvoyPatchPolicy

Apply the configuration as follows:

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

Let’s further edit the HTTPRoute resource from Quickstart to match only on paths with the value /get.

kubectl patch httproute backend --type=json -n default --patch '[{
   "op": "add",
   "path": "/spec/rules/0/matches/0/path/value",
   "value": "/get",
}]'

Finally, let’s test it by specifying a path other than /get.

curl --header "Host: www.example.com" http://localhost:8888/find

The response should be could not find what you are looking for.

It’s essential to note that this API might remain unstable across versions due to potential changes in the Envoy Proxy API or Envoy Gateway’s xDS translation. Be prepared for variations in outcomes as the software evolves.

Enjoy exploring the powerful EnvoyPatchPolicy to shape your Envoy Gateway’s behavior dynamically!

Reference

Last updated on Apr 14, 2025