TLS 代理

本指南介绍了一些传输层安全 (TLS) 代理的概念,以及如何在 KES 服务器前面设置和配置 TLS 代理。

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 代理基础

使用 TLS 代理为一个或多个服务提供一个通用的 TLS 端点。一组客户端连接到 TLS 代理提供服务的一个端点。然后,代理将请求转发到实际的服务。

一些常见的 TLS 代理包括 HAProxyNginx

在 KES 客户端和 KES 服务器之间运行 TLS 代理有一些优缺点

优点

  • 部署多个 KES 服务器,并将它们都放在一个公共端点下,并向所有客户端提供一个 TLS 证书。
  • TLS 代理可以平衡所有 KES 服务器上的负载。
  • 负载平衡允许您根据流量和可用资源透明地添加或删除 KES 服务器。
  • TLS 代理在某种程度上将基础设施面向公众和客户端的部分与内部部分隔离开来。

缺点

  • TLS 代理可以充当任何 KES 身份 - 包括 root,如果未禁用。安全地配置 TLS 代理并使其保持最新非常重要。有关更多信息,请查看下面的 安全隐患最佳实践 部分。

  • TLS 代理由于需要额外的 TLS 握手而增加了额外的开销。但是,现代 TLS 代理使这种额外的开销对用户来说可以忽略不计。

安全影响

在您的 KES 服务器前面运行 TLS 代理会带来一些安全隐患。每个 KES 客户端在与 KES 服务器建立连接时都必须提供有效的 X.509 TLS 客户端证书。但是,当 TLS 代理位于 KES 客户端和 KES 服务器之间时,客户端无法与 KES 服务器执行 TLS 握手。相反,客户端必须与 TLS 代理执行 TLS 握手。然后,代理提取并转发客户端的 X.509 证书到 KES 服务器。

这带来了一个潜在的问题,即 KES 服务器无法确保从 TLS 代理接收到的客户端证书实际上属于与 TLS 代理执行 TLS 握手的客户端。恶意的 TLS 代理可能会向 KES 服务器谎报哪个客户端执行了 TLS 握手。

风险场景

考虑一种情况,其中客户端A连接到 TLS 代理并提供其客户端证书。在这种情况下,代理可能会向 KES 服务器撒谎并转发客户端B的证书。KES 服务器无法验证 TLS 代理是否在说实话,即哪个客户端发出了请求。KES 服务器会假设客户端B发出了请求,并应用与B关联的任何策略。TLS 代理还可以通过转发root的证书并执行任意操作来充当root身份,除非root身份已被禁用。

缓解措施

由于存在这些可能性,TLS 代理必须是系统中受信任的组件。您必须配置和正确管理代理以降低这些风险。

最佳实践

上面解释的安全影响需要一些最佳实践设置,尤其是在生产环境中。

通常,身份无法将自身分配到策略。例如,身份A无法将A分配到策略(不允许自我分配)。

但是,恶意的 TLS 代理可以规避这一点。如果有两个身份(AB),其中A可以创建策略,而B可以将A分配到策略。TLS 代理可以首先使用A创建一个具有过大权限的策略,然后使用BA分配到此新策略。现在,恶意代理可以再次充当A并执行其已授予自身访问权限的任何操作。

我们建议至少对此类环境执行以下操作。

在接受来自 TLS 代理请求的 KES 服务器上

  • 使用以下任一选项禁用root身份。
    • 将这些服务器的配置文件中的root条目设置为_
    • 在启动服务器时传递标志--root=_
  • 不要授予任何身份对危险操作(如/v1/key/delete/<key-name>)的访问权限。特别是,请将/v1/policy/write/<policy-name> API 视为危险操作。
  • 仅将 KES 服务器连接到必须为客户端/应用程序请求提供服务的 TLS 代理。对于常规管理任务(例如删除密钥),请考虑仅为执行这些任务的团队设置一个专用的 KES 服务器。将管理服务器连接到与其他服务器相同的密钥存储,但不要将管理 KES 服务器置于 TLS 代理配置之后。
  • 启用审计日志记录。配置 KES 服务器将所有 API 调用作为审计事件记录到审计日志中。

教程

配置 NGINX

以下 NGINX 配置模板将客户端请求路由到https://your.domain.com,到在localhost:7373上运行的 KES 服务器。

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://#: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 代理列表中。

  1. 获取 NGINX 的身份

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

    注意:这是 NGINX 向 KES 提供以认证自身为 TLS 代理的证书。它**必须**与您在 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.