TLS Proxy

本指南說明傳輸層安全性 (TLS) Proxy 的一些概念,以及如何在 KES 伺服器前面設定和配置 TLS Proxy。

K E S C l i e n t T L S P r o x y K E S S e r v e r K M S

TLS Proxy 基礎概念

使用 TLS Proxy 為一個或多個服務提供一個通用的 TLS 端點。一組客戶端連接到由 TLS Proxy 服務的一個端點。接著,Proxy 會將請求轉發到實際的服務。

一些常見的 TLS Proxy 包括 HAProxyNginx

在您的 KES 客戶端和 KES 伺服器之間運行 TLS Proxy 有一些優缺點。

優點

  • 部署多個 KES 伺服器,並將它們全部暴露在一個通用的端點下,並為所有客戶端提供一個 TLS 憑證。
  • TLS Proxy 可以在所有 KES 伺服器之間平衡負載。
  • 負載平衡可讓您根據流量和可用資源,透明地添加或移除 KES 伺服器。
  • 在一定程度上,TLS Proxy 將您基礎架構中面向公眾、客戶端的部分與內部部分隔離開來。

缺點

  • 如果未停用,TLS Proxy 可以充當任何 KES 身分,包括 root。務必安全地設定您的 TLS Proxy 並保持其更新。有關更多資訊,請參閱下方的「安全性隱憂」和「最佳實務」章節。
  • TLS Proxy 由於額外的 TLS 交握而增加了額外開銷。然而,現代的 TLS Proxy 使這種額外開銷對使用者而言可以忽略不計。

安全性隱憂

在您的 KES 伺服器前面運行 TLS Proxy 具有一些安全性隱憂。每個 KES 客戶端在建立與 KES 伺服器的連線時,都必須出示有效的 X.509 TLS 客戶端憑證。然而,當 TLS Proxy 位於 KES 客戶端和 KES 伺服器之間時,客戶端無法與 KES 伺服器執行 TLS 交握。相反地,客戶端必須與 TLS Proxy 執行 TLS 交握。接著,Proxy 會提取並將客戶端的 X.509 憑證轉發到 KES 伺服器。

這會產生一個潛在問題,即 KES 伺服器無法確保從 TLS Proxy 收到的客戶端憑證實際上屬於與 TLS Proxy 執行 TLS 交握的客戶端。惡意的 TLS Proxy 可能會向 KES 伺服器謊報哪個客戶端已執行 TLS 交握。

風險情境

假設客戶端 A 連接到 TLS Proxy 並出示其客戶端憑證的情境。在這種情況下,Proxy 可能會向 KES 伺服器謊報,並轉發客戶端 B 的憑證。KES 伺服器無法驗證 TLS Proxy 是否說實話,說明哪個客戶端已發出請求。KES 伺服器會假設請求是由客戶端 B 發出的,並套用與 B 相關聯的任何原則。除非 root 身分已停用,否則 TLS Proxy 也可以透過轉發 root 的憑證來充當 root 身分,並執行任意操作。

緩解措施

由於這些可能性,TLS Proxy 必須是系統中受信任的元件。您必須設定並妥善管理 Proxy 以降低這些風險。

最佳實務

上述「安全性隱憂」說明需要一些最佳實務設定,尤其是在生產環境中。

一般而言,身分不能將自己指派給原則。例如,身分 A 不能將 A 指派給原則(沒有自我指派)。

然而,惡意的 TLS Proxy 可以規避此情況。如果有兩個身分 (AB),其中 A 可以建立原則,而 B 可以將 A 指派給原則。TLS Proxy 可以先使用 A 建立具有過多權限的原則,然後使用 BA 指派給這個新原則。現在,惡意 Proxy 可以再次充當 A,並執行其已授予自己存取權限的任何操作。

我們建議針對這類環境至少執行以下動作。

在接受來自 TLS Proxy 的請求的 KES 伺服器上

  • 使用以下任一選項停用 root 身分。
    • 將這些伺服器的設定檔中的 root 條目設定為 _
    • 當您啟動伺服器時,傳遞旗標 --root=_
  • 請勿授予任何身分存取危險操作的權限,例如 /v1/key/delete/<key-name>。特別是,請將 /v1/policy/write/<policy-name> API 視為危險。
  • 僅將 KES 伺服器連接到必須服務客戶端/應用程式請求的 TLS Proxy。對於例行管理工作(例如刪除金鑰),請考慮設定專門的 KES 伺服器,僅供執行這些工作的團隊使用。將管理伺服器連接到與其他伺服器相同的金鑰儲存區,但請勿將管理 KES 伺服器放在 TLS Proxy 設定之後。
  • 啟用稽核記錄。將 KES 伺服器設定為將所有 API 呼叫記錄為稽核事件到稽核記錄檔。

