Istio 的数据面扩展能力一直是其设计核心——从自定义认证到专用遥测采集再到请求/响应实时改写,都依赖往 Envoy sidecar 里注入自定义逻辑。但直到现在,这条路走得并不顺畅:WasmPlugin 只管 WebAssembly 扩展,想写 Lua 脚本只能绕道 EnvoyFilter,后者强大却极易配错。Istio 1.30 推出 TrafficExtension API,把 Wasm 和 Lua 两种扩展方式收进同一个 API,同时补上了 ambient 模式的支持。
为什么需要 TrafficExtension
旧方案有两个痛点:
- Lua 用户没有正式 API。EnvoyFilter 是 Envoy 层面的底层机制,直接操作 filter chain,参数写错一行就可能让整个代理崩溃,排查成本高。
- WasmPlugin 只覆盖 Wasm。如果你同时需要 Lua 做轻量 header 操作和 Wasm 做复杂策略执行,就要维护两套完全不同的 API 资源,selector 逻辑各写一遍。
TrafficExtension 把两者统一到 extensions.istio.io/v1alpha1 这个 API 组下,一个资源里可以声明 Lua 或 Wasm,selector/targetRefs 共用,执行顺序也用同一套 phase + priority 机制控制。
Lua 与 Wasm:怎么选
TrafficExtension 支持两种扩展类型,适用场景泾渭分明:
| 维度 | Lua | WebAssembly |
|---|---|---|
| 代码形式 | 内嵌 inline 脚本,无需分发模块 | OCI 镜像仓库拉取,支持 Go/Rust/C++/AssemblyScript |
| 适合场景 | header 操作、简单日志、条件判断 | 复杂策略、遥测采集、payload 改写 |
| 协议层 | 仅 Layer 7 (HTTP) | Layer 7 + Layer 4 (TCP) |
| 性能 | 轻量,无沙箱开销 | 沙箱隔离,启动有冷启动成本 |
| 依赖 | 无外部模块 | 需 OCI 仓库或 HTTP 拉取 |
一句话决策:能用 Lua 解决的别上 Wasm,需要多语言/复杂逻辑/TCP 层面的才用 Wasm。
写一个 Lua 扩展:给请求加奇偶标记
下面这个示例读取请求头 x-number,判断奇偶,然后在响应头里加 x-parity。整个脚本内嵌在 TrafficExtension 资源里,不需要额外分发任何文件。
apiVersion: extensions.istio.io/v1alpha1
kind: TrafficExtension
metadata:
name: parity
namespace: istio-system
spec:
selector:
matchLabels:
istio: ingressgateway
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
部署后,发一个带 x-number: 42 的请求,响应里就会出现 x-parity: even。注意脚本把中间结果存到 dynamicMetadata 里再在 response 阶段取出来——这是 Envoy Lua filter 的标准做法,避免直接在 request 阶段改 response headers(那时 response 对象还不存在)。
运行验证:
# 假设 ingress gateway 暴露在 $INGRESS_HOST:$INGRESS_PORT
curl -H "x-number: 7" http://$INGRESS_HOST:$INGRESS_PORT/productpage -I
# 响应头中应出现: x-parity: odd
写一个 Wasm 扩展:给网关加 Basic Auth
Lua 处理不了的场景——比如需要 TCP 层策略、或者逻辑复杂到值得用 Go/Rust 写——就该上 Wasm。下面用 Istio 社区预构建的 basic_auth 插件,给 /productpage 路径加 Basic 认证:
apiVersion: extensions.istio.io/v1alpha1
kind: TrafficExtension
metadata:
name: basic-auth
namespace: istio-system
spec:
selector:
matchLabels:
istio: ingressgateway
phase: AUTHN
wasm:
url: oci://ghcr.io/istio-ecosystem/wasm-extensions/basic_auth:1.12.0
pluginConfig:
basic_auth_rules:
- prefix: "/productpage"
request_methods: ["GET", "POST"]
credentials: ["ok:test"]
phase: AUTHN 把这个插件放到认证阶段执行,确保它在授权和统计插件之前运行。credentials: ["ok:test"] 表示只允许用户名 ok、密码 test 通过。
验证:
# 无认证——应返回 401
curl http://$INGRESS_HOST:$INGRESS_PORT/productpage -I
# 带认证——应返回 200
curl -u ok:test http://$INGRESS_HOST:$INGRESS_PORT/productpage -I
两种目标定位方式
TrafficExtension 提供两种定位机制,对应不同部署模式:
selector——基于标签匹配 sidecar
- 写在
istio-system命名空间 → 集群级生效 - 写在其他命名空间 → 只对该命名空间内匹配标签的 workload 生效
targetRefs——直接引用 Gateway 或 Service
这是 ambient 模式的必需方式,因为 waypoint proxy 不对应具体 workload 标签。同一个 basic-auth 扩展,定位到 ambient Gateway 时写法变为:
apiVersion: extensions.istio.io/v1alpha1
kind: TrafficExtension
metadata:
name: basic-auth-gateway
spec:
targetRefs:
- kind: Gateway
group: gateway.networking.k8s.io
name: bookinfo-gateway
phase: AUTHN
wasm:
url: oci://ghcr.io/istio-ecosystem/wasm-extensions/basic_auth:1.12.0
pluginConfig:
basic_auth_rules:
- prefix: "/productpage"
request_methods: ["GET", "POST"]
credentials: ["ok:test"]
注意这里没有 namespace 字段——targetRefs 直接指定资源,不需要标签间接匹配。
多扩展的执行顺序
当多个 TrafficExtension 指向同一个代理时,phase 和 priority 控制先后:
- phase 决定扩展在 filter chain 中的大位置:
AUTHN— 认证阶段AUTHZ— 授权阶段STATS— 可观测性阶段- 不设置 — 靠近 router(默认)
- priority 在同一 phase 内排序,数值越大越先执行。
典型组合:一个 AUTHN phase 的 basic-auth Wasm 插件(priority 100)+ 一个 AUTHZ phase 的 RBAC 插件(priority 50)+ 一个未设 phase 的遥测 Lua 脚本。请求路径上依次是认证 → 授权 → 路由前遥测。
从 WasmPlugin 迁移
Istio 1.30 内部已经把所有 WasmPlugin 资源自动转换为 TrafficExtension 再下发配置,所以现有 WasmPlugin 完全兼容,没有强制迁移时间线。
当你准备好迁移时,步骤很直接:
- 把
kind: WasmPlugin改为kind: TrafficExtension - 把
apiVersion: extensions.istio.io/v1alpha1保持不变(WasmPlugin 也在这个组) - 把
spec.wasm下的字段按 TrafficExtension API reference 微调(主要是phase/priority/targetRefs等新字段) - 删除旧 WasmPlugin 资源,创建新的 TrafficExtension 资源
- 观察代理配置是否正常下发
迁移前建议在测试集群跑一遍,确认 OCI 拉取、pluginConfig 解析、phase 定位都和旧资源行为一致。
当前状态与上手建议
TrafficExtension 目前是 alpha,API 行为可能随反馈调整。上手路径:
- 先用 Lua inline 脚本做简单 header 操作——零依赖,调试快
- 需要复杂逻辑时引入 Wasm,优先用社区预构建插件(Istio ecosystem 仓库里有 basic_auth、oauth2 等)
- 自建 Wasm 插件时参考 Proxy-Wasm SDK(Go/Rust/C++),走 OCI 镜像分发
- ambient 模式下务必用
targetRefs定位 waypoint - 遇到问题或有好想法,开 GitHub issue 或到 Istio Slack 反馈——alpha 阶段的社区输入直接决定 API 最终形态
一句话总结:TrafficExtension 让 Istio 数据面扩展从"两套 API 各管各的"变成"一个 API 选 Lua 或 Wasm",降低了配置复杂度,补上了 ambient 支持,是 WasmPlugin 的正式接班人。