从“网格”说起:服务网格到底是什么
我的处理经验
说到Mesh Istio,很多问题都出在细节上。在传统的单体架构里,安全防护往往集中在网关或应用自身。但微服务化之后,服务之间动辄成百上千条网络调用,每个服务都自己实现安全逻辑既不现实,也容易产生漏洞。这时候,服务网格(Service Mesh) 出现了——它把网络通信、负载均衡、服务发现、安全策略等基础设施能力从业务代码中剥离出来,下沉到一个独立的基础设施层。这个层通常以“边车代理”(Sidecar Proxy)的形式伴随每个服务实例运行。
你只需要部署一个代理容器(比如 Envoy),它自动劫持服务进出流量,所有集群内的通信都经过它。于是,整个网格变成了一个可编程的数据平面,安全规则、流量路由、可观测性全部可以在这个平面上统一配置。这就是云原生 Mesh 架构的核心思想。
Istio 和 Envoy:谁在网格里干活?
容易忽略的细节
目前最流行的服务网格实现是 Istio。它并不是自己实现了代理,而是基于 Envoy(一个高性能 C++ 代理)来作为数据平面。Istio 的控制平面负责下发配置(比如路由、策略、安全规则),而 Envoy 代理负责执行。换句话说,Istio 是大脑,Envoy 是手脚。
Envoy 强大的可扩展性使其支持动态配置。除了内置的 HTTP 连接管理、健康检查、TLS 终止等功能,Envoy 还提供了一种机制允许用户在不修改 Envoy 核心代码的前提下,注入自定义逻辑——这就是 EnvoyFilter。
相关阅读:此处可内链到“Mesh Istio常见问题”专题。
EnvoyFilter 是什么?为什么它适合做 WAF?——Mesh Istio
实际操作要点
EnvoyFilter 是 Istio 中的一种自定义资源(CRD),允许你直接操作 Envoy 的配置。你可以通过它插入新的过滤器、修改现有过滤器参数、甚至完全替换 Envoy 监听器或集群配置。对于安全场景来说,我们最常用的是在 HTTP 连接管理器(HttpConnectionManager)上插入一个 Lua 过滤器 或 本地速率限制过滤器,实现自定义的请求检查逻辑。
传统的 WAF(Web 应用防火墙) 通常部署在入口网关(如 Nginx、硬件设备)或者作为反向代理集群。但在服务网格中,每个服务实例都有一个 Envoy 边车,这意味着你可以在距离攻击目标最近的地方——也就是每个服务的入口——执行安全检测。这样有几个明显优势:
- 精细化:可以为特定的服务、特定的路由、特定的请求头设定不同的规则。
- 无侵入:业务代码完全不需要修改,安全能力由基础设施层提供。
- 统一管控:所有安全策略通过 Istio 控制平面集中下发,审计和变更都非常方便。
用 EnvoyFilter 实现 WAF 的两种常见方式
1. 使用 Envoy 内置的 rate_limit 过滤器做简单的请求限频
虽然限频不属于严格意义上的 WAF,但它是防止暴力破解和 CC 攻击的有效手段。Envoy 的本地速率限制过滤器可以直接在 EnvoyFilter 中配置阈值,比如每个客户端 IP 每秒最多 10 次请求。
2. 使用 Lua 过滤器编写自定义检测逻辑
Envoy 支持内嵌 Lua 虚拟机,你可以编写 Lua 脚本拦截 HTTP 请求/响应,检查 URL、请求体、请求头中的可疑模式。例如检测 SQL 注入关键词(’ OR 1=1 — 等)、XSS 标签()等。检测到攻击后,可以返回 403、记录日志或直接丢弃连接。
动手:一个拦截 SQL 注入的 EnvoyFilter 实例
先看关键判断
假设我们有一个微服务 orders,它在集群内部接收来自前端网关的请求。我们想对 /api/orders 路径下的所有 POST 请求体进行简单的关键词检查,发现 SQL 注入特征则拒绝。下面是一个典型的 EnvoyFilter 配置(YAML):
apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
name: orders-sql-injection-filter
namespace: default
spec:
workloadSelector:
labels:
app: orders
configPatches:
- applyTo: HTTP_FILTER
match:
context: SIDECAR_INBOUND
listener:
portNumber: 8080
filterChain:
filter:
name: "envoy.filters.network.http_connection_manager"
subFilter:
name: "envoy.filters.http.router"
patch:
operation: INSERT_BEFORE
value:
name: envoy.filters.http.lua
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.lua.v3.Lua
inlineCode: |
function envoy_on_request(request_handle)
local body = request_handle:body()
if body then
if string.find(body, "' OR ") or string.find(body, "1=1") or string.find(body, "DROP TABLE") then
request_handle:respond({[":status"] = "403"}, "Blocked by WAF: SQL injection detected")
end
end
end
这个配置做了几件事:
- 通过
workloadSelector只作用于app=orders的 Pod。 - 在入站 HTTP 连接管理器的 router 过滤器之前插入一个 Lua 过滤器。
- Lua 脚本读取请求体,检查是否包含常见的 SQL 注入模式,命中则返回 403。
注意:实际生产环境不要用简单关键词匹配,应当使用专业的正则表达式库或集成 ModSecurity 的规则集。Lua 过滤器更适合快速自定义轻量逻辑。
补充参考:此处可内链到“Mesh Istio故障排查实例”。
关联教程:此处可内链到“Mesh Istio部署与验证”内容。
Mesh Istio:如何验证和调试你的 WAF 规则?
验证与回滚
EnvoyFilter 一旦 apply,会立即生效。建议先在 staging 环境测试:
- 观察 Envoy 的访问日志(通过 Istio 的 accessLog 配置)确认请求被拦截。
- 使用
istioctl proxy-config listener [pod]查看指定 Pod 的 Envoy 监听器配置,确认 Lua 过滤器已注入。 - 如果规则误拦截了正常请求,可以快速删除 EnvoyFilter 或修改 inlineCode 后重新 apply。
风险与回滚
容易忽略的细节
EnvoyFilter 非常强大,但也容易出错。常见的风险包括:
- 语法错误:Lua 脚本或 YAML 格式错误可能导致 Envoy 拒绝配置,甚至造成 Sidecar 重启。
- 性能影响:复杂的 Lua 逻辑或高并发下请求体检查会增加延迟。
- 误封正常流量:过于激进的规则会阻断合法请求。
回滚方法非常简单:直接 kubectl delete envoyfilter orders-sql-injection-filter,Istio 会自动恢复之前的配置。建议在修改时使用 --dry-run 检查语法,并且逐步灰度(先对少量实例应用)。
总结:Mesh 原生 WAF 是未来趋势
我的处理经验
通过 Istio 的 EnvoyFilter 实现自定义 WAF 并不复杂,它充分利用了服务网格已有的基础设施,避免了在微服务架构中引入额外的反向代理或专用 WAF 设备。对于中小团队来说,这是一种低成本、高灵活性的安全方案。当然,对于复杂的攻击模式(如规则绕过、多阶段攻击),还需要结合专业的 WAF 引擎(如 ModSecurity)或者云厂商的 Web 应用防火墙。但无论如何,掌握 EnvoyFilter 的能力,能让你在服务网格中真正实现“安全即代码”。后续只要定期检查关键指标,Mesh Istio就不会变成维护负担。
延伸阅读