教學課程

設定 NGINX

以下 NGINX 設定範本會將客戶端請求路由到在 localhost:7373 上執行的 KES 伺服器 https://your.domain.com

server {
    listen         443 ssl http2;
    server_name    your.domain.com;

    proxy_buffering off;
    client_max_body_size 0;

    ssl_certificate     /path/to/the/nginx-server.crt;
    ssl_certificate_key /path/to/the/nginx-server.key;

    # You may set this to:
    # - "ssl_verify_client on"
    #    The client has to provide a TLS client certificate
    #    and it must have been issued by a CA that nginx trusts.
    #
    # - "ssl_verify_client optional"
    #    The client may provide a TLS client certificate. If it does
    #    then the certificate must haven been issued by a CA that nginx
    #    trusts. (e.g. no self-signed)
    #    However, if the client does not send a certificate then the
    #    KES server will reject the request.
    #
    # - "ssl_verify_client optional_no_ca"
    #    The client may provide a TLS client certificate. It may not
    #    be issued by a CA that nginx trusts. (e.g. self-signed)
    #    However, if the client does not send a certificate then the
    #    KES server will reject the request.
    ssl_verify_client   optional_no_ca;
        
    location / {
       # The KES server endpoint.
       proxy_pass            https://localhost:7373;
       
       # Disable response buffering. Nginx will forward any
       # response sent by the KES server directly to the client
       # instead of writing it into its cache first. 
       proxy_buffering off;

       # This requires that the KES server presents a certificate
       # signed by a (public or internal) CA that is trusted by nginx.
       # For testing/development purposes you may set this to "grpc_ssl_verify off". 
       proxy_ssl_verify       on;

       # KES requires TLSv1.3.
       proxy_ssl_protocols    TLSv1.3;

       # The nginx client certificate used to authenticate nginx
       # to the KES server. The identity of this certificate must be
       # included in the list of TLS proxies. See KES config file.
       proxy_ssl_certificate       /path/to/the/nginx-client.cert;
       # The nginx client private key used to authenticate nginx
       # to the KES server.
       proxy_ssl_certificate_key   /path/to/the/nginx-client.key;

       # The header containing the forwarded certificate of the 
       # actual KES client. This value must match the corresponding
       # entry in the kes config file.
       # Nginx will replace $ssl_client_escaped_cert with the certificate
       # presented by the KES client.
       proxy_set_header X-Tls-Client-Cert $ssl_client_escaped_cert;
    }
}

更新 KES 設定

您必須將 NGINX 身分新增至 KES 伺服器上的 TLS Proxy 清單。

  1. 取得 NGINX 的身分

    kes tool identity of </path/to/the/nginx-client.cert>
    

    注意:這是 NGINX 向 KES 出示,以將自己驗證為 TLS Proxy 的憑證。它必須符合您在 NGINX 設定檔中指定為 proxy_ssl_certificate 的路徑。

  2. 使用以下 KES 設定範本將身分新增至您的 KES 設定檔

    tls:
      proxy:
        # Add the identity of your Nginx proxy to the list of TLS proxies.
        # For example:
        identities:
        - c84cc9b91ae2399b043da7eca616048e4b4200edf2ff418d8af3835911db945d
        header:
          # The HTTP header containing the URL-escaped and PEM-encoded
          # certificate of the KES client. This must match the header Nginx
          # will set to forward the client certificate. 
          cert: X-Tls-Client-Cert
    
  3. 重新啟動 KES 伺服器。

  4. 確認您可以透過 NGINX 連線到 KES 伺服器

    • 將 KES CLI 客戶端指向您的 NGINX 端點。

      若要設定環境變數,請使用以下命令,將 your-domain.com 替換為您的 NGINX 端點的位址。

      export KES_SERVER=https://your-domain.com
      
    • 執行您的身分授權執行的操作。

      例如,若要列出所有原則

      kes policy list -k
      
       You can only perform operations if the policy attached to your identity allows them.
       If you act as the `root` identity because you have set `KES_CLIENT_TLS_CERT_FILE` to the root certificate file, then you should be able to perform any operation. 
       If you act as another identity that does not have the policy permission to list all policies then the KES server will reject the request with a `prohibited by policy` error.