南北向 TLS 经常被说成「网关开了 HTTPS」。这句话至少叠了两层:客户端到 Envoy 的 listener 终止,以及 Envoy 到后端的再加密。两层可以用完全不同的证书、CA 与发现方式。v1.9.0 又在 SDS 上改了 URL 形态和系统 CA 的 secret 名字——照着旧 patch 去改 xDS,会在升级后静默失配。
本文只钉这三块:Gateway listener
TLS、BackendTLSPolicy、以及 v1.9 SDS
破坏面(unix://、共享
system_ca_certificates、旧 EnvoyPatchPolicy
名)。不写云厂商证书控制台步骤。证书 warming 与 ACK≠上量外链
envoy/11。
本文是「Envoy Gateway / Gateway API」系列第 7 篇(共 16 篇)。→ 系列目录
篇目 核心内容 第 6 篇 · HTTPRoute / GRPCRoute 匹配进入 RDS 第 7 篇 · TLS / SDS listener 证书 vs 后端 TLS;v1.9 SDS 破坏面 第 8 篇 · L4 路由 TCP/UDP 升 v1 与静默跳过 上一篇:HTTPRoute / GRPCRoute · 下一篇:L4 路由
版本锚定:Envoy Gateway v1.9.0 Release Notes 的 TLS/SDS 节;Gateway API BackendTLSPolicy(Standard since v1.4.0);tag
internal/xds/translator/sds.go。v1.9 默认是共享system_ca_certificates,不是 per-resource/-ca。无伪造 SDS dump。
一、Gateway listener TLS
客户端看到的「HTTPS / TLS 入口」停在 Gateway listener。协议与 mode 决定证书出现在哪:
| Listener 协议 | TLS mode | 证书在哪 | 解密后交给谁 |
|---|---|---|---|
| HTTPS | Terminate(HTTPS 语义) | tls.certificateRefs |
HTTPRoute / GRPCRoute |
| TLS | Terminate | tls.certificateRefs |
TCPRoute(不看 SNI)或 TLSRoute(按 SNI) |
| TLS | Passthrough | listener 不终止 | TLSRoute 按 SNI 把密文交给后端 |
EG v1.9 TLS Termination for TCP 把 Terminate 再分成两种后端选择:TCPRoute 不检查 SNI,一个 listener 只能对一个后端;TLSRoute 按客户端 SNI 扇出,多条 TLSRoute 可挂同一 listener。Passthrough 任务是另一页,本篇不写菜谱。
默认证书材料是 Kubernetes Secret,类型
kubernetes.io/tls。v1.9.0
还修了几类「证看起来对、Envoy 拒」的翻译错误,避免
mergeGateways 时一张坏证拖垮同代理上的全部 TLS:
- 非规范 PEM(异常换行)会先规范化再下发,避免 BoringSSL
BAD_END_LINE。 - 证书与私钥不匹配、服务链里含过期/畸形成员:翻译期拒绝,失败隔离在引用该 Secret 的 listener;不再静默丢掉过期成员导致链被截断。
- 客户端校验用的 CA bundle 仍会丢掉过期 CA。
- ECDSA 私钥前若带
EC PARAMETERSPEM 块,不再被误拒。
同一地址端口上的 HTTPS listener,EG 会合并成一条 Envoy listener(System Design:按端口分组,兼容则折叠;不跨 Gateway 合并)。因此一张证没就绪,可以拖住同端口上所有 listener 的激活。SDS 任务页写明:Envoy 会等 SDS 证书到齐才激活 listener;外部 SDS 不可用时,共享该地址端口的连接可能被延迟或重置。这是数据面合并语义,不是「改 HTTPRoute 能修好」。
ClientTrafficPolicy 上的
TLS(客户端校验、cipher、握手超时等)作用在
下游(客户端 ↔︎ Envoy),与 BackendTLSPolicy
的上游 TLS 正交。v1.9 新增
allowExpiredCertificate、更多握手超时字段,属于第
9 篇 Policy,本篇只防止把「listener 要证」和「backend 要
CA」写成同一张工单。
v1.9.0 新能力:tls.certificateRefs
可以引用类型为 gateway.envoyproxy.io/sds 的
Secret,让 Envoy 在运行时从外部 SDS
服务器拉 listener 证书。默认关闭,需在
EnvoyGateway 配置里打开
extensionApis.enableSDSSecretRef。Secret 的
stringData 需要 url(带 scheme 的
SDS unix URL)与 secretName。文档示例:
apiVersion: v1
kind: Secret
metadata:
name: sds-cert
type: gateway.envoyproxy.io/sds
stringData:
url: unix:///var/run/secrets/workload-spiffe-uds/socket
secretName: default打开开关不会自动把 UDS 挂进 Envoy
Pod;要用 EnvoyProxy patch 挂 volume。Kubernetes RBAC /
ReferenceGrant 管的是这张「连接信息」Secret;SDS
服务器另用代理的 SDS 身份授权
secretName。文档警告:只在能创建/引用此类
Secret 的用户可信时启用。
SDS 证书对控制面是不透明的。多条合法 HTTPS listener
共享端口时,SDS 支持的 listener 默认
HTTP/1.1,以避免 HTTP/2 coalescing。同端口上、已知
DNS/SAN 与 SDS listener hostname 重叠的 inline 证书 listener
也会降到 HTTP/1.1;SDS listener 若省略
hostname(匹配全部主机),同端口所有合法 HTTPS listener
都降级。单独一条 SDS listener 仍保留 HTTP/2。受影响 listener
上报
gateway.envoyproxy.io/TLSCertificateNamesUnknown=True,reason
SDSCertificateOpaque。可用 ClientTrafficPolicy
显式配置 ALPN 覆盖默认。
二、BackendTLSPolicy
BackendTLSPolicy 是 Gateway API 对象,描述 Gateway 数据面到后端 的 TLS(文档称 backend TLS termination):后端自己持证,网关要校验并设置 SNI。它不是 listener 证书的另一种写法。
EG v1.9 Concepts 与 BackendTLSPolicy 页写该资源
GA、Standard since v1.4.0。v1.9
任务示例仍使用
apiVersion: gateway.networking.k8s.io/v1alpha3。本篇不把任务页的
alpha
字符串改写成「唯一合法版本」,只记录:控制面把该策略编译进上游
TLS;安装的 CRD 必须实际 served 该版本。若集群只装了不含
BackendTLSPolicy 的托管 CRD 子集,v1.9 会跳过对该 kind 的
watch(发行说明:OpenShift Ingress-Operator 一类),而不是用
HTTP 500 提醒——与第 8 篇 L4 的「缺 CRD
则跳过」同一类控制器存活选择。
v1.9 任务页示例使用
apiVersion: gateway.networking.k8s.io/v1alpha3,validation.caCertificateRefs
指向 ConfigMap 或 ClusterTrustBundle,hostname
作为 SNI。sectionName 在 Service 上对应
port name,在 EG Backend
上对应端口号。v1.9.0 修复:同一 backend 上带 section name
的策略优先于通配匹配。
校验材料二者取一,不能同时写:
| 字段 | 含义 |
|---|---|
caCertificateRefs |
PEM CA,引用同命名空间对象 |
wellKnownCACertificates: System |
使用实现提供的系统 CA 集合 |
hostname 不允许 IP 与通配。v1.2 起的
subjectAltNames 把 SNI 与证书身份分开(例如
SPIFFE URI SAN 不是合法 SNI)。options
是实现扩展槽。
EG 还允许在 EnvoyProxy spec.backendTLS
上改最低/最高 TLS 版本等参数。v1.9.0 修复:上游 TLS
默认最高版本从被错误限制在 1.2,改为文档所写的 TLS
1.3。任务页用 minVersion: "1.3"
演示参数覆盖。这些参数不替代
BackendTLSPolicy 的 CA/SNI。
v1.9 对 Backend 资源上的
spec.tls.wellKnownCACertificates: System 与
BackendTLSPolicy 使用同一套系统 CA SDS
机制(下一节)。不要把「系统 CA」理解成每张策略一份独立
secret——那是升级前的默认。
三、SDS unix://
这里有两套「SDS」,不要混:
- Envoy 内置 SDS:控制面把 Secret 编成
xDS
type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.Secret,经 EG 自己的 xDS 流下发。listener 的kubernetes.io/tls走这条。 - 外部 SDS 服务器:Envoy 再作为客户端,经
Unix domain socket 向另一个 SDS
进程要证。v1.9 的
gateway.envoyproxy.io/sdsSecret 与部分后端/客户端证书 IR 走这条。
v1.9.0 破坏性变更:SDS 引用 secret 的
url 必须带 unix://
scheme。v1.9.0-rc.0
曾接受裸文件系统路径,正式版拒绝。文档与 notes 给的形态是
unix:///var/run/secrets/workload-spiffe-uds/socket。
tag v1.9.0
internal/xds/translator/sds.go
与发行说明一致:从 URL 去掉 unix:// 前缀得到
pipe path,并为该 URL 建 STATIC cluster;cluster
名字带 path 的 hash
后缀,避免不同路径撞名。因此 EnvoyPatchPolicy
若匹配「由路径直接派生、无 hash」的旧 cluster
名,升级后不再命中。
同一发行说明还加了校验:UDS URL 必须形态合法——拒绝带 host
的成分、要求有 path——避免静默生成错误的 socket
地址。另修:类型
type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.Secret
的初次 fetch 超时。
翻译器在 Translate 末段调用
processSDSClusters,扫描 HTTP/TCP IR 与
BackendClusters 上的 SDS URL,去重排序后建 cluster。没有
unix:// 的 URL 在这一层不会被当成合法 UDS 去
TrimPrefix——应在更早的 API
校验被拒。本篇不编造校验错误文案。
四、共享
system_ca_certificates
v1.9.0 破坏性变更原文:所有使用
WellKnownCACertificates: System 的
BackendTLSPolicy,以及
spec.tls.wellKnownCACertificates: System 的
Backend,改为共享一份 SDS
secret,名字是
system_ca_certificates;不再为每个资源生成名为
/ -ca 的 per-resource secret。
发行说明给出的运维后果:
- 指向旧 per-resource 名或 cluster
validationContextSdsSecretConfig的 EnvoyPatchPolicy / extension server 必须改。 - 不要 patch
system_ca_certificates;若每个后端需要自定义 CA,用CACertificateRefs,不要用WellKnownCACertificates: System。 - 升级期间可能短暂中断,因为新 secret 需要 warming。
- 若要恢复旧的 per-resource 行为:打开 runtime flag
PerResourceSystemCASecret。这是 opt-out,不是 v1.9 默认。
Performance 节补充动机:共享 secret 减少
WellKnownCACertificates: System 时的 inotify
watch 数量。
v1.9 默认叙事是:系统 CA
是集群级共享信任锚,不是策略级私有文件。
把旧文档里的 per-resource -ca
当成现行默认,会在升级后对着空气 patch。
五、EnvoyPatchPolicy 旧 secret 名失效
把第三节、第四节合成一张「升级后 patch 打空」清单。这些都来自 v1.9.0 Breaking notes,不是推断:
| 旧匹配对象 | v1.9.0 之后 |
|---|---|
裸路径 SDS url |
必须 unix:// |
| 由 UDS 路径直接派生的 SDS cluster 名 | 名带 hash 后缀 |
per-resource / -ca 系统 CA secret |
共享 system_ca_certificates |
cluster validationContextSdsSecretConfig
指向旧 CA secret |
必须改目标;且不可 patch 共享 secret |
JWT jwt_authn.providers /
requirementMap 的 route 派生键 |
改为内容派生稳定名(相关但非本篇主线) |
DNS cluster 顶层 dns_refresh_rate 等 |
改到 envoy.cluster.dns typed config |
JSON patch 匹配的是生成后的 xDS 名字。IR 没变、CR 没变,只升 EG,patch 就可以从「一直成功」变成 no-op。失败表象通常不是 HTTP 500,而是:mTLS/后端校验仍用系统 CA 默认、或 listener 仍用旧证——看起来像「策略写了不生效」。第 9 篇会把 EnvoyPatchPolicy 放进五类 Policy;本篇只要求:升 v1.9 前先搜 patch 里的 secret/cluster 名。
与第 5 篇衔接:patch
失败被当成用户错误,不会挡住其余 xDS
进快照。因此「控制面已推送」可以与「你那条 patch
再也匹配不到 secret」同时为真。要用 EnvoyPatchPolicy status
/ 生成配置对账,而不是看 Gateway
Programmed。
flowchart TB
client["Client"] -->|"listener TLS"| env["Envoy"]
env -->|"BackendTLSPolicy"| be["Backend"]
subgraph listener["Listener layer"]
k8s["Secret kubernetes.io/tls"]
ext["Secret type gateway.envoyproxy.io/sds"]
end
subgraph sds["SDS"]
xds["EG xDS Secret resources"]
uds["unix:// SDS server"]
sys["shared system_ca_certificates"]
end
k8s --> xds
ext --> uds
sys --> be
xds --> env
uds --> env
图:listener 证书(inline 或外部 SDS)与后端 TLS(BackendTLSPolicy / 系统 CA)不是同一层;v1.9 系统 CA 默认共享一个 SDS secret。
六、谱系、争论与开放问题
谱系
RFC 8446 TLS 1.3(握手、证书、SNI)
→ 反向代理边缘终止 vs 到上游再加密(两段 TLS)
→ Envoy SDS:证书不当静态 bootstrap,而作为可发现资源
→ SPIFFE / 工作负载身份常用 UDS SDS(工程实践)
→ Gateway API BackendTLSPolicy:把「到 Service 的校验与 SNI」写成可移植策略
→ EG v1.9:强制 unix://、共享系统 CA secret、可选 listener SDS Secret
边缘终止解决的是「客户端如何信任网关」;BackendTLSPolicy 解决的是「网关如何信任 Pod」。SDS 解决的是「证的旋转不要重配整棵 LDS」。三件事共享「TLS」这个词,排障坐标却不同。
争论:共享系统 CA vs per-resource secret
A 侧(v1.9 默认):所有
System 信任锚本就是同一套文件;共享 SDS secret
降低 watch 与重复 warming。
B 侧(opt-out
PerResourceSystemCASecret):隔离变更半径——一张策略的
CA 更新不应触发全局 secret
warming。发行说明承认升级时可能中断。
EG 的选择是默认共享、允许 flag 退回。需要定制 CA
的后端应走 CACertificateRefs,不要 patch 共享
secret。
开放问题
- SDS 不透明证书与同端口 HTTP/2 coalescing:默认降 HTTP/1.1 是否应成为多租户 HTTPS 的 SLO 项?需要在真实 ALPN 流量下测,本文未跑。
- 外部 SDS 身份与 Kubernetes Secret 授权是否足够:能创建
gateway.envoyproxy.io/sdsSecret 的主体,等于能让 Envoy 向该 UDS 请求任意secretName。文档已警告互不信任租户应拆代理身份。 - BackendTLSPolicy 与节点级透明加密(WireGuard 等)叠层时的责任划分,见 cilium/15;本篇不引用虚构延迟百分比。
七、小结
- Listener 证书终止客户端 TLS;BackendTLSPolicy 终止(实际是发起)到后端的 TLS。两套材料、两套失败模式。
- 外部 SDS 的
url在 v1.9 必须unix://;UDS cluster 名带 hash。 WellKnownCACertificates: System默认共享system_ca_certificates;per-resource-ca不是现行默认。- EnvoyPatchPolicy 盯旧 secret/cluster 名会在升级后打空;不要 patch 共享系统 CA secret。
下一篇是版本门:TCPRoute/UDPRoute 改走 v1
之后,不升 Gateway API CRDs 会让 L4
路由静默消失。
八、参考资料
规范 / 官方文档(A)
- Envoy Gateway v1.9.0 Release Notes:SDS
unix://、共享system_ca_certificates、PerResourceSystemCASecret、enableSDSSecretRef、SDS cluster hash、PEM/链校验修复、上游 TLS 默认最高 1.3。 - TLS Termination for TCP(含 SDS Certificate References)。
- Backend TLS、BackendTLSPolicy API。
- Gateway API BackendTLSPolicy(Standard since v1.4.0):同 ns、CA 与 System 互斥、SNI hostname。
- RFC 8446:TLS 1.3。
源码(A)
envoyproxy/gatewaytag v1.9.0:internal/xds/translator/sds.go(sdsClusterNameFromURL、processSDSClusters、unix://trim)、internal/xds/translator/translator.go(processSDSClusters调用点)。
核心论文 / 规范传统
- RFC 8446 —— 证书与 SNI 的协议定义;本篇不推导握手状态机。
- Envoy Secret Discovery Service(官方协议,经 envoy/11)—— 证书作为 xDS 资源。
- SPIFFE 工作负载身份与 UDS SDS(工程实践;EG
文档示例路径含
workload-spiffe-uds)—— 外部 SDS 的典型部署,不是 EG 内置服务器。examples/sds-test-server被文档标为 E2E fixture,不是生产实现。
实验 / 工具
- 实验台账:未跑。不写握手耗时,不粘贴伪造证书 dump。
站内对照
→ 上一篇:HTTPRoute / GRPCRoute · 系列目录 · 下一篇:L4 路由
读完这篇,下一步读什么
优先读同系列或同问题的下一篇,把单篇消费变成主题集群。
【Envoy Gateway】Policy attachment:五类策略编译到哪一层,mergeType 挂错父资源会发生什么
把 SecurityPolicy、BackendTrafficPolicy、ClientTrafficPolicy、EnvoyExtensionPolicy、EnvoyPatchPolicy 钉到 IR/xDS 层;说明 v1.9 mergeType 只允许挂 xRoute,以及 Lua 默认关闭与 Patch 匹配旧 xDS 名如何表现为「策略写了不生效」。
【Envoy Gateway】南北向全景:缺口、五轴坐标系与 16 篇路线
相对 Gateway API 产品教程、Cilium 南北向边界、Envoy 消费侧与 istiod 翻译,钉清 Envoy Gateway v1.9.0 控制面内核缺口;定义附着/status、IR、xDS、Envoy 数据面、入口之后东西向五条轴,给出 16 篇阅读路线。
【Envoy Gateway】角色与附着:GatewayClass / Gateway / Route 各保证什么
钉清 Gateway API v1.6.1 角色分离在 Envoy Gateway v1.9.0 里的失败语义:parentRefs 与跨 namespace、ReferenceGrant 握手、Accepted 相对 Programmed / ResolvedRefs,以及 YAML 已 apply 仍无流量时该先查哪条条件。
【Envoy Gateway】Provider 与 watch:哪些对象进入翻译输入集
钉清 Envoy Gateway v1.9.0 Kubernetes provider 如何把 Gateway API 与引用对象收成翻译输入集、Status Manager 如何写回,以及漏 watch、缺 CRD、namespace 范围收窄时的失败表象;并核对 System Design 对 file provider 的过时表述。