TLS 认证#

Ray 可以配置为在其 gRPC 通道上使用 TLS。这意味着连接到 Ray 头节点将需要一组适当的凭证,并且各种进程(客户端、头节点、工作节点)之间交换的数据将被加密(Ray 的文档)。

本文档提供了生成公私钥对和CA证书的详细说明,用于配置KubeRay。

警告:启用 TLS 会导致性能下降,这是由于相互认证和加密带来的额外开销。测试表明,这种开销在小工作负载下很大,而在大工作负载下相对较小。确切的开销将取决于您的工作负载的性质。

先决条件#

要完全理解本文档,强烈建议您对以下概念有扎实的理解:

  • 私钥/公钥

  • CA (证书颁发机构)

  • CSR (证书签名请求)

  • 自签名证书

这个 YouTube 视频 是一个很好的开始。

太长不看#

请注意,本文档旨在支持 KubeRay 0.5.0 或更高版本。如果您使用的是 KubeRay 的旧版本,某些指令或配置可能不适用,或者可能需要额外的修改。

警告:请注意,ray-cluster.tls.yaml 文件仅用于演示目的。在生产环境中,切勿将您的 CA 私钥存储在 Kubernetes Secret 中,这一点至关重要。

# Install v1.0.0 KubeRay operator
# `ray-cluster.tls.yaml` will cover from Step 1 to Step 3

# Download `ray-cluster.tls.yaml`
curl -LO https://raw.githubusercontent.com/ray-project/kuberay/v1.0.0/ray-operator/config/samples/ray-cluster.tls.yaml

# Create a RayCluster
kubectl apply -f ray-cluster.tls.yaml

# Jump to Step 4 "Verify TLS authentication" to verify the connection.

ray-cluster.tls.yaml 将创建:

  • 包含CA的私钥(ca.key)和自签名证书(ca.crt)的Kubernetes Secret(步骤1

  • 一个包含脚本 gencert_head.shgencert_worker.sh 的 Kubernetes ConfigMap,这些脚本允许 Ray Pods 生成私钥 (tls.key) 和自签名证书 (tls.crt) (步骤 2)

  • 一个配置了适当TLS环境变量的RayCluster(步骤3

Ray Pod 的证书(tls.crt)使用 CA 的私钥(ca.key)进行加密。此外,所有 Ray Pod 都包含 CA 的公钥,该公钥包含在 ca.crt 中,这使得它们能够解密来自其他 Ray Pod 的证书。

步骤 1:为 CA 生成私钥和自签名证书#

在本文件中,使用了自签名证书,但用户也可以选择公开受信任的证书颁发机构(CA)进行TLS认证。

# Step 1-1: Generate a self-signed certificate and a new private key file for CA.
openssl req -x509 \
            -sha256 -days 3650 \
            -nodes \
            -newkey rsa:2048 \
            -subj "/CN=*.kuberay.com/C=US/L=San Francisco" \
            -keyout ca.key -out ca.crt

# Step 1-2: Check the CA's public key from the self-signed certificate.
openssl x509 -in ca.crt -noout -text

# Step 1-3
# Method 1: Use `cat $FILENAME | base64` to encode `ca.key` and `ca.crt`.
#           Then, paste the encoding strings to the Kubernetes Secret in `ray-cluster.tls.yaml`.

# Method 2: Use kubectl to encode the certifcate as Kubernetes Secret automatically.
#           (Note: You should comment out the Kubernetes Secret in `ray-cluster.tls.yaml`.)
kubectl create secret generic ca-tls --from-file=ca.key --from-file=ca.crt
  • ca.key: CA 的私钥

  • ca.crt: CA 的自签名证书

此步骤是可选的,因为 ca.keyca.crt 文件已经包含在 ray-cluster.tls.yaml 中指定的 Kubernetes Secret 中。

步骤 2:为 Ray Pods 创建单独的私钥和自签名证书#

ray-cluster.tls.yaml 中,每个 Ray Pod(包括头节点和工作节点)在其初始化容器中生成自己的私钥文件(tls.key)和自签名证书文件(tls.crt)。我们为每个 Pod 生成单独的文件,因为工作节点 Pod 没有确定的 DNS 名称,我们不能在不同的 Pod 之间使用相同的证书。

在 YAML 文件中,你会发现一个名为 tls 的 ConfigMap,其中包含两个 shell 脚本:gencert_head.shgencert_worker.sh。这些脚本用于为 Ray 头节点和工作节点 Pod 生成私钥和自签名证书文件(tls.keytls.crt)。用户的一个替代方法是直接将 shell 脚本预先打包到 init 容器使用的 docker 镜像中,而不是依赖于 ConfigMap。

请在下方找到对这些脚本中每个脚本发生情况的简要说明:

  1. 生成并保存一个2048位的RSA私钥为 /etc/ray/tls/tls.key

  2. 证书签名请求 (CSR) 是使用私钥文件 (tls.key) 和 csr.conf 配置文件生成的。

  3. 使用证书颁发机构 (ca.key) 的私钥和之前生成的 CSR,生成自签名证书 (tls.crt)。

gencert_head.shgencert_worker.sh 之间的唯一区别在于 csr.confcert.conf 文件中的 [ alt_names ] 部分。工作节点 Pod 使用头节点 Kubernetes 服务的完全限定域名 (FQDN) 与头节点 Pod 建立连接。因此,头节点 Pod 的 [alt_names] 部分需要包含头节点 Kubernetes 服务的 FQDN。顺便说一下,头节点 Pod 使用 $POD_IP 与工作节点 Pod 通信。

# gencert_head.sh
[alt_names]
DNS.1 = localhost
DNS.2 = $FQ_RAY_IP
IP.1 = 127.0.0.1
IP.2 = $POD_IP

# gencert_worker.sh
[alt_names]
DNS.1 = localhost
IP.1 = 127.0.0.1
IP.2 = $POD_IP

Kubernetes 网络模型 中,Pod 看到的自身 IP 与他人看到的相同。这就是 Ray Pod 能够自我注册证书的原因。

步骤 3:为 Ray TLS 认证配置环境变量#

要在 Ray 集群中启用 TLS 认证,请设置以下环境变量:

  • RAY_USE_TLS: 设置为1或0以启用/禁用TLS。如果设置为1,则必须设置以下所有环境变量。默认值:0。

  • RAY_TLS_SERVER_CERT: 证书文件的位置,该文件由其他端点提供以实现相互认证(即 tls.crt)。

  • RAY_TLS_SERVER_KEY: 私钥文件的位置,这是向其他端点证明你是给定证书的授权用户(即 tls.key)的加密手段。

  • RAY_TLS_CA_CERT: CA 证书文件的位置,允许 TLS 决定端点的证书是否由正确的权威机构签名(即 ca.crt)。

有关如何使用TLS认证配置Ray的更多信息,请参阅 Ray的文档

步骤 4:验证 TLS 认证#

# Log in to the worker Pod
kubectl exec -it ${WORKER_POD} -- bash

# Since the head Pod has the certificate of $FQ_RAY_IP, the connection to the worker Pods
# will be established successfully, and the exit code of the ray health-check command
# should be 0.
ray health-check --address $FQ_RAY_IP:6379
echo $? # 0

# Since the head Pod has the certificate of $RAY_IP, the connection will fail and an error
# message similar to the following will be displayed: "Peer name raycluster-tls-head-svc is
# not in peer certificate".
ray health-check --address $RAY_IP:6379

# If you add `DNS.3 = $RAY_IP` to the [alt_names] section in `gencert_head.sh`,
# the head Pod will generate the certificate of $RAY_IP.
#
# For KubeRay versions prior to 0.5.0, this step is necessary because Ray workers in earlier
# versions use $RAY_IP to connect with Ray head.