Ray on ACK 最佳实践,保障 AI 数据处理/训练/推理等环境的安全部署

简介: 本文将从通信加密、资源隔离、权限控制、运行时防护及成本管控等多个维度,系统阐述 Ray on ACK 的安全最佳实践,帮助用户在保障开发效率的同时,最大限度降低潜在风险。

【阅读原文】戳: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 集群的稳定与云上资源的安全。

 

image.png

 

下面将从通信加密、资源隔离、权限控制、运行时防护及成本管控等多个维度,系统阐述 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 公网访问

 

image.png

 

每个 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

 


在本地浏览器中访问地址 链接

 

image.png

 

 

1.5.2.  ACK Ray HistoryServer

 

Ray 原生 Dashboard 仅在 Ray 集群运行时可用,集群终止后用户无法获取历史日志与监控数据。为解决此问题,ACK 提供了 Ray 集群的 HistoryServer。HistoryServer 能够提供对于当前正在运行的以及过往已经结束的 RayCluster 的 Dashboard 的访问,提供对历史 RayCluster 的问题回溯排查能力,同时提供阿里云认证能力。其中 HistoryServer 的 Dashboard 与 Ray 自身的 DashBoard 有一致的能力, Metric 监控自动对接阿里云 Arms 监控,无需客户自己搭建 Promethus 和 Granfa,如下图所示:

 

image.png image.png

image.png


具体参考:安装并使用 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/

 

image.png

 

 

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 集群。

 

image.png

 

 

10. 其他

 

其他安全防范 ,请参考 ACK 安全体系 [11]

Ray on ACK 最佳实践 参考 Ray on ACK [12]

 

相关链接:

 

[1] RayCluster TLS 配置案例

 

[2] Ray Cluster 上执行任意代码

 

[3] Ray security

 

[4]安装并使用 HistoryServer 组件

 

[5] 自建认证系统

 

[6] 强密码

 

[7] Configuring and Managing Ray Dashboard

 

[8] 镜像安全扫描

 

[9] RRSA

 

[10] 阿里云AK 和账密防泄漏最佳实践

 

[11] ACK 安全体系

 

[12] Ray on ACK




我们是阿里巴巴云计算和大数据技术幕后的核心技术输出者。

欢迎关注 “阿里云基础设施”同名微信微博知乎

获取关于我们的更多信息~

作者介绍
目录