TLS 认证#
Ray 可以配置为其 gRPC 通道使用 TLS。这意味着连接到 Ray head 需要一套适当的凭据,并且各种进程(客户端、head、worker)之间交换的数据将被加密(Ray 文档)。
本文档提供了生成公私密钥对和 CA 证书以配置 KubeRay 的详细说明。
警告:启用 TLS 会导致性能下降,因为相互认证和加密会带来额外的开销。测试表明,对于小型工作负载,此开销很大,而对于大型工作负载,开销相对较小。确切的开销取决于您的工作负载的性质。
先决条件#
为了充分理解本文档,强烈建议您对以下概念有深入的了解
私钥/公钥
CA(证书颁发机构)
CSR(证书签名请求)
自签名证书
这个YouTube 视频是一个不错的入门。
TL;DR#
请注意,本文档旨在支持 KubeRay 0.5.0 或更高版本。如果您使用的是较旧的 KubeRay 版本,某些说明或配置可能不适用或可能需要额外修改。
警告:请注意,
ray-cluster.tls.yaml
文件仅用于演示目的。在生产环境中,切勿将您的 CA 私钥存储在 Kubernetes Secret 中,这一点至关重要。
# Install 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.3.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
将创建
一个 Kubernetes Secret,包含 CA 的私钥 (
ca.key
) 和自签名证书 (ca.crt
) (步骤 1)一个 Kubernetes ConfigMap,包含脚本
gencert_head.sh
和gencert_worker.sh
,这些脚本允许 Ray Pod 生成私钥 (tls.key
) 和自签名证书 (tls.crt
) (步骤 2)一个 RayCluster,包含正确的 TLS 环境变量配置 (步骤 3)
Ray Pod 的证书 (tls.crt
) 使用 CA 的私钥 (ca.key
) 加密。此外,所有 Ray Pod 在 ca.crt
中都包含 CA 的公钥,这允许它们解密来自其他 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 certificate 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.key
和 ca.crt
文件已包含在 ray-cluster.tls.yaml 中指定的 Kubernetes Secret 中。
步骤 2:为 Ray Pod 创建单独的私钥和自签名证书#
在 ray-cluster.tls.yaml 中,每个 Ray Pod(包括 head 和 worker)都在其 init 容器中生成自己的私钥文件 (tls.key
) 和自签名证书文件 (tls.crt
)。我们为每个 Pod 生成单独的文件,因为 worker Pod 没有确定的 DNS 名称,并且我们无法在不同 Pod 之间使用相同的证书。
在 YAML 文件中,您会找到一个名为 tls
的 ConfigMap,其中包含两个 shell 脚本:gencert_head.sh
和 gencert_worker.sh
。这些脚本用于为 Ray head 和 worker Pod 生成私钥和自签名证书文件 (tls.key
和 tls.crt
)。用户另一种方法是将 shell 脚本直接预烘焙到 init 容器使用的 docker 镜像中,而不是依赖于 ConfigMap。
请在下方找到每个脚本执行操作的简要说明
生成一个 2048 位 RSA 私钥,并保存为
/etc/ray/tls/tls.key
。使用私钥文件 (
tls.key
) 和csr.conf
配置文件生成证书签名请求 (CSR)。使用证书颁发机构的私钥 (
ca.key
) 和先前生成的 CSR 生成自签名证书 (tls.crt
)。
gencert_head.sh
和 gencert_worker.sh
之间唯一的区别是 csr.conf
和 cert.conf
中的 [ alt_names ]
部分。worker Pod 使用 head Kubernetes Service 的完全限定域名 (FQDN) 与 head Pod 建立连接。因此,head Pod 的 [alt_names]
部分需要包含 head Kubernetes Service 的 FQDN。顺便说一下,head Pod 使用 $POD_IP
与 worker 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 与其他 Pod 看到的该 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
)。
有关如何配置 Ray 的 TLS 认证的更多信息,请参阅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.