Envoy 秘钥发现服务(SDS)实战指南:从静态证书到动态轮换与按需下发

发布时间:2026/9/15 1:32:32
Envoy 秘钥发现服务(SDS)实战指南:从静态证书到动态轮换与按需下发 Envoy 秘钥发现服务SDS实战指南从静态证书到动态轮换与按需下发【免费下载链接】envoyCloud-native high-performance edge/middle/service proxy项目地址: https://gitcode.com/GitHub_Trending/en/envoy导读Secret Discovery ServiceSDS秘钥发现服务是 Envoy 中用于统一管理和动态下发 TLS 证书、私钥与信任 CA 的核心机制它让证书生命周期管理从手动更新 重启代理演进为中央下发 热加载。本文以 secret.rst 为主干结合 sds.proto 与 TLS 传输套接字扩展源码系统讲解 SDS 的原理、静态与远程两种配置方式、三种连接 SDS 服务器的安全方案、文件系统密钥轮换、SDS 统计指标以及按需on-demand证书下发等高级能力。读完本文你将能够独立在 Envoy 中配置 SDS 并把证书托管给 xDS/SDS 控制面。一、为什么需要 SDS集中式证书管理的价值在 Envoy 中TLS 证书等秘钥既可以直接写在 bootstrap 的static_resources.secrets中也可以通过 SDS 从远端服务器拉取。SDS 最核心的价值是简化证书管理流程。在 Kubernetes 部署场景中如果不使用 SDS证书必须以 Kubernetes Secret 形式创建并挂载进 Envoy 代理容器一旦证书过期需要更新 Secret 并重新部署代理容器这会带来滚动重启成本和短暂的流量中断。而使用 SDS 后由一个集中的 SDS 服务器向所有 Envoy 实例推送证书。证书过期时服务器只需推送新证书Envoy 会立即使用新证书无需重新部署。这套机制与 xDS 控制面天然契合也是 SPIFFE/SPIRE 生态中为工作负载下发生产身份的标准方式。1.1 证书未就绪时的阻塞语义SDS 是先决条件型资源证书获取成功之前依赖它的组件不会进入可用状态。具体语义如下下游 Listener如果监听器的服务器证书需要通过 SDS 远程获取那么在证书到位之前监听器不会被标记为 active端口也不会打开。如果 Envoy 因连接失败或响应数据错误而无法获取证书监听器会被标记为 active、端口开放但对该端口的连接将被重置。上游 Cluster类似地如果集群的客户端证书需要通过 SDS 获取证书到位前集群不会被标记为 active也不会被用于转发。若获取失败集群会被标记为 active 并可以处理请求但路由到该集群的请求会被拒绝。1.2 静态 Cluster 使用 SDS 时的定义顺序约束如果一个静态 Cluster 使用了 SDS并且需要定义一个专门的 SDS Cluster 来承载到 SDS 服务器的连接使用 Google gRPC 时除外它不需要 Envoy 侧的 Cluster那么该 SDS Cluster 必须定义在使用它的静态 Cluster 之前——因为 Envoy 在解析下游 Cluster 配置时需要先知道去哪建立 SDS 订阅连接。1.3 Envoy 与 SDS 服务器之间的安全通道Envoy 代理与 SDS 服务器之间的连接必须安全两种主流做法是Unix Domain SocketUDS把 SDS 服务器部署在同一主机上通过 UDS 通信无需走网络TLS 加认证否则连接必须启用 TLS 并进行双向认证。目前官方文档明确支持的认证凭据类型有两种mTLS此时 SDS 连接所用的客户端证书必须静态配置即不能通过 SDS 自身来获取否则会形成自举死循环AWS IAM SigV4适用于 AWS 环境下的鉴权场景。二、SDS 服务器协议SecretDiscoveryServiceSDS 服务器需要实现 gRPC 服务SecretDiscoveryService定义于 sds.proto。该服务遵循与其他 xDS 协议一致的发现语义其资源类型为envoy.extensions.transport_sockets.tls.v3.Secret对外暴露三个 RPCservice SecretDiscoveryService { option (envoy.annotations.resource).type envoy.extensions.transport_sockets.tls.v3.Secret; rpc DeltaSecrets(stream discovery.v3.DeltaDiscoveryRequest) returns (stream discovery.v3.DeltaDiscoveryResponse) { } rpc StreamSecrets(stream discovery.v3.DiscoveryRequest) returns (stream discovery.v3.DiscoveryResponse) { } rpc FetchSecrets(discovery.v3.DiscoveryRequest) returns (discovery.v3.DiscoveryResponse) { } }从源码可以确认SDS 完整复用 discovery.proto 中的DiscoveryRequest/Response与DeltaDiscoveryRequest/Response消息定义因此 SDS 与 LDS/RDS/CDS/EDS 使用完全相同的 xDS 订阅协议支持 SotW gRPC 流式、Delta 增量式与单次 Fetch。DeltaSecrets的存在也是按需证书场景推荐使用DELTA_GRPC的协议基础。生态提示SPIRE 是 SPIFFE 生产身份规范的开源参考实现可以充当 Envoy 的 SDS 服务器。借助 SPIRE 控制面Envoy 可以动态获取基于 SPIFFE ID 的证书实现工作负载身份与 TLS 的自动化绑定。三、SDS 配置模型SdsSecretConfig 详解SdsSecretConfig定义于envoy.extensions.transport_sockets.tls.v3用于指定秘钥的获取方式其核心字段语义如下字段必填语义name是秘钥名称。当sds_config为空时它指向 bootstrapstatic_resources.secrets中同名秘钥否则用于标识从 SDS 服务器订阅的秘钥名sds_config否类型为ConfigSource。为空表示走静态秘钥非空表示指定 SDS 服务器。使用远程 SDS 时api_config_source必须指定grpc_service因为 SDS仅支持 gRPCSdsSecretConfig出现在CommonTlsContext的两个字段中tls_certificate_sds_secret_configs列表通过 SDS 获取TlsCertificate证书链 私钥用于代理自身的身份validation_context_sds_secret_config单值通过 SDS 获取CertificateValidationContext信任 CA、校验规则用于验证对端证书。也就是说凡是原来用tls_certificates和validation_context静态内联的地方都可以替换为对应的*_sds_secret_config*字段把证书数据源托管给 SDS。四、示例一静态资源static_resources中定义秘钥当不需要远程下发时可以直接在 bootstrap 的static_resources.secrets中声明秘钥然后让 TLS 上下文通过名称引用。以下配置完整定义了三份秘钥并分别在集群上游与监听器下游中引用static_resources: secrets: - name: server_cert tls_certificate: certificate_chain: filename: certs/servercert.pem private_key: filename: certs/serverkey.pem - name: client_cert tls_certificate: certificate_chain: filename: certs/clientcert.pem private_key: filename: certs/clientkey.pem - name: validation_context validation_context: trusted_ca: filename: certs/cacert.pem verify_certificate_hash: E0:F3:C8:CE:5E:2E:A3:05:F0:70:1F:F5:12:E3:6E:2E:97:92:82:84:A2:28:BC:F7:73:32:D3:39:30:A1:B6:FD clusters: - connect_timeout: 0.25s load_assignment: cluster_name: local_service_tls ... transport_socket: name: envoy.transport_sockets.tls typed_config: type: type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext common_tls_context: tls_certificate_sds_secret_configs: - name: client_cert listeners: .... filter_chains: transport_socket: name: envoy.transport_sockets.tls typed_config: type: type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext common_tls_context: tls_certificate_sds_secret_configs: - name: server_cert validation_context_sds_secret_config: name: validation_context要点解析secrets静态资源中有三份秘钥client_cert、server_cert、validation_context集群配置中上游主机在其tls_certificate_sds_secret_configs里引用client_cert作为客户端证书监听器配置中filter_chains的DownstreamTlsContext用server_cert作为服务器证书用validation_context作为验证对端mTLS 场景的校验上下文本例中秘钥均来自本地文件、不走网络适合证书极少变化的固定部署。这里可以注意到一个关键点SdsSecretConfig.name在这里充当了按名索引静态秘钥的入口其数据解析逻辑与远程 SDS 场景完全相同只是数据源不同——这正是 SDS 抽象的统一之处。五、示例二从远程 SDS 服务器拉取秘钥当证书需要集中管理时把sds_config指向远程服务器即可。完整的可运行示例见 sds-source-example.yaml下面给出核心配置并逐一解读。5.1 监听器通过 Envoy gRPC 从两个 SDS 集群获取证书static_resources: listeners: - name: listener_0 address: socket_address: address: 0.0.0.0 port_value: 8000 filter_chains: - transport_socket: name: envoy.transport_sockets.tls typed_config: type: type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext common_tls_context: tls_certificate_sds_secret_configs: - name: server_cert sds_config: api_config_source: api_type: GRPC grpc_services: - envoy_grpc: cluster_name: sds_server_mtls validation_context_sds_secret_config: name: validation_context sds_config: api_config_source: api_type: GRPC grpc_services: - envoy_grpc: cluster_name: sds_server_uds监听器需要获取server_cert与validation_context两枚秘钥server_cert走Envoy gRPC通过名为sds_server_mtls的集群配了客户端证书mTLS访问 SDS 服务器validation_context走Envoy gRPC通过名为sds_server_uds的集群UDS 路径访问 SDS 服务器。5.2 SDS 连接集群一mTLS127.0.0.1:8234- name: sds_server_mtls typed_extension_protocol_options: envoy.extensions.upstreams.http.v3.HttpProtocolOptions: type: type.googleapis.com/envoy.extensions.upstreams.http.v3.HttpProtocolOptions explicit_http_config: http2_protocol_options: {} load_assignment: cluster_name: sds_server_mtls endpoints: - lb_endpoints: - endpoint: address: socket_address: address: 127.0.0.1 port_value: 8234 transport_socket: name: envoy.transport_sockets.tls typed_config: type: type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext common_tls_context: tls_certificates: - certificate_chain: filename: certs/servercert.pem private_key: filename: certs/serverkey.pem该集群通过 TCP127.0.0.1:8234连接 SDS 服务器并在UpstreamTlsContext.common_tls_context.tls_certificates中静态配置客户端证书certs/servercert.pemcerts/serverkey.pem以此满足前文所述的 mTLS 认证要求——SDS 连接自身的客户端证书不能由 SDS 提供必须静态声明。5.3 SDS 连接集群二Unix Domain Socket- name: sds_server_uds typed_extension_protocol_options: envoy.extensions.upstreams.http.v3.HttpProtocolOptions: type: type.googleapis.com/envoy.extensions.upstreams.http.v3.HttpProtocolOptions explicit_http_config: http2_protocol_options: {} load_assignment: cluster_name: sds_server_uds endpoints: - lb_endpoints: - endpoint: address: pipe: path: /tmp/uds_path该集群使用pipe.path: /tmp/uds_path指向本机 UDS 端点无需 TLS 即可安全通信是最简单、最安全的本机 SDS 接入方式。5.4 业务集群通过 Google gRPC UDS 获取客户端证书- name: example_cluster load_assignment: cluster_name: local_service_tls endpoints: - lb_endpoints: - endpoint: address: socket_address: address: 127.0.0.1 port_value: 8443 transport_socket: name: envoy.transport_sockets.tls typed_config: type: type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext common_tls_context: tls_certificate_sds_secret_configs: - name: client_cert sds_config: api_config_source: api_type: GRPC grpc_services: - google_grpc: target_uri: unix:/tmp/uds_path stat_prefix: sds_uds_server这里的client_cert使用Google gRPC直连 UDStarget_uri: unix:/tmp/uds_pathstat_prefix: sds_uds_server为其统计命名。注意api_type: GRPC表示 SotW 流式订阅client_cert通过 SDS 获取后将被用于example_cluster访问上游127.0.0.1:8443时的 mTLS 身份。5.5 小结三种接入方式对照方式SDS 集群传输认证适用场景Envoy gRPC mTLSsds_server_mtlsTCP 8234静态客户端证书双向认证远程 SDS 服务器Envoy gRPC UDSsds_server_uds/tmp/uds_path本机信任与 SDS 服务器同主机Google gRPC UDS无需 Envoy 集群unix:/tmp/uds_path本机信任业务集群直连 SDS示例中三枚秘钥client_cert、server_cert、validation_context均由 SDS 服务器提供同时注意sds_server_mtls、sds_server_uds两个 SDS 连接集群都定义在example_cluster之前正好落实了静态集群使用 SDS 时 SDS 集群必须前置定义的约束。六、示例三xDS gRPC 连接的文件系统密钥轮换为 xDS gRPC 连接管理证书存在一个自举难题Envoy 连接 xDS 服务器本身需要证书而 SDS 无法管理用于连接 SDS/xDS 服务器的证书。解决办法是把 SDS 配置放到本地文件系统通过文件监控实现免重启轮换。6.1 控制面集群SDS 配置来自文件clusters: - name: control_plane type: LOGICAL_DNS connect_timeout: 1s load_assignment: cluster_name: control_plane endpoints: - lb_endpoints: - endpoint: address: socket_address: address: controlplane port_value: 8443 typed_extension_protocol_options: envoy.extensions.upstreams.http.v3.HttpProtocolOptions: type: type.googleapis.com/envoy.extensions.upstreams.http.v3.HttpProtocolOptions explicit_http_config: http2_protocol_options: {} transport_socket: name: envoy.transport_sockets.tls typed_config: type: type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext common_tls_context: tls_certificate_sds_secret_configs: name: tls_sds sds_config: path_config_source: path: /etc/envoy/tls_certificate_sds_secret.yaml validation_context_sds_secret_config: name: validation_context_sds sds_config: path_config_source: path: /etc/envoy/validation_context_sds_secret.yaml注意这里sds_config用的是path_config_source.path指向本机文件文件中的资源以Secret消息形式组织Envoy 会用 inotify 监控文件变化自动重载证书与私钥而无需重启。6.2 客户端证书 SDS 文件/etc/envoy/tls_certificate_sds_secret.yamlresources: - type: type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.Secret name: tls_sds tls_certificate: certificate_chain: filename: /certs/sds_cert.pem private_key: filename: /certs/sds_key.pem6.3 信任 CA SDS 文件/etc/envoy/validation_context_sds_secret.yamlresources: - type: type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.Secret name: validation_context_sds validation_context: trusted_ca: filename: /certs/cacert.pem6.4 文件系统轮换机制与 watched_directory默认情况下Envoy 会监控秘钥所在目录的文件系统 move 事件。例如/foo/bar/baz/cert.pem会被在/foo/bar/baz上建立 watch。但常用的原子轮换方案是把活动路径做成符号链接symlink再整体替换此时需要把 watch 建立在证书的祖父目录上。Envoy 通过watched_directory字段显式控制监控目录该字段同时存在于TlsCertificate与CertificateValidationContext中从而支持在路径前驱目录上建立监听。带watched_directory的轮换配置resources: - type: type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.Secret name: tls_sds tls_certificate: certificate_chain: filename: /certs/current/sds_cert.pem private_key: filename: /certs/current/sds_key.pem watched_directory: path: /certsresources: - type: type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.Secret name: validation_context_sds validation_context: trusted_ca: filename: /certs/current/cacert.pem watched_directory: path: /certs/certs/current是指向当前有效证书版本的符号链接watch 建立在/certs上。执行轮换时使用原子替换先建新链接再整体替换旧链接避免中间态ln -s path to new secrets /certs/new mv -Tf /certs/new /certs/current对比两种轮换方式文件路径直接引用监控文件所在目录更新文件即触发重载symlink 方案推荐监控祖父目录通过原子mv切换链接提供更好的原子性这也解释了watched_directory为什么允许指定路径前驱。与之相对示例二 中那种SDS 配置内联在 xDS 响应里的方式在 xDS 证书更新后需要重启 Envoy才能生效而本例的文件轮换方案完全免重启。同样地远程 SDS 获取的普通 TLS 证书非连接 xDS 所需的证书也支持 gRPC SDS 在线轮换。七、SDS 相关统计指标SSL socket factory 会输出以下 SDS 相关统计均为 Counter 类型。下游监听器命名空间为listener.LISTENER_IP.server_ssl_socket_factory.*名称说明ssl_context_update_by_sdsSSL 上下文被更新经 SDS的总次数downstream_context_secrets_not_ready因 SSL 证书为空而被重置的下游连接总数上游集群命名空间为cluster.CLUSTER_NAME.client_ssl_socket_factory.*名称说明ssl_context_update_by_sdsSSL 上下文被更新经 SDS的总次数upstream_context_secrets_not_ready因 SSL 证书为空而被重置的上游连接总数此外SDS 订阅自身有一棵以sds.SECRET_NAME.*为根的统计树与所有 xDS 订阅共享的subscription_statistics体系一致其中还额外跟踪名称说明key_rotation_failed在 SDS 更新之外发生的文件系统密钥轮换失败总次数借助这些指标可以观测证书是否就绪、SDS 推送是否生效、轮换是否失败是排查端口已开但连接被重置请求被拒绝类问题时的第一手依据。八、按需On-demand证书多租户场景的按需下发默认情况下SDS 证书获取会阻塞引用它的 listener 和 cluster 的初始化。但在多租户部署中一个监听器或上游集群可能需要向对端呈现多种证书如按域名区分的 SNI 证书此时更适合先接受连接、再按需申请证书。8.1 工作方式Envoy 提供按需证书选择器扩展envoy.tls.certificate_selectors.on_demand_secret源码位于 cert_selectors/on_demand当证书不存在时它暂停 TLS 握手发起 SDS 请求收到响应后继续握手。同时配合证书映射器certificate mapper从对端 hello 消息字段如 SNI推导出秘钥名。仓库中已有的映射器包括sni、static_name、filter_state_override见 cert_mappers 目录。关键语义按需获取的证书与上下文中的常规 TLS 证书同样配置父级设置全部生效若父级 TLS 上下文发生动态更新如 validation context 的 SDS 更新按需证书上下文也会同步收到并更新因此恢复握手时使用的是最新版本的 CA 秘钥按需 SDS应配合DELTA_GRPC使用通过 xDS 响应移除资源会取消数据面对应秘钥名的订阅而普通 GRPC xDS 协议下每个映射秘钥的订阅会一直保持到父资源listener/cluster被移除注意按需证书目前不支持会话恢复session resumption因此示例中均显式设置disable_stateless_session_resumption与disable_stateful_session_resumption为true。8.2 按需证书统计除标准 SDS 订阅统计外按需证书扩展还输出以下指标下游监听器listener.stat_prefix.on_demand_secret.*上游集群cluster.stat_prefix.on_demand_secret.*名称类型说明cert_requestedCounter新建的 SDS 订阅总数cert_updatedCounter证书更新总数cert_activeGauge当前活跃的证书订阅与证书数量8.3 示例 A下游按 SNI 映射秘钥名以下DownstreamTlsContext使用 SNI 字段作为 SDS 请求中的秘钥名并在任何请求之前预取default_host证书common_tls_context: custom_tls_certificate_selector: name: on-demand typed_config: type: type.googleapis.com/envoy.extensions.transport_sockets.tls.cert_selectors.on_demand_secret.v3.Config config_source: api_config_source: api_type: DELTA_GRPC grpc_services: - envoy_grpc: cluster_name: some_xds_cluster certificate_mapper: name: sni typed_config: type: type.googleapis.com/envoy.extensions.transport_sockets.tls.cert_mappers.sni.v3.SNI default_value: default_host # Starts fetching the secret prior to any requests. prefetch_secret_names: - default_host disable_stateless_session_resumption: true disable_stateful_session_resumption: true8.4 示例 B下游单秘钥、不阻塞监听与常规 SDS TLS 证书场景类似但不阻塞 listener 就绪——连接先被接受并在 TLS 握手阶段暂停收到证书后恢复common_tls_context: custom_tls_certificate_selector: name: on-demand typed_config: type: type.googleapis.com/envoy.extensions.transport_sockets.tls.cert_selectors.on_demand_secret.v3.Config config_source: api_config_source: api_type: DELTA_GRPC grpc_services: - envoy_grpc: cluster_name: some_xds_cluster certificate_mapper: name: sni typed_config: type: type.googleapis.com/envoy.extensions.transport_sockets.tls.cert_mappers.static_name.v3.StaticName name: secret_0 prefetch_secret_names: - secret_0 disable_stateless_session_resumption: true disable_stateful_session_resumption: true8.5 示例 C上游通过 filter state 覆盖秘钥名以下UpstreamTlsContext使用动态 filter state 值由下游 listener 传入决定秘钥名common_tls_context: custom_tls_certificate_selector: name: on-demand typed_config: type: type.googleapis.com/envoy.extensions.transport_sockets.tls.cert_selectors.on_demand_secret.v3.Config config_source: api_config_source: api_type: DELTA_GRPC grpc_services: - envoy_grpc: cluster_name: some_xds_cluster certificate_mapper: name: filter_state_override typed_config: type: type.googleapis.com/envoy.extensions.transport_sockets.tls.cert_mappers.filter_state_override.v3.Config default_value: default_secret要让上述上游配置生效必须在下游 filter chain 中写入该 filter state 值例如通过set_filter_state网络过滤器name: envoy.filters.network.set_filter_state typed_config: type: type.googleapis.com/envoy.extensions.filters.network.set_filter_state.v3.Config on_new_connection: - object_key: envoy.tls.certificate_mappers.on_demand_secret factory_key: envoy.hashable_string format_string: text_format_source: inline_string: my_secret_name shared_with_upstream: ONCE该过滤器在新连接建立时写入envoy.tls.certificate_mappers.on_demand_secret对象值为my_secret_name并标记shared_with_upstream: ONCE使其可被上游 TLS 上下文读取从而实现下游决定上游证书的按需下发链路。九、选型建议与实战要点证书规模小、变更极少直接在static_resources.secrets中静态声明示例一配置最简需要集中管理、动态轮换部署 SDS 服务器并通过 gRPC 订阅示例二优先选择DELTA_GRPC同主机部署时优先用 UDS跨主机则用 mTLS且 mTLS 的客户端证书必须静态配置为 xDS/SDS 控制面连接自身准备证书采用文件系统 SDS watched_directory symlink 原子替换方案示例三免重启轮换多租户 SNI 证书使用 on-demand 证书选择器 SNI/static_name/filter_state_override 映射器配合prefetch_secret_names预取热点证书监控告警关注ssl_context_update_by_sds、*_context_secrets_not_ready、key_rotation_failed及on_demand_secret.*指标它们直接反映证书下发与轮换的健康状况。如需继续深入可阅读 sds.proto 理解 SDS 协议细节参考 sds-source-example.yaml 获取可直接运行的远程 SDS 示例并前往 source/extensions/transport_sockets/tls 查看 TLS 传输套接字、按需选择器与各证书映射器的实现源码。【免费下载链接】envoyCloud-native high-performance edge/middle/service proxy项目地址: https://gitcode.com/GitHub_Trending/en/envoy创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询