Executing Lua Scripts

Istio provides the ability to extend proxy functionality using inline Lua scripts via the TrafficExtension API. Lua filters are a lightweight alternative to WebAssembly for simple request and response transformations — the script is embedded directly in the resource and executed within the Envoy proxy, with no module distribution required.

Before you begin

Deploy the Bookinfo sample application.

Configure a Lua script

A Lua script must define one or both of the following functions:

  • envoy_on_request(request_handle): called for each inbound request
  • envoy_on_response(response_handle): called for each outbound response

The handles provide access to headers, body, metadata, and logging. See the Envoy Lua filter documentation for the complete API.

In this example, you will add a Lua filter to the ingress gateway that reads an x-number request header and responds with an x-parity header indicating whether the value is odd or even. The value is read during request processing and stored in dynamic metadata so it is available when writing the response header:

$ kubectl apply -f - <<EOF
apiVersion: extensions.istio.io/v1alpha1
kind: TrafficExtension
metadata:
  name: parity
  namespace: istio-system
spec:
  selector:
    matchLabels:
      istio: ingressgateway
  phase: AUTHN
  lua:
    inlineCode: |
      function envoy_on_request(request_handle)
        local number = tonumber(request_handle:headers():get("x-number"))
        if number == nil then return end
        local parity = number % 2 == 0 and "even" or "odd"
        request_handle:streamInfo():dynamicMetadata():set(
          "envoy.filters.http.lua", "parity", parity)
      end
      function envoy_on_response(response_handle)
        local meta = response_handle:streamInfo():dynamicMetadata():get(
          "envoy.filters.http.lua")
        if meta == nil then return end
        response_handle:headers():add("x-parity", meta["parity"])
      end
EOF

Verify the Lua script

Determine the ingress IP and port.

Send a request with an x-number header and check that x-parity is set in the response:

$ curl -s -o /dev/null -D - -H "x-number: 42" "http://$INGRESS_HOST:$INGRESS_PORT/productpage" | grep x-parity
x-parity: even
$ curl -s -o /dev/null -D - -H "x-number: 7" "http://$INGRESS_HOST:$INGRESS_PORT/productpage" | grep x-parity
x-parity: odd

Ordering and scoping

When multiple TrafficExtension resources target the same workload, execution order is controlled by phase and priority.

  • phase sets the broad position in the filter chain: AUTHN, AUTHZ, or STATS. Extensions without a phase are inserted near the end of the chain, before the router.
  • priority breaks ties within the same phase. Higher values run first.

The match field restricts a TrafficExtension to specific traffic by mode and port:

spec:
  match:
  - mode: SERVER
    ports:
    - number: 8080

Valid modes are CLIENT (outbound), SERVER (inbound), and CLIENT_AND_SERVER (both, the default).

Clean up

$ kubectl delete trafficextension -n istio-system parity
Was this information useful?
Do you have any suggestions for improvement?

Thanks for your feedback!