Envoy 可以作为 API 网关的数据面、独立边缘代理,或服务网格的一部分。这些是不同的运维模型。Envoy 提供监听器、过滤器、集群、路由、可观测性以及静态或动态配置;网关产品或平台仍需定义期望状态、API 消费者、策略、发布、租户和支持由谁负责。
第一步应明确产品边界。“我们使用 Envoy”并不能告诉值班工程师应该修改 Bootstrap 文件、Kubernetes HTTPRoute、厂商控制面,还是自建 xDS 服务。
本文中的原生 Envoy 行为按稳定版 Envoy 1.39.1 审阅。实际部署要固定补丁版本;Envoy 浮动的 latest 文档跟随开发分支,因此本文不把它作为证据。
核心要点
- 区分 Envoy Proxy、Envoy Gateway、服务网格和第三方 Envoy 网关产品;它们共享技术,但不共享同一份配置和功能契约。
- 静态配置适合简单部署。xDS 增加动态配置能力,同时也带来必须由平台负责的控制面 API 与一致性问题。
- 在边缘监听器上,
use_remote_address和可信 XFF 跳数决定客户端 IP 语义;默认路径并不保证最终用户身份。 - 在
ext_authz中,授权服务返回裁决,Envoy 负责执行;failure_mode_allow会改变授权服务异常时的 Envoy 行为。 - 为重试、超时、转换和授权各指定一个权威层,再测试过滤器顺序与故障时机。
区分各个组件
| 组件 | 负责内容 | 不会自动提供的内容 |
|---|---|---|
| Envoy Proxy | 网络监听器、过滤器链、路由、集群与请求处理 | API 产品生命周期、人工作流或集群控制面 |
| 自建 xDS 控制面 | 由实现方定义的动态 Envoy 资源和发布语义 | 除非平台自行建设,否则不具备完整 API 治理 |
| Envoy Gateway | 把 Kubernetes Gateway API 资源转换成 Envoy Proxy xDS 的控制面 | 不等同于所有 Envoy 商业或开源网关 |
| 使用 Envoy 的服务网格 | 由网格定义的服务流量策略与工作负载集成 | 默认不负责公开 API 消费者管理 |
| 基于 Envoy 的 API 网关产品 | 产品特定策略、界面/API、租户、扩展和支持 | 不能脱离产品默认值与约束,直接等同于原生 Envoy |
Envoy 1.39.1 概览描述了一个支持可选动态配置的通用 L3/L4 与 HTTP 代理。Envoy Gateway是独立项目,其控制面把 Kubernetes Gateway API 资源转换为 Envoy Proxy 所需的 xDS。评估时必须固定具体项目和版本,不能在它们之间直接继承能力。
选择部署模式
1. 在边缘独立运行 Envoy
1flowchart LR
2 C[客户端] --> E[边缘 Envoy]
3 E --> A[API 服务]当小团队需要明确的代理行为,并愿意完整负责静态配置、交付、证书、过滤器和回滚时,该模式是合理选择。Envoy 1.39.1 的 xDS 概览确认支持完全静态配置,因此 Envoy 并不强制要求动态控制面。
代价是平台职责。静态文件不会自动产生消费者接入、策略审批、分布式配额状态或安全的多团队租户能力。平台只应建设组织愿意长期维护的控制界面。
2. Envoy 数据面加网关控制面
1flowchart LR
2 O[平台运维人员] --> P[网关控制面]
3 P -->|xDS 资源| E[Envoy 数据面]
4 C[客户端] --> E
5 E --> A[API 服务]该模式集中管理期望状态,可动态更新监听器、路由、集群、端点和密钥。平台必须定义资源验证、顺序、拒绝、发布、回滚以及控制面断开时的行为。xDS API 是传输与资源模型,不是完整的变更管理策略。
应记录最后一次接受的配置,并暴露被拒绝的更新。测试部分资源更新、无效监听器、缺失集群、证书轮换和管理服务器丢失。不能仅凭控制面 API 接受了请求,就宣称更新成功。
3. 公网 API 网关位于 Envoy 网格代理之前
1flowchart LR
2 C[外部客户端] --> G[API 网关]
3 G --> W1[带 Envoy 的服务工作负载]
4 W1 --> W2[带 Envoy 的下游工作负载]当网关负责外部 API 契约、基于 Envoy 的网格组件负责服务流量时,可以采用该模式。应认证网关到工作负载的连接,在边缘删除调用方提供的身份头,并决定哪些已验证上下文可以跨越边界。不要让边缘和网格独立重试或转换同一个操作。
明确客户端 IP 处理
Envoy 1.39.1 的 HTTP 请求头文档说明,客户端可以伪造 X-Forwarded-For(XFF),直接相连的对等端才是第一个可靠网络事实。必须结合布尔参数 use_remote_address 与默认值为 0 的 xff_num_trusted_hops 判断处理路径:
use_remote_address: false(默认)且xff_num_trusted_hops: 0:存在 XFF 时,Envoy 选择其中最右侧地址;不存在 XFF 时,使用直接下游连接地址。use_remote_address: false且xff_num_trusted_hops: N(N > 0):Envoy 选择 XFF 从右向左第N + 1个地址;地址数量不足时,回退到直接下游连接地址。use_remote_address: true且xff_num_trusted_hops: 0:Envoy 使用直接下游连接地址,不从 XFF 选择可信客户端地址。use_remote_address: true且xff_num_trusted_hops: N(N > 0):Envoy 选择 XFF 从右向左第N个地址;地址数量不足时,回退到直接下游连接地址。
文档通常建议前置代理设置 use_remote_address: true,内部网格代理则可能需要 false。没有拓扑上下文时,任何取值都不是普遍安全答案。如果代理数量变化,基于跳数的规则可能选错地址。应优先建立稳定且经过认证的代理路径,限制直连,并测试零跳、预期跳数和额外跳点。
Envoy 会依据边缘和保留设置生成或修改 x-request-id。该值用于关联,而不是认证。如果保留外部请求 ID,它仍受调用方影响,除非边缘边界主动替换。
分离授权裁决与执行
Envoy 1.39.1 ext_authz 过滤器把选定的请求上下文发送给外部授权服务。授权服务给出允许或拒绝裁决,Envoy 在请求路径中执行结果。过滤器顺序决定检查前是否已经存在认证元数据与转换,以及检查后还会运行哪些过滤器。
下面是有意省略外围配置的 Envoy 1.39.1 v3 API 摘录,展示“异常时关闭”的路径。实际使用时必须把它集成到该版本的完整监听器和集群配置中:
1http_filters:
2 - name: envoy.filters.http.ext_authz
3 typed_config:
4 "@type": type.googleapis.com/envoy.extensions.filters.http.ext_authz.v3.ExtAuthz
5 grpc_service:
6 envoy_grpc:
7 cluster_name: authorization_service
8 timeout: 0.5s
9 failure_mode_allow: false
10 - name: envoy.filters.http.router
11 typed_config:
12 "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Routerfailure_mode_allow 是会改变行为的布尔参数,其 protobuf 默认值为 false:
false(默认):授权服务通信错误或 HTTP 5xx 会让 Envoy 拒绝请求。true:发生这些服务错误时 Envoy 会继续放行,指标仍会记录事件。
failure_mode_allow_header_add 是另一个会改变行为的布尔参数,默认值同样为 false。取值为 false 时,Envoy 不添加异常放行标记;取值为 true 时,只有在 failure_mode_allow 也为 true,且授权服务通信失败或返回 HTTP 5xx 的情况下,Envoy 才会添加 x-envoy-auth-failure-mode-allowed: true。应在可信边缘删除调用方提供的同名请求头;如果路径可以绕过该边缘,也不能仅凭此请求头认定异常放行状态可信。
这些参数控制基础设施异常,而不是授权服务明确给出的拒绝裁决。应按每个 ext_authz 过滤器实例及其配置范围选择 failure_mode_allow,而不是把它当成路由级覆盖项:该版本的 ExtAuthzPerRoute API可以禁用过滤器或提供检查设置,但不能覆盖 failure_mode_allow。需要不同错误策略的路由必须使用分别限定作用域的过滤器配置。还要让异常放行流量可观测,绝不能把授权服务裁决标注成 Envoy 运行模式;同时限制发送给服务的请求体和请求头、保护凭据,并说明请求体被截断或缺失时是否会改变裁决。
把 xDS 交付设计成安全系统
动态配置会增加多个状态:期望、已交付、已接受、已拒绝和正在提供服务。必须分别跟踪。
- 发布前验证跨资源引用。
- 使用分批实例,不要一次更新整个数据面集群。
- 观测 ACK/NACK 以及每个代理的准确资源版本。
- 不在普通日志和 Diff 中暴露证书与密钥。
- 明确回滚恢复单个资源,还是一组一致快照。
- 限制控制面丢失时代理可继续使用旧状态的时间。
- 演练控制面携带更新但无效的配置恢复连接。
Aggregated xDS 可以改善不同资源类型之间的顺序,但平台仍需负责依赖正确性和发布。控制面 API 健康,并不能证明每个代理都接受了同一份可用路由图。
只指定一个过滤器与弹性负责人
Envoy 过滤器顺序本身就是策略。认证必须先于使用认证声明的策略;授权前修改请求头会改变策略看到的内容,授权后修改则会改变上游收到的内容;最终转换前记录日志,也可能与实际交付的请求不同。
对于重试和超时,应记录:
- 端到端和单次尝试截止时间;
- 可重试的状态、重置和连接条件;
- 方法和操作安全性;
- 客户端、网关、网格和应用的总尝试上限;
- 请求体缓冲与流式行为;
- 熔断与异常实例驱逐的交互;
- 客户端离开后的取消传播。
某一层 Envoy 可以成为合适负责人,但多个 Envoy 跳点不会自动共享全局重试预算。应在重置、超时、过载和部分响应条件下验证真实上游尝试次数。
保留应用边界
网关可以认证消费者并执行路由级权限,但在缺少权威领域状态时,不应宣称完成对象级授权。通过已认证连接转发最少的已验证上下文,再由服务判断该主体是否可以操作指定账号、订单或文档。
同样,一次成功外部授权裁决只说明当时输入和策略的计算结果,并不能证明上游会用完全相同的方式解释 path、method 或规范化后的请求头。应测试规范化过程,并把关键领域检查留在服务中。
验证清单
- 已记录准确的 Envoy、Envoy Gateway、服务网格或网关产品版本与边界。
- 只有预期监听器和管理接口可以访问。
- 静态或 xDS 配置都有经过验证的回滚产物。
- XFF 测试覆盖直连、预期代理、伪造和额外跳点路径。
- 缺失、无效、拒绝、授权服务异常与允许请求产生可区分观测。
failure_mode_allow行为与过滤器配置范围记录的威胁模型一致。- 使用实际转换后的请求头和身份元数据测试过滤器顺序。
- 每个 Envoy 与非 Envoy 跳点的重试总数与截止时间均保持有界。
- 已测试 gRPC、流式、WebSocket、大请求体与取消路径。
- 可以区分期望、已交付、已接受和正在提供服务的资源版本。
总结
Envoy 是功能丰富的代理基础,不是一种通用 API 网关产品。需要明确配置是静态的、由 Envoy Gateway 管理、由自建 xDS 控制面交付,还是由其他产品管理。随后再明确客户端 IP 路径、授权裁决、异常开放或关闭行为、过滤器顺序、重试和应用边界。只有当运维人员知道要修改哪个系统,并能证明每个代理正在使用哪份配置时,架构才算完整。
常见问题
Envoy 必须使用 xDS 吗?
不需要。Envoy 支持静态配置。xDS 适合动态管理数据面集群,但控制面和发布行为会成为平台职责。
Envoy Gateway 与 Envoy Proxy 是同一个组件吗?
不是。Envoy Proxy 是数据面代理;Envoy Gateway 是为 Envoy Proxy 下发配置的 Kubernetes Gateway API 控制面。
是否应该启用 failure_mode_allow?
只有当受影响路由的可用性与威胁模型允许在授权服务异常时放行请求,才应启用。其默认值是 false;无论选择哪条路径,都必须可观测并经过测试。需要不同处理方式的路由必须使用分别限定作用域的过滤器配置。
后续步骤
继续比较 Envoy 与其他网关运行时家族,设计外部授权边界,并使用可复现的网关基准测试方法。
