密鑰探索服務 (SDS)

TLS 憑證 (密鑰) 可以在 bootstrap.static_resource secrets 中指定。但它們也可以透過密鑰探索服務 (SDS) 遠端擷取。

SDS 最重要的優點是簡化憑證管理。如果沒有此功能,在 k8s 部署中,憑證必須建立為密鑰並掛載到 Proxy 容器中。如果憑證過期,則需要更新密鑰並重新部署 Proxy 容器。透過 SDS,中央 SDS 伺服器會將憑證推送至所有 Envoy 實例。如果憑證過期,伺服器只會將新憑證推送至 Envoy 實例,Envoy 會立即使用新憑證而無需重新部署。

如果需要透過 SDS 遠端擷取監聽器伺服器憑證,則在擷取憑證之前,它不會被標記為作用中,其連接埠將不會開啟。如果 Envoy 因連線失敗或錯誤的回應資料而無法擷取憑證,監聽器將會被標記為作用中,並且連接埠將會開啟,但與該連接埠的連線將會重設。

上游叢集的處理方式類似,如果需要透過 SDS 遠端擷取叢集用戶端憑證,則在擷取憑證之前,它不會被標記為作用中且不會使用。如果 Envoy 因連線失敗或錯誤的回應資料而無法擷取憑證,叢集將會被標記為作用中,可以用來處理請求,但路由到該叢集的請求將會被拒絕。

如果靜態叢集正在使用 SDS,並且需要定義 SDS 叢集 (除非使用不需要叢集的 Google gRPC),則必須在使用它的靜態叢集之前定義 SDS 叢集。

Envoy Proxy 和 SDS 伺服器之間的連線必須安全。一種選項是在同一主機上執行 SDS 伺服器,並使用 Unix 網域套接字進行連線。否則,連線需要 Proxy 和 SDS 伺服器之間具有驗證的 TLS。目前用於驗證的憑證類型有:

  • mTLS – 在這種情況下,必須靜態組態 SDS 連線的用戶端憑證。

  • AWS IAM SigV4

SDS 伺服器

SDS 伺服器需要實作 gRPC 服務 SecretDiscoveryService。它遵循與其他 xDS 相同的協定。

注意

SPIRE (生產身分識別的 SPIFFE 規格的開放原始碼參考實作) 可以作為 Envoy 的 SDS 伺服器。請參閱 SPIRE 文件,了解如何透過 SPIFFE 和 SPIRE 組態 Envoy。

SDS 組態

SdsSecretConfig 用於指定密鑰。其 name 欄位為必填欄位。如果其 sds_config 欄位為空,則 name 欄位會指定 bootstrap static_resource secrets 中的密鑰。否則,它會將 SDS 伺服器指定為 ConfigSource。SDS 服務僅支援 gRPC,因此其 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 中監看。可以透過在 TlsCertificateCertificateValidationContext 中指定 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

在此範例中,憑證在 bootstrap static_resource 中指定,不會遠端擷取。在組態中,secrets 靜態資源具有 3 個密鑰:client_certserver_certvalidation_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 伺服器。可以使用 Unix 網域套接字路徑 /tmp/uds_path127.0.0.1:8234 (透過 mTLS) 來連線 gRPC SDS 伺服器。它提供三個密鑰:client_certserver_certvalidation_context。在組態中,叢集 example_cluster 憑證 client_cert 組態為使用 Google gRPC (使用 UDS) 與 SDS 伺服器通訊。監聽器需要從 SDS 伺服器擷取 server_certvalidation_contextserver_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

驗證 xDS 伺服器憑證的 CA 憑證套件的路徑在 SDS 組態檔案 /etc/envoy/validation_context_sds_secret.yaml 中提供

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 更新之外失敗的檔案系統金鑰輪換總數。