Traffic Extension
TrafficExtension provides a mechanism to extend the functionality provided by the Istio proxy through WebAssembly or Lua filters.
This API supersedes WasmPlugin by providing a unified mechanism for configuring multiple extension types (WebAssembly and Lua) while maintaining consistent targeting and configuration patterns.
The order of execution (as part of Envoy’s filter chain) is determined by phase and priority settings, allowing the configuration of complex interactions between user-supplied WebAssembly or Lua and Istio’s internal filters.
Examples:
AuthN Filter deployed to ingress-gateway that implements an OpenID flow
and populates the Authorization header with a JWT to be consumed by
Istio AuthN.
apiVersion: extensions.istio.io/v1alpha1
kind: TrafficExtension
metadata:
name: openid-connect
namespace: istio-ingress
spec:
selector:
matchLabels:
istio: ingressgateway
phase: AUTHN
wasm:
url: file:///opt/filters/openid.wasm
sha256: 1ef0c9a92b0420cf25f7fe5d481b231464bc88f486ca3b9c83ed5cc21d2f6210
pluginConfig:
openid_server: authn
openid_realm: ingress
This is the same as the last example, but using an OCI image.
apiVersion: extensions.istio.io/v1alpha1
kind: TrafficExtension
metadata:
name: openid-connect
namespace: istio-ingress
spec:
selector:
matchLabels:
istio: ingressgateway
phase: AUTHN
wasm:
url: oci://private-registry:5000/openid-connect/openid:latest
imagePullPolicy: IfNotPresent
imagePullSecret: private-registry-pull-secret
pluginConfig:
openid_server: authn
openid_realm: ingress
This is the same as the last example, but using VmConfig to configure environment variables in the VM.
apiVersion: extensions.istio.io/v1alpha1
kind: TrafficExtension
metadata:
name: openid-connect
namespace: istio-ingress
spec:
selector:
matchLabels:
istio: ingressgateway
phase: AUTHN
wasm:
url: oci://private-registry:5000/openid-connect/openid:latest
imagePullPolicy: IfNotPresent
imagePullSecret: private-registry-pull-secret
pluginConfig:
openid_server: authn
openid_realm: ingress
vmConfig:
env:
- name: POD_NAME
valueFrom: HOST
- name: TRUST_DOMAIN
value: "cluster.local"
This is also the same as the last example, but the Wasm module is pulled via https and updated for each time when this plugin resource is changed.
apiVersion: extensions.istio.io/v1alpha1
kind: TrafficExtension
metadata:
name: openid-connect
namespace: istio-ingress
spec:
selector:
matchLabels:
istio: ingressgateway
phase: AUTHN
wasm:
url: https://private-bucket/filters/openid.wasm
imagePullPolicy: Always
pluginConfig:
openid_server: authn
openid_realm: ingress
vmConfig:
env:
- name: POD_NAME
valueFrom: HOST
- name: TRUST_DOMAIN
value: "cluster.local"
And a more complex example that deploys three TrafficExtensions and orders them
using phase and priority. The (hypothetical) setup is that the
openid-connect filter performs an OpenID Connect flow to authenticate the
user, writing a signed JWT into the Authorization header of the request,
which can be verified by the Istio authn plugin. Then, the acl-check plugin
kicks in, passing the JWT to a policy server, which in turn responds with a
signed token that contains information about which files and functions of the
system are available to the user that was previously authenticated. The
acl-check filter writes this token to a header. Finally, the check-header
filter verifies the token in that header and makes sure that the token’s
contents (the permitted ‘function’) matches its plugin configuration.
The resulting filter chain looks like this: -> openid-connect -> istio.authn -> acl-check -> check-header -> router
apiVersion: extensions.istio.io/v1alpha1
kind: TrafficExtension
metadata:
name: openid-connect
namespace: istio-ingress
spec:
selector:
matchLabels:
istio: ingressgateway
phase: AUTHN
wasm:
url: oci://private-registry:5000/openid-connect/openid:latest
imagePullPolicy: IfNotPresent
imagePullSecret: private-registry-pull-secret
pluginConfig:
openid_server: authn
openid_realm: ingress
apiVersion: extensions.istio.io/v1alpha1
kind: TrafficExtension
metadata:
name: acl-check
namespace: istio-ingress
spec:
selector:
matchLabels:
istio: ingressgateway
phase: AUTHZ
priority: 1000
wasm:
url: oci://private-registry:5000/acl-check/acl:latest
imagePullPolicy: Always
imagePullSecret: private-registry-pull-secret
pluginConfig:
acl_server: some_server
set_header: authz_complete
apiVersion: extensions.istio.io/v1alpha1
kind: TrafficExtension
metadata:
name: check-header
namespace: istio-ingress
spec:
selector:
matchLabels:
istio: ingressgateway
phase: AUTHZ
priority: 10
wasm:
url: oci://private-registry:5000/check-header:latest
imagePullPolicy: IfNotPresent
imagePullSecret: private-registry-pull-secret
pluginConfig:
read_header: authz_complete
verification_key: a89gAzxvls0JKAKIJSBnnvvvkIO
function: read_data
Gateway with Lua filter for conditional header modification:
apiVersion: extensions.istio.io/v1alpha1
kind: TrafficExtension
metadata:
name: conditional-header-modifier
namespace: istio-ingress
spec:
selector:
matchLabels:
istio: ingressgateway
match:
- mode: CLIENT
ports:
- number: 8080
- number: 8081
phase: AUTHN
priority: 1000
lua:
inlineCode: |
function envoy_on_request(request_handle)
local domain = "foo.com"
local headers = request_handle:headers()
local host = headers:get(":authority")
local existing_auth_header = headers:get("Authorization")
if (domain ~= nil and host ~= nil and existing_auth_header == nil and domain == host) then
local bearer_token = headers:get("cookie"):match("foo")
if (bearer_token ~= nil) then
headers:add("Authorization", "Bearer " .. bearer_token)
end
end
end
Waypoint with Lua filter for header count logging:
apiVersion: extensions.istio.io/v1alpha1
kind: TrafficExtension
metadata:
name: reviews-header-logger
namespace: default
spec:
targetRefs:
- kind: Service
name: reviews
match:
- mode: SERVER
phase: STATS
lua:
inlineCode: |
function envoy_on_request(request_handle)
local headers = request_handle:headers()
local num_headers = 0
for key, value in pairs(headers) do
num_headers = num_headers + 1
end
request_handle:logInfo("Request to reviews service has " .. num_headers .. " headers")
end
TrafficExtension
+kubebuilder:validation:XValidation:message=“only one of targetRefs or selector can be set”,rule="(has(self.selector)?1:0)+(has(self.targetRefs)?1:0)<=1" +kubebuilder:validation:XValidation:message=“exactly one of wasm or lua must be set”,rule=“has(self.wasm) != has(self.lua)”
ExecutionPhase
ExecutionPhase specifies where in the filter chain a TrafficExtension is injected.
| Name | Description |
|---|---|
UNSPECIFIED | Control plane decides where to insert the extension. This will generally
be at the end of the filter chain, right before the Router.
Do not specify |
AUTHN | Insert before Istio authentication filters. |
AUTHZ | Insert before Istio authorization filters and after Istio authentication filters. |
STATS | Insert before Istio stats filters and after Istio authorization filters. |
WasmConfig
WasmConfig configures a WebAssembly filter.
Example:
wasm:
url: oci://gcr.io/myproject/filter:v1.0.0
sha256: abc123...
imagePullPolicy: IfNotPresent
imagePullSecret: gcr-secret
pluginName: my-filter
pluginConfig:
key1: value1
key2: value2
failStrategy: FAIL_CLOSE
vmConfig:
env:
- name: SOME_ENV_VAR
value: some_value
type: HTTP
LuaConfig
LuaConfig configures a Lua filter.
Lua filters provide a lightweight alternative to WebAssembly for simple request/response transformations. The Lua code is executed inline within the Envoy proxy.
Example: Simple header manipulation
lua:
inlineCode: |
function envoy_on_request(request_handle)
request_handle:headers():add("x-custom-header", "custom-value")
end
The Lua script must define one or both of the following functions:
envoy_on_request(request_handle): Called when a request is receivedenvoy_on_response(response_handle): Called when a response is received
The request_handle and response_handle provide access to headers, body, metadata, and other request/response attributes. See the Envoy Lua filter documentation for the complete API: https://www.envoyproxy.io/docs/envoy/latest/configuration/http/http_filters/lua_filter
TrafficSelector
TrafficSelector provides a mechanism to select a specific traffic flow for which a TrafficExtension will be enabled. When all the sub conditions in the TrafficSelector are satisfied, the traffic will be selected.