【阅读原文】戳:Ray on ACK 最佳实践,保障 AI 数据处理/训练/推理等环境的安全部署
随着 Ray 在 AI 训练、数据处理与高并发在线推理等场景中的广泛落地,越来越多的团队选择在阿里云容器服务 Kubernetes 版(以下简称 ACK)上部署 Ray 集群,以便按需弹性扩缩、统一运维。Ray 提供了 Dashboard 以及命令行等高权限工具改善开发人员体验,如:
- Ray Dashboard(用于集群自检和调试)
- Ray Jobs 作业提交(集成 Dashboard 服务里, 提供 http 服务,提供 Ray Job 提交服务)(不是 kuberay 的 rayjob cr)
- Ray Client(用于与本地或者远程集群进行本地交互式开发)
这些组件一旦被恶意或未经授权的用户访问,将可直接在集群中执行任意代码,甚至威胁到底层 K8s 集群的稳定与云上资源的安全。
下面将从通信加密、资源隔离、权限控制、运行时防护及成本管控等多个维度,系统阐述 Ray on ACK 的安全最佳实践,帮助用户在保障开发效率的同时,最大限度降低潜在风险:
- RayCluster 通信域安全设置
- NameSpace 隔离
- ResourceQuota/ElasticQuotaTree
- RBAC
- Security context
- Head/Work Pod 镜像安全
- Request/Limit
- RRSA
- 多 RayCluster 隔离/one job one cluster
- 其他
1. RayCluster 通信域安全设置
1.1 RayCluster Head 和 Work 数据通信
若您对 RayCluster 集群内 Head 和 work pod 之间 需要 TLS 加密通信,请参考如下链接:
RayCluster 的配置参考:RayCluster TLS 配置案例 [1]
apiVersion: ray.io/v1 kind: RayCluster metadata: name: raycluster-tls spec: rayVersion: '2.9.0' # Ray head pod configuration headGroupSpec: rayStartParams: dashboard-host: '0.0.0.0' template: spec: initContainers: - name: ray-head-tls image: rayproject/ray:2.9.0 command: ["/bin/sh", "-c", "cp -R /etc/ca/tls /etc/ray && /etc/gen/tls/gencert_head.sh"] volumeMounts: - mountPath: /etc/ca/tls name: ca-tls readOnly: true - mountPath: /etc/ray/tls name: ray-tls - mountPath: /etc/gen/tls name: gen-tls-script env: - name: POD_IP valueFrom: fieldRef: fieldPath: status.podIP containers: - name: ray-head image: rayproject/ray:2.9.0 ports: - containerPort: 6379 name: gcs - containerPort: 8265 name: dashboard - containerPort: 10001 name: client lifecycle: preStop: exec: command: ["/bin/sh","-c","ray stop"] volumeMounts: - mountPath: /tmp/ray name: ray-logs - mountPath: /etc/ca/tls name: ca-tls readOnly: true - mountPath: /etc/ray/tls name: ray-tls resources: ... env: - name: RAY_USE_TLS value: "1" - name: RAY_TLS_SERVER_CERT value: "/etc/ray/tls/tls.crt" - name: RAY_TLS_SERVER_KEY value: "/etc/ray/tls/tls.key" - name: RAY_TLS_CA_CERT value: "/etc/ca/tls/ca.crt" volumes: ... workerGroupSpecs: # the pod replicas in this group typed worker - replicas: 1 minReplicas: 1 maxReplicas: 10 groupName: small-group template: spec: initContainers: # Generate worker's private key and certificate before `ray start`. - name: ray-worker-tls image: rayproject/ray:2.9.0 command: ["/bin/sh", "-c", "cp -R /etc/ca/tls /etc/ray && /etc/gen/tls/gencert_worker.sh"] volumeMounts: - mountPath: /etc/ca/tls name: ca-tls readOnly: true - mountPath: /etc/ray/tls name: ray-tls - mountPath: /etc/gen/tls name: gen-tls-script ... containers: - name: ray-worker image: rayproject/ray:2.9.0 lifecycle: preStop: exec: command: ["/bin/sh","-c","ray stop"] volumeMounts: - mountPath: /tmp/ray name: ray-logs - mountPath: /etc/ca/tls name: ca-tls readOnly: true - mountPath: /etc/ray/tls name: ray-tls ... env: # Environment variables for Ray TLS authentication. # See https://docs.ray.io/en/latest/ray-core/configure.html#tls-authentication for more details. - name: RAY_USE_TLS value: "1" - name: RAY_TLS_SERVER_CERT value: "/etc/ray/tls/tls.crt" - name: RAY_TLS_SERVER_KEY value: "/etc/ray/tls/tls.key" - name: RAY_TLS_CA_CERT value: "/etc/ca/tls/ca.crt" volumes: ...
1.2 RayClient/Ray Dashboard 内网访问
Ray 本身会无差别的执行传递给它的代码,仅在 Ray 中执行受信任的代码,Ray 开发人员在使用 RayClient 时,有责任负责业务代码的稳定,安全并妥善保管业务代码,防止泄露。
1.3 RayClient 公网访问
RayCluster GCS 服务(默认 6379 端口)若开放公网,由于 Ray 本身不提供认证鉴权服务,理论上任何能访问到公网 IP 和端口的用户,都可以使用 RayClient 向 RayCluster 无差别的提交任务,恶意或者有风险代码会导致 RayCluster down 掉,甚至会影响 K8s 集群的稳定,因此 ACK 不建议通过 RayClient 向暴露给公网的 RayCluster(默认 6379 端口)提交任务。
1.4 RayCluster 内部通信域访问限制
因为 Ray 对提交作业没有身份验证或授权。为进一步保护 Ray API 作为 Ray 安全的关键措施,使用 Kubernetes NetworkPolicy 来控制到达 Ray 组件的流量。请参考以下链接:链接
apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: ray-head-ingress spec: podSelector: matchLabels: app: ray-cluster-head policyTypes: - Ingress ingress: - from: - podSelector: {} ports: - protocol: TCP port: 6380 - from: - podSelector: {} ports: - protocol: TCP port: 8265 - from: - podSelector: {} ports: - protocol: TCP port: 10001 - from: - podSelector: matchLabels: app: ray-cluster-worker --- # Ray Head Egress apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: ray-head-egress spec: podSelector: matchLabels: app: ray-cluster-head policyTypes: - Egress egress: - to: - podSelector: matchLabels: app: redis ports: - protocol: TCP port: 6379 - to: - podSelector: matchLabels: app: ray-cluster-worker --- # Ray Worker Ingress apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: ray-worker-ingress spec: podSelector: matchLabels: app: ray-cluster-worker policyTypes: - Ingress ingress: - from: - podSelector: matchLabels: app: ray-cluster-head --- # Ray Worker Egress apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: ray-worker-egress spec: podSelector: matchLabels: app: ray-cluster-worker policyTypes: - Egress egress: - to: - podSelector: matchLabels: app: ray-cluster-head
1.5 Ray Dashboard 公网访问
每个 RayCluster 都会默认启动一个 DashBoard 服务(默认 8265 端口),此服务提供两类功能:
- 读操作:可以供开发者调试或者查看当前 RayCluster 的运行状态
- 写操作:提供/api/jobs restful api , 提供对 Ray job 的 CRUD 操作
若 RayCluster Dashboard 服务,开放到公网,由于 Ray 本身不提供认证鉴权服务,理论上任何能访问到公网 IP 和端口的用户,都可以使用 Ray DashBoard 的/api/jobs 服务,向 RayCluster 无差别的提交任务,恶意或者有风险代码会导致 RayCluster down 掉,甚至会影响 K8s 集群的稳定,因此 ACK 不建议 RayCluster 的 DashBoard 服务暴露给公网。
如果您确定要公开这些服务(Ray Dashboard、Ray GCS server),需要认识到任何可以访问相关端口的人都可以在您的 Ray Cluster 上执行任意代码 [2], 另外建议在这些服务前配置 proxy 服务,添加额外的认证授权功能或者开启公网 ACL 访问策略。
以下是 Ray on ACK 给出的一些公网访问下的相关建议配置,具体更高安全要求请参考 Ray security [3]:
- kubectl port-forward 【推荐】
- ray history server 【推荐】
- 公网 ACL/鉴权
1.5.1. kubectl port-forward
作为一种安全替代方案,您可以使用 kubectl port-forward 命令在本地机器上转发端口,从而实现对 Ray Dashboard 的安全访问。
kubectl port-forward svc/myfirst-ray-cluster-head-svc --address 0.0.0.0 8265:8265 -n ${RAY_CLUSTER_NS} Forwarding from 0.0.0.0:8265 -> 8265
在本地浏览器中访问地址 链接。
1.5.2. ACK Ray HistoryServer
Ray 原生 Dashboard 仅在 Ray 集群运行时可用,集群终止后用户无法获取历史日志与监控数据。为解决此问题,ACK 提供了 Ray 集群的 HistoryServer。HistoryServer 能够提供对于当前正在运行的以及过往已经结束的 RayCluster 的 Dashboard 的访问,提供对历史 RayCluster 的问题回溯排查能力,同时提供阿里云认证能力。其中 HistoryServer 的 Dashboard 与 Ray 自身的 DashBoard 有一致的能力, Metric 监控自动对接阿里云 Arms 监控,无需客户自己搭建 Promethus 和 Granfa,如下图所示:
具体参考:安装并使用 HistoryServer 组件_容器服务 Kubernetes 版 ACK(ACK)-阿里云帮助中心 [4]
1.5.3. ACL/鉴权
公网 ACL
容器服务控制台 找到对一个 RayCluster 的 Service,将 ServiceType 改为 LoadBalancer [公网]
找到对应 SLB 实例, 配置访问控制策略, 配置可以访问的 IP,ACL 策略建议范围更小
认证鉴权
ACK 提供了基础的认证(auth)示例。如需更高级的认证鉴权体系,可基于阿里云 RAM /自建认证系统 [5]实现,并自行实现:
- 安装 nginx ingress controller
- 创建 secret
密码、弱口令一直是数据泄露的一个大症结。因为弱口令是最容易出现的也是最容易被利用的漏洞之一。服务器的口令建议至少 8 位以上,从字符种类上增加口令复杂度,如包含大小写字母、数字和特殊字符等,并且要不定时更新口令,养成良好的安全运维习惯。设置为强密码 [6]:8 - 30 个字符,必须同时包含三项(大写字母、小写字母、数字、 ()`~!@#$%^&*_-+=|{}[]:;'<>,.?/ 中的特殊符号)
htpasswd -c auth foo k create secret generic basic-auth --from-file=auth
- 配置 ingress + basic auth
demo 例子
apiVersion: ray.io/v1 kind: RayCluster metadata: annotations: nginx.ingress.kubernetes.io/auth-type: basic nginx.ingress.kubernetes.io/auth-secret: basic-auth nginx.ingress.kubernetes.io/auth-realm: 'Authentication Required - foo' nginx.ingress.kubernetes.io/rewrite-target: /$2 name: myfirst-ray-cluster namespace: default spec: suspend: false headGroupSpec: enableIngress: true rayStartParams: dashboard-host: 0.0.0.0 num-cpus: "0" serviceType: ClusterIP template: spec: containers: ...
- 配置 nginx ingress 公网 slb ACL
通过浏览器访问公网slb ip 地址,url 为 /myfirst-ray-cluster/
如:http://*.*.*.*/myfirst-ray-cluster/
1.6. RayCluster/RayJob 配置
在 ACK 中创建的 RayCluster , 建议您不要对这些服务(如 Ray Dashboard 8265、Ray gcs 6379 服务)开放公网访问,默认使用 ClusterIP 类型的 service。
- RayCluster
关于 RayCluster HeadGroupSpec 的 serviceType 建议使用 ClusterIP
apiVersion: ray.io/v1 kind: RayCluster name: *** spec: headGroupSpec: serviceType: ClusterIP
- RayJob
spec.submissionMode 建议使用 K8sJobMode
spec.rayClusterSpec.headGroupSpec.serviceType 建议使用 ClusterIP
apiVersion: ray.io/v1 kind: RayJob metadata: name: *** spec: submissionMode: "K8sJobMode" rayClusterSpec: headGroupSpec: serviceType: ClusterIP
相关链接请参考:Configuring and Managing Ray Dashboard [7]
2. NameSpace 隔离
通过将 Ray 集群按照不同业务/团队分离到不同的名称空间中,以充分利用基于名称空间的 Kubernetes 策略,如 ResourceQuota/NetworkPolicy。
3. ResourceQuota/ElasticQuotaTree
- ResourceQuota
通过在 Ray 集群名称空间上设置资源配额限制(特别是 cpu、gpu、tpu 和内存),防止由于资源耗尽而导致的拒绝服务。
- ElasticQuotaTree
通过 ACK 提供的 ElasticQuotaTree 提供 quota 和队列更精细化管理,详细见链接:链接
4. RBAC
- 若 RayCluster 需要访问 Kubernetes 资源,建议为每个 RayCluster 配置单独的 ServiceAccount,同时最小化 ServiceAccount 的 RBAC 权限。
- 若RayCluster 不需要访问 Kubernetes 资源,则建议对使用的 ServiceAccount 设置 automountServiceAccountToken:false,以确保 KSA 的令牌对 Ray 集群 pod 不可用,因为 Ray 作业不期望调用Kubernetes API。
5. Security context
建议 RayCluster CR 中关于 Pod 的配置,遵循 Kubernetes Pod 安全标准,将 Pod 配置为使用强化设置来运行,防止特权升级,以 root 身份运行,并限制潜在的危险系统调用。
以下为相关建议的限制项:
- privilege
- root 身份运行
- 限制使用 hostPath
如果需要使用 hostPath,限制只可以挂载指定前缀的目录并将卷配置为只读
- 特权提升 allowPriviledgedEscalation
6. Head/Work pod 安全镜像
建议生产使用前,将您为 RayCluster 配置的 Ray 镜像,使用镜像安全扫描[8],保证容器应用安全交付和高效部署。
7. Request/Limit
RayCluster 在处理大作业时(数据处理/模型推理),会消耗大量的内存和 CPU, 每个容器设置请求和资源限制。没有请求或资源限制的 pod 理论上可以消耗掉主机上的所有可用资源。当有 pod 被调度到此节点上时,该节点可能会遭遇 CPU 或内存不足的情况,这可能导致 Kubelet 崩溃或从节点驱逐 pod。虽然无法完全避免这种情况的发生,但设置请求和资源限制将有助于最大程度地减少资源争夺,并降低应用程序编写不当导致资源消耗过多所带来的风险。
8. RRSA
若您的 Ray 作业中, 有访问阿里云的资源, 如 OSS 等,建议通过阿里云提供的 RRSA [9] 方案访问云产品。
不建议将 AK/SK 以明文的方式配置在 RayCluster 的环境变量中。具体请参考阿里云 AK 和账密防泄漏最佳实践 [10]。
9. 多 RayCluster 隔离/one job one cluster
可以使用 RayJob 将不同的不同作业提交在不同的 RayCluster 中运行, 充分使用容器的隔离能力,防止 RayCluster down 掉对作业的影响。在 ACK 集群中通过名称空间隔离,可以通过 RBAC 等能力,允许授权用户调用其分配的 Ray 集群,而无需访问其他 Ray 集群。
10. 其他
其他安全防范 ,请参考 ACK 安全体系 [11]。
Ray on ACK 最佳实践 参考 Ray on ACK [12]。
相关链接:
[3] Ray security
[5] 自建认证系统
[6] 强密码
[7] Configuring and Managing Ray Dashboard
[8] 镜像安全扫描
[9] RRSA
[10] 阿里云AK 和账密防泄漏最佳实践
[11] ACK 安全体系
[12] Ray on ACK
我们是阿里巴巴云计算和大数据技术幕后的核心技术输出者。
获取关于我们的更多信息~