External processing (ExtProc)
Modify aspects of an HTTP request or response with an external processing server.
About external processing
Envoy offers multiple filters that you can use to manage, monitor, and secure traffic to your apps. Although Envoy is extensible via C++ and WebAssembly modules, it might not be practical to implement these extensions for all of your apps. You might also have very specific requirements for how to process a request or response to allow traffic routing between different types of apps, such as adding specific headers to new and legacy apps.
With the Envoy external processing (ExtProc) filter, you can implement an external gRPC processing server that can read and modify all aspects of an HTTP request or response, and add that server to the Envoy filter chain. The external service can manipulate headers, body, and trailers of a request or response before it is forwarded to an upstream or downstream service. The request or response can also be terminated at any given time.
With this approach, you have the flexibility to apply your requirements to all types of apps, without the need to run WebAssembly or other custom scripts.
How it works
The following diagram shows an example for how request header manipulation works when an external processing server is used.
- The downstream service sends a request with headers to the Envoy gateway.
- The gateway extracts the header information and sends it to the external processing server.
- The external processing server modifies, adds, or removes the request headers.
- The modified request headers are sent back to the gateway.
- The modified headers are added to the request.
- The request is forwarded to the upstream application.
ExtProc server considerations
The ExtProc server is a gRPC interface that must be able to respond to events in the lifecycle of an HTTP request. When the ExtProc filter is enabled in Gloo Gateway and a request or response is received on the gateway, the filter communicates with the ExtProc server by using bidirectional gRPC streams.
To implement your own ExtProc server, make sure that you follow Envoy’s technical specification for an external processor. This guide uses a sample ExtProc server that you can use to try out the ExtProc functionality.
Before you begin
-
Follow the Get started guide to install kgateway.
-
Follow the Sample app guide to create an API gateway proxy with an HTTP listener and deploy the httpbin sample app.
-
Get the external address of the gateway and save it in an environment variable.
export INGRESS_GW_ADDRESS=$(kubectl get svc -n kgateway-system http -o jsonpath="{.status.loadBalancer.ingress[0]['hostname','ip']}") echo $INGRESS_GW_ADDRESS
kubectl port-forward deployment/http -n kgateway-system 8080:8080
Set up an ExtProc server
Use a sample ExtProc server implementation to try out the ExtProc functionality in kgateway
-
Set up the ExtProc server. This example uses a prebuilt ExtProc server that manipulates request and response headers based on instructions that are sent in an instructions header.
kubectl apply -n kgateway-system -f- <<EOF apiVersion: apps/v1 kind: Deployment metadata: name: ext-proc-grpc spec: selector: matchLabels: app: ext-proc-grpc replicas: 1 template: metadata: labels: app: ext-proc-grpc spec: containers: - name: ext-proc-grpc image: gcr.io/solo-test-236622/ext-proc-example-basic-sink:0.0.2 imagePullPolicy: IfNotPresent ports: - containerPort: 18080 --- apiVersion: v1 kind: Service metadata: name: ext-proc-grpc labels: app: ext-proc-grpc spec: ports: - port: 4444 targetPort: 18080 protocol: TCP appProtocol: kubernetes.io/h2c selector: app: ext-proc-grpc EOF
The
instructions
header must be provided as a JSON string in the following format:{ "addHeaders": { "header1": "value1", "header2": "value2" }, "removeHeaders": [ "header3", "header4" ], } }
-
Verify that the ExtProc server is up and running.
kubectl get pods -n kgateway-system | grep ext-proc-grpc
Set up ExtProc for a route
You can enable ExtProc for a particular route in an HTTPRoute resource.
-
Create a GatewayExtension resource to enable external processing in your environment. This resource points to the ExtProc service that you created earlier.
kubectl apply -n kgateway-system -f- <<EOF apiVersion: gateway.kgateway.dev/v1alpha1 kind: GatewayExtension metadata: name: ext-proc-extension spec: type: ExtProc extProc: grpcService: backendRef: name: ext-proc-grpc port: 4444 EOF
-
Create a TrafficPolicy that references the GatewayExtension resource that you created earlier.
kubectl apply -n kgateway-system -f- <<EOF apiVersion: gateway.kgateway.dev/v1alpha1 kind: TrafficPolicy metadata: name: extproc spec: extProc: extensionRef: name: ext-proc-extension EOF
-
Create an HTTPRoute that exposes two routes for the httpbin app along the
extproc.example
domain. One route (/headers
) is configured for external processing and the other one (/get
) is not.kubectl apply -f- <<EOF apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: name: extproc namespace: kgateway-system labels: example: httpbin-route spec: parentRefs: - name: http namespace: kgateway-system hostnames: - "extproc.example" rules: - matches: - path: type: PathPrefix value: /headers backendRefs: - name: httpbin port: 8000 namespace: httpbin filters: - type: ExtensionRef extensionRef: group: gateway.kgateway.dev kind: TrafficPolicy name: extproc - matches: - path: type: PathPrefix value: /get backendRefs: - name: httpbin port: 8000 namespace: httpbin EOF
-
Create a ReferenceGrant resource to allow the HTTPRoute to forward traffic to the httpbin app. This resource is required, because the HTTPRoute resource and httpbin app are deployed to different namespaces.
kubectl apply -f- <<EOF apiVersion: gateway.networking.k8s.io/v1beta1 kind: ReferenceGrant metadata: name: allow-httproute-to-httpbin namespace: httpbin # The namespace where the target Service exists spec: from: - group: gateway.networking.k8s.io kind: HTTPRoute namespace: kgateway-system # The namespace of the HTTPRoute to: - group: "" # Empty string means it's a core API (like Service) kind: Service EOF
-
Send a request to the httpbin app along the
/headers
path and provide your instructions in theinstruction
header. This example instructs the ExtProc server to add theextproc: true
header. Verify that you get back a 200 HTTP response and that your response includes theextproc: true
header.curl -vik http://$INGRESS_GW_ADDRESS:8080/headers -H "host: extproc.example" -H 'instructions: {"addHeaders":{"extproc":"true"}}'
Example output:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
< HTTP/1.1 200 OK HTTP/1.1 200 OK ... < { "headers": { "Accept": [ "*/*" ], "Extproc": [ "true" ], "Host": [ "extproc.example" ], "Instructions": [ "{\"addHeaders\":{\"extproc\":\"true\"}}" ], "User-Agent": [ "curl/8.7.1" ], ...
-
Send a request along the
/get
path. Verify that you get back a 200 HTTP response code. However, because this route is not configured for ExtProc, you do not see theextproc: true
header in your response.curl -vik http://$INGRESS_GW_ADDRESS:8080/get -H "host: extproc.example" -H 'instructions: {"addHeaders":{"extproc":"true"}}'
Example output:
< HTTP/1.1 200 OK HTTP/1.1 200 OK ... < { "headers": { "Accept": [ "*/*" ], "Host": [ "extproc.example" ], "Instructions": [ "{\"addHeaders\":{\"extproc\":\"true\"}}" ], "User-Agent": [ "curl/8.7.1" ], ...
Cleanup
You can remove the resources that you created in this guide.kubectl delete httproute extproc -n kgateway-system
kubectl delete trafficpolicy extproc -n kgateway-system
kubectl delete referencegrant allow-httproute-to-httpbin -n httpbin
kubectl delete gatewayextension ext-proc-extension -n kgateway-system
kubectl delete deployment ext-proc-grpc -n kgateway-system
kubectl delete service ext-proc-grpc -nkgateway-system