秘密发现服务 (SDS)
TLS 证书(秘密)可以在引导程序的 static_resource secrets 中指定。但它们也可以通过秘密发现服务 (SDS) 远程获取。
SDS 最重要的优点是简化证书管理。没有此功能,在 k8s 部署中,证书必须作为秘密创建并挂载到代理容器中。如果证书已过期,则需要更新秘密并重新部署代理容器。使用 SDS,中央 SDS 服务器会将证书推送到所有 Envoy 实例。如果证书已过期,服务器只需将新证书推送到 Envoy 实例,Envoy 将立即使用新证书,无需重新部署。
如果监听器服务器证书需要通过 SDS 远程获取,则它不会被标记为活动状态,其端口在获取证书之前不会打开。如果 Envoy 由于连接故障或错误响应数据而无法获取证书,则监听器将被标记为活动状态,端口将打开,但对该端口的连接将被重置。
上游集群以类似的方式处理,如果集群客户端证书需要通过 SDS 远程获取,则它不会被标记为活动状态,并且在获取证书之前不会使用。如果 Envoy 由于连接故障或错误响应数据而无法获取证书,则该集群将被标记为活动状态,它可以用于处理请求,但路由到该集群的请求将被拒绝。
如果静态集群使用 SDS,并且它需要定义 SDS 集群(除非使用 Google gRPC,它不需要集群),则 SDS 集群必须在使用它的静态集群之前定义。
Envoy 代理与 SDS 服务器之间的连接必须是安全的。一种选择是在同一主机上运行 SDS 服务器并使用 Unix 域套接字进行连接。否则,连接需要代理和 SDS 服务器之间的 TLS 身份验证。当前用于身份验证的凭据类型包括
mTLS – 在这种情况下,SDS 连接的客户端证书必须静态配置。
AWS IAM SigV4
SDS 服务器
SDS 服务器需要实现 gRPC 服务 SecretDiscoveryService。它遵循与其他 xDS 相同的协议。
SDS 配置
SdsSecretConfig 用于指定秘密。它的字段 _name_ 是必填字段。如果它的 _sds_config_ 字段为空,则 _name_ 字段指定引导程序 static_resource secrets 中的秘密。否则,它指定 SDS 服务器作为 ConfigSource。仅 gRPC 支持 SDS 服务,因此它的 _api_config_source_ 必须指定 grpc_service。
SdsSecretConfig 用于 CommonTlsContext 中的两个字段。第一个字段是 _tls_certificate_sds_secret_configs_,用于使用 SDS 获取 TlsCertificate。第二个字段是 _validation_context_sds_secret_config_,用于使用 SDS 获取 CertificateValidationContext。
密钥轮换
通常更倾向于通过 gRPC SDS 执行密钥轮换,但当无法或不需要这样做时(例如,在 SDS 凭据引导期间),SDS 允许在秘密引用文件系统路径时进行文件系统轮换。目前,这支持以下秘密类型
默认情况下,包含秘密的目录将被监视以进行文件系统移动事件。例如,位于 /foo/bar/baz/cert.pem
的密钥或受信任的 CA 证书将在 /foo/bar/baz
处被监视。可以通过在 TlsCertificate 和 CertificateValidationContext 中指定 _watched_directory_ 路径来明确控制被监视的目录。这允许在路径前身(例如 /foo/bar
)处建立监视;当实现常见的密钥轮换方案时,此功能非常有用。
密钥轮换的示例在 下面 提供。
示例一:static_resource
此示例展示了如何在 static_resource 中配置秘密
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
在此示例中,证书在引导程序 static_resource 中指定,它们不会远程获取。在配置中,_secrets_ 静态资源有 3 个秘密:client_cert、server_cert 和 validation_context。在集群配置中,主机之一在其 _tls_certificate_sds_secret_configs_ 中使用 client_cert。在监听器部分,其中之一在其 _tls_certificate_sds_secret_configs_ 中使用 server_cert,并在其 _validation_context_sds_secret_config_ 中使用 validation_context。
示例二:SDS 服务器
此示例展示了如何配置从远程 SDS 服务器获取的秘密
1node:
2 cluster: envoy_cluster
3 id: envoy_node
4
5static_resources:
6 listeners:
7 - name: listener_0
8 address:
9 socket_address:
10 address: 0.0.0.0
11 port_value: 8000
12 filter_chains:
13 - transport_socket:
14 name: envoy.transport_sockets.tls
15 typed_config:
16 "@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext
17 common_tls_context:
18 tls_certificate_sds_secret_configs:
19 - name: server_cert
20 sds_config:
21 api_config_source:
22 api_type: GRPC
23 grpc_services:
24 - envoy_grpc:
25 cluster_name: sds_server_mtls
26 validation_context_sds_secret_config:
27 name: validation_context
28 sds_config:
29 api_config_source:
30 api_type: GRPC
31 grpc_services:
32 - envoy_grpc:
33 cluster_name: sds_server_uds
34 clusters:
35 - name: sds_server_mtls
36 typed_extension_protocol_options:
37 envoy.extensions.upstreams.http.v3.HttpProtocolOptions:
38 "@type": type.googleapis.com/envoy.extensions.upstreams.http.v3.HttpProtocolOptions
39 explicit_http_config:
40 http2_protocol_options: {}
41 load_assignment:
42 cluster_name: sds_server_mtls
43 endpoints:
44 - lb_endpoints:
45 - endpoint:
46 address:
47 socket_address:
48 address: 127.0.0.1
49 port_value: 8234
50 transport_socket:
51 name: envoy.transport_sockets.tls
52 typed_config:
53 "@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext
54 common_tls_context:
55 tls_certificates:
56 - certificate_chain:
57 filename: certs/servercert.pem
58 private_key:
59 filename: certs/serverkey.pem
60 - name: sds_server_uds
61 typed_extension_protocol_options:
62 envoy.extensions.upstreams.http.v3.HttpProtocolOptions:
63 "@type": type.googleapis.com/envoy.extensions.upstreams.http.v3.HttpProtocolOptions
64 explicit_http_config:
65 http2_protocol_options: {}
66 load_assignment:
67 cluster_name: sds_server_uds
68 endpoints:
69 - lb_endpoints:
70 - endpoint:
71 address:
72 pipe:
73 path: /tmp/uds_path
74 - name: example_cluster
75 load_assignment:
76 cluster_name: local_service_tls
77 endpoints:
78 - lb_endpoints:
79 - endpoint:
80 address:
81 socket_address:
82 address: 127.0.0.1
83 port_value: 8443
84 transport_socket:
85 name: envoy.transport_sockets.tls
86 typed_config:
87 "@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext
88 common_tls_context:
89 tls_certificate_sds_secret_configs:
90 - name: client_cert
91 sds_config:
92 api_config_source:
93 api_type: GRPC
94 grpc_services:
95 - google_grpc:
96 target_uri: unix:/tmp/uds_path
97 stat_prefix: sds_uds_server
为了说明,上面的示例使用三种方法访问 SDS 服务器。gRPC SDS 服务器可以通过 Unix 域套接字路径 /tmp/uds_path 和 127.0.0.1:8234 通过 mTLS 访问。它提供三个秘密,client_cert、server_cert 和 validation_context。在配置中,集群 example_cluster 证书 client_cert 被配置为使用 Google gRPC 与 UDS 交谈 SDS 服务器。监听器需要从 SDS 服务器获取 server_cert 和 validation_context。server_cert 使用 Envoy gRPC 与集群 sds_server_mtls 配合使用,该集群配置为使用客户端证书通过 mTLS 与 SDS 服务器通信。validate_context 使用 Envoy gRPC 与集群 sds_server_uds 配合使用,该集群配置为使用 UDS 路径与 SDS 服务器通信。
示例三:xDS gRPC 连接的证书轮换
管理 Envoy 与 xDS 服务器之间的 xDS gRPC 连接的证书会引入引导问题:SDS 服务器无法管理连接到服务器所需的证书。
此示例展示了如何通过从文件系统获取 SDS 配置来设置 xDS 连接。证书和密钥文件将使用 inotify 进行监视,并在没有重新启动的情况下自动重新加载。相反,示例二:SDS 服务器 要求在更新后重新启动才能重新加载 xDS 证书和密钥。
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: /etc/envoy/tls_certificate_sds_secret.yaml
validation_context_sds_secret_config:
name: validation_context_sds
sds_config:
path: /etc/envoy/validation_context_sds_secret.yaml
SDS 配置文件 /etc/envoy/tls_certificate_sds_secret.yaml
中给出了客户端证书的路径,包括客户端的证书链和私钥。
resources:
- "@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.pem
SDS 配置文件 /etc/envoy/validation_context_sds_secret.yaml
中给出了用于验证 xDS 服务器证书的 CA 证书捆绑包的路径。
resources:
- "@type": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.Secret"
name: validation_context_sds
validation_context:
trusted_ca:
filename: /certs/cacert.pem
在上面的示例中,将建立对 /certs
的监视。此目录中的文件移动将触发更新。提供改进原子性的另一种常见密钥轮换方案是建立一个活动符号链接 /certs/current
并使用原子移动操作来替换符号链接。在这种情况下,监视需要在证书的祖父母目录上。Envoy 通过使用 _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: /certs
resources:
- "@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
可以使用以下方法执行秘密轮换
ln -s <path to new secrets> /certs/new && mv -Tf /certs/new /certs/current
统计信息
SSL 套接字工厂输出以下与 SDS 相关的统计信息。它们都是计数器类型。
对于下游监听器,它们位于 _listener.<LISTENER_IP>.server_ssl_socket_factory._ 命名空间中。
名称 |
描述 |
---|---|
ssl_context_update_by_sds |
已更新的 ssl 上下文的总数。 |
downstream_context_secrets_not_ready |
由于 ssl 证书为空而导致的下游连接重置的总数。 |
对于上游集群,它们位于 _cluster.<CLUSTER_NAME>.client_ssl_socket_factory._ 命名空间中。
名称 |
描述 |
---|---|
ssl_context_update_by_sds |
已更新的 ssl 上下文的总数。 |
upstream_context_secrets_not_ready |
由于 ssl 证书为空而导致的上游连接重置的总数。 |
SDS 有一个 统计信息 树,根位于 _sds.<SECRET_NAME>._ 命名空间中。此外,以下统计信息在此命名空间中跟踪
名称 |
描述 |
---|---|
key_rotation_failed |
在 SDS 更新之外失败的文件系统密钥轮换的总数。 |