Envoy Wasm 网络过滤器:用 WebAssembly 插件扩展 Envoy 的 Network Filter 能力
本篇指南基于 Envoy 官方文档中的 Wasm Network Filter 配置章节展开,完整讲解 envoy.filters.network.wasm 过滤器的定位、实验性状态、YAML 配置写法与全部关键字段(PluginConfig、VmConfig、failure_policy 等),并结合仓库中的 protobuf 定义与 C++ 实现源码,说明该过滤器从配置解析到 VM 加载的完整调用链,帮助读者理解如何在 Envoy 的 TCP 网络过滤器链中安全地接入 Wasm 插件。
1. 什么是 Wasm 网络过滤器
Wasm 网络过滤器(Wasm Network Filter)用于用一个 Wasm 插件实现一个网络过滤器,即它工作在 Envoy 的 L4 网络过滤器链上(envoy.filters.network.wasm),而不是 HTTP 过滤器链上。插件以 Proxy-Wasm ABI 编写,编译为 .wasm 二进制后由 Envoy 内置的 Wasm 运行时加载执行。
官方文档中有明确的实验性声明,这一点在评估生产可用性时必须注意:
The Wasm filter is experimental and is currently under active development. Capabilities will be expanded over time and the configuration structures are likely to change.
(Wasm 过滤器目前是实验性的,正在积极开发中,能力会随时间扩展,配置结构也可能发生变化。)
对应 v3 API 参考文档为 envoy.extensions.filters.network.wasm.v3.Wasm。
2. 基本配置示例
文档给出的完整过滤器配置如下,它从本地磁盘加载一个 Wasm 二进制文件:
name: envoy.filters.network.wasm
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.network.wasm.v3.Wasm
config:
config:
name: "my_plugin"
vm_config:
code:
local:
filename: "/etc/envoy_filter_http_wasm_example.wasm"
allow_precompiled: true
逐层解读这个配置:
name: envoy.filters.network.wasm:过滤器在过滤器链中的名称,取自注册名。源码中WasmFilterConfig构造函数以NetworkFilterNames::get().Wasm作为注册名(见 config.h)。@type:指向 proto 消息envoy.extensions.filters.network.wasm.v3.Wasm,该消息只有一个字段config,类型为envoy.extensions.wasm.v3.PluginConfig(见 wasm.proto)。config.name: "my_plugin":插件在 VM 中的唯一名称,用于日志和调试;当同一个vm_id与root_id下存在多个插件时,用它来区分。vm_config.code.local.filename:Wasm 代码来源,这里使用AsyncDataSource的本地文件方式。也可以改用远程获取(remote)方式下发。allow_precompiled: true:允许 wasm 文件包含预编译代码(仅限支持该特性的运行时)。
需要注意的是,官方示例中文件名沿用了 envoy_filter_http_wasm_example.wasm 这类 HTTP Wasm 示例的命名习惯;对于网络过滤器,插件需实现 Proxy-Wasm 的 network filter 相关回调(如 proxy_on_connect、proxy_on_data),由同一个 VM 基础设施驱动。
3. 核心配置字段详解
Wasm 过滤器的实际配置主体是 PluginConfig(wasm.proto),以下字段对配置该过滤器时理解行为至关重要。
3.1 插件标识与 VM 复用
| 字段 | 说明 |
|---|---|
name |
插件唯一名称,用于同一 VM 内多插件的标识与日志调试 |
root_id |
同一 VM 中共享 RootContext/Contexts 的插件分组 ID(例如一个 Wasm HTTP 过滤器与一个 Wasm 访问日志)。留空时,vm_id 相同且 root_id 为空的插件共享 Context |
vm_config.vm_id |
与 wasm 代码哈希一起决定使用哪个 VM。所有使用相同 vm_id 和代码的插件将复用同一个 VM。留空即可。共享 VM 可降低内存占用、便于数据共享,但可能有安全影响 |
3.2 运行时与代码来源
vm_config.runtime:Wasm 运行时类型,默认使用 Envoy 构建时第一个可用的引擎,查找优先级为 v8 -> wasmtime -> wamr。内置可用运行时:envoy.wasm.runtime.null:Null 沙箱,Wasm 模块必须编译链接进 Envoy 二进制,注册名写在code字段的inline_string中;envoy.wasm.runtime.v8:基于 V8 的运行时;envoy.wasm.runtime.wamr:基于 WAMR 的运行时(官方构建未启用);envoy.wasm.runtime.wasmtime:基于 Wasmtime 的运行时(官方构建未启用)。
vm_config.code:类型为config.core.v3.AsyncDataSource,支持本地文件(local)、远程获取(remote)与内联字符串(inline_string)。vm_config.allow_precompiled:允许 wasm 文件携带预编译代码。警告:预编译代码不做校验,只能对可信来源开启。vm_config.nack_on_code_cache_miss:若代码需要远程获取且缓存未命中,为true时直接 NACK 该配置更新并在后台拉取填充缓存;否则异步拉取代码并进入 warming 状态。
3.3 插件初始化配置
vm_config.configuration(VM 级):用于proxy_on_start初始化 VM。google.protobuf.Struct会序列化为 JSON 传给插件;google.protobuf.BytesValue与google.protobuf.StringValue直接透传。configuration(插件级):用于proxy_on_configure配置或重配置插件,序列化规则同上。
3.4 环境变量注入
vm_config.environment_variables(类型 EnvironmentVariables)可向 VM 注入环境变量,插件通过 WASI 的 environ_get / environ_get_sizes_get 系统调用访问——这些调用通常由语言标准库隐式触发,插件代码可按原生日平台方式读取环境变量。
host_env_keys:从 Envoy 自身 的环境中透传指定 key(若 Envoy 环境中不存在该 key 则忽略);key_values:以"KEY=VALUE"形式显式注入的键值对。- 注意:Envoy 会在键空间冲突时拒绝该配置。
4. 失败策略:failure_policy
VM 发生致命错误(如异常、abort()、on_start 或 on_configure 返回 false)时,按 failure_policy 处理。可选枚举值(wasm.proto):
| 策略 | 行为 |
|---|---|
UNSPECIFIED(默认) |
未指定策略,使用默认策略 FAIL_CLOSED |
FAIL_RELOAD |
VM 失败后,为新请求创建新的插件实例。注意仅对 proxy_wasm::FailState::RuntimeError 生效,其余失败会回退到 FAIL_CLOSED |
FAIL_CLOSED |
该 VM 关联的所有插件返回 HTTP 503 错误 |
FAIL_OPEN |
该 VM 关联的所有插件被忽略,过滤器链继续处理(适合插件是可选能力的场景) |
配套字段:
reload_config.backoff:仅当failure_policy为FAIL_RELOAD时生效,控制 VM 失败重载的退避策略,不指定时默认 1s 基础间隔。- 旧字段
fail_open(布尔)已废弃(deprecated_at_minor_version "3.0"),被failure_policy取代。
另有一个重要注意点:当 on_start 或 on_configure 在 xDS 更新过程中返回 false 时,xDS 配置会被拒绝;在初始启动时返回 false 则代理进程不会启动。
5. 能力限制:capability_restriction_config
CapabilityRestrictionConfig 用于限制模块可用的 Proxy-Wasm 能力:
allowed_capabilities:以能力名为键的白名单。能力名遵循 Proxy-Wasm ABI;此外实现了以下 WASI 能力,可被允许:fd_write、fd_read、fd_seek、fd_close、fd_fdstat_get、environ_get、environ_sizes_get、args_get、args_sizes_get、proc_exit、clock_time_get、random_get。- 每个能力映射的
SanitizationConfig目前未实现,应留空。 - 限制在 VM 创建时生效,且被该 VM 中所有插件共享,因此它是 VM 的属性而非单个插件的属性。
- 插件级旧字段
capability_restriction_config已废弃:若插件级字段已设置而vm_config.capability_restriction_config未设置,则用插件级字段填充 VM 级字段。
6. 源码实现视角
结合仓库源码,可以看清配置到运行的完整链路。
过滤器注册:config.cc 中,WasmFilterConfig 通过 FactoryBase<envoy::extensions::filters.network.wasm.v3::Wasm> 解析 Wasm proto,并在文件末尾以 REGISTER_FACTORY(WasmFilterConfig, Server::Configuration::NamedNetworkFilterConfigFactory) 完成静态注册,这正是配置中 envoy.filters.network.wasm 名称的来源。
工厂回调的 fail-open 语义:
auto filter_config = std::make_shared<FilterConfig>(proto_config, context);
return filter_config -> void {
auto filter = filter_config->createContext();
if (filter) {
filter_manager.addFilter(filter);
} // else fail open
};
从源码结构看,若插件上下文创建失败,工厂回调不会向过滤器管理器添加任何过滤器,即请求“fail open”地绕过该 Wasm 过滤器继续走后续过滤器链——这与第 4 节 FAIL_OPEN 策略在连接建立阶段的默认行为相一致。同时该工厂在创建前会注册 Wasm 的自定义统计命名空间(Extensions::Common::Wasm::CustomStatNamespace),用于插件自定义指标。
配置基类:wasm_filter.cc 中,网络过滤器的 FilterConfig 直接继承通用的 Extensions::Common::Wasm::PluginConfig,构造时把 proto 的 config.config()(即 PluginConfig)、统计作用域、InitManager 传入,最后一个参数 false 表明它不是 singleton 模式(每个 worker 拥有自己的 VM 实例,而非 WasmService 那种全局单例 VM)。也就是说,网络过滤器、HTTP 过滤器、访问日志等所有 Wasm 扩展共享同一套插件配置与 VM 管理逻辑,网络过滤器只是其在 L4 过滤器链上的一个出口。
7. 实战注意事项
- 实验性定位:文档明确标注该过滤器为实验性,配置结构可能变化,变更前应确认目标 Envoy 版本。
allow_precompiled只对可信代码开启:预编译代码不做校验,远程下发不可信.wasm时存在供应链风险。- 默认失败策略是 fail closed:
UNSPECIFIED回退到FAIL_CLOSED(HTTP 503),若插件属于可选增强能力,应显式配置FAIL_OPEN以避免 VM 崩溃阻断流量。 on_start/on_configure返回 false 的后果:xDS 更新阶段会拒绝配置;启动阶段会直接阻止代理启动,调试插件时建议先本地验证这两个回调。- VM 共享与
vm_id:多个插件配相同vm_id与代码会复用同一 VM,节省内存并便于插件间共享数据,但需评估跨插件数据可见性带来的安全影响。 - 远程代码与缓存:使用
remote下发代码时,用nack_on_code_cache_miss控制缓存未命中的行为——true时快速失败(NACK)加后台拉取,false时进入 warming 异步拉取。
8. 相关资源索引
- API 定义:api/envoy/extensions/filters/network/wasm/v3/wasm.proto
- 通用 Wasm 插件配置(
PluginConfig/VmConfig/FailurePolicy):api/envoy/extensions/wasm/v3/wasm.proto - 过滤器注册与工厂:source/extensions/filters/network/wasm/config.cc、source/extensions/filters/network/wasm/config.h
- 过滤器配置实现:source/extensions/filters/network/wasm/wasm_filter.cc
- 原始文档:docs/root/configuration/listeners/network_filters/wasm_filter.rst
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust4.24 K638- DDeepSeek-V4.1-FlashDeepSeek-V4.1-Flash 是一个多模态混合专家(MoE)模型,拥有 5520 亿骨干参数,并支持最多一百万 token 的上下文长度。该模型原生支持图像和文本输入,并以自回归方式生成文本Python670
SlideSCIPPT插件,支持素材库、AI助手、一键添加图片标题,复制粘贴位置、一键图片对齐、一键插入Markdown(加粗、超链接等行内样式、代码块、LaTeX等块级样式)、便捷导出图片!C#230
hello-agents📚 《从零开始构建智能体》——从零开始的智能体原理与实践教程Python52874
new-apiAI模型聚合管理中转分发系统,一个应用管理您的所有AI模型,支持将多种大模型转为统一格式调用,支持OpenAI、Claude、Gemini等格式,可供个人或者企业内部管理与分发渠道使用。🍥 A Unified AI Model Management & Distribution System. Aggregate all your LLMs into one app and access them via an OpenAI-compatible API, with native support for Claude (Messages) and Gemini formats.Go22545
JeecgBoot🔥企业级低代码平台集成了AI应用平台,帮助企业快速实现低代码开发和构建AI应用!前后端分离架构 SpringBoot,SpringCloud、Mybatis,Ant Design4、 Vue3.0、TS+vite!强大的代码生成器让前后端代码一键生成,无需写任何代码! 引领AI低代码开发模式: AI生成->OnlineCoding-> 代码生成-> 手工MERGE,显著的提高效率,又不失灵活~Java36351