基于Agent Identity为Agent Sandbox挂载OSS存储

更新时间:
复制 MD 格式

动态创建的 Agent Sandbox 实例需要持久化读写 OSS 存储时,为消除容器内留存长期密钥的安全隐患,可创建声明 Agent Identity 认证的 PV 卷并配合 SandboxClaim 挂载,利用临时凭据实现按需授权与 OSS 目录挂载。

背景信息

相比传统AccessKey方式将长期静态凭据挂载到Sandbox(所有Sandbox共享同一组AK/SK,权限无法收缩到实例维度),Agent Identity通过ack-agent-identity组件为每个Sandbox签发独立身份,动态获取短期STS(Security Token Service,安全令牌服务)临时凭据,实现Sandbox级别的精细化权限隔离,且Sandbox内不留存任何长期密钥。

Agent Identity采用两层权限模型:

  • 第一层:RAM角色权限(最大权限边界)。在RAM控制台创建,覆盖所有Sandbox可能访问的Bucket范围,由管理员一次性配置。

  • 第二层:CredentialProvider策略(实际生效权限)。在集群内通过CredentialProviderCR(Custom Resource,自定义资源)定义,必须是第一层的子集,支持模板函数按每个Sandbox声明的Bucket和子路径动态收缩。

每个 Sandbox 最终获取的 STS 凭据权限,为 RAM 角色权限与 CredentialProvider 策略的交集。此外,该权限的生效范围仅限于该 Sandbox 声明的 Bucket 及其子路径。

适用范围

  • 已完成Agent Sandbox的基础环境搭建。具体操作,请参见创建Agent Sandbox

  • 已在集群组件管理中安装或升级并配置以下组件:

    • ack-agent-identity ≥ v0.4.0,并勾选agentTokenDelegation配置项。

    • ack-agent-sandbox-controller ≥ v0.5.22-release.1,并勾选identityProvider配置项。

      由于组件运行及配置沙箱时需要依赖 csi-agent、csi-plugin 以及 agent-runtime 镜像,建议提前配置好镜像缓存,避免扩容耗时。
    • ack-sandbox-manager ≥ v0.6.8,并勾选identityProvider配置项。

  • 已在集群集群信息页的基本信息页签中的安全与审计区域开启RRSA OIDC,并已记录供应商URL和供应商ARN,用于后续RAM角色信任策略配置。具体操作,请参考启用RRSA功能

其他功能使用限制,可参考后文使用限制

网络放行配置

Sandbox访问Credential Provider获取STS凭据、访问OSS Endpoint读写数据均需要显式放行。使用TrafficPolicy控制Pod层出入方向流量,使用安全组控制ECS网卡层流量,二者需同步配置。

TrafficPolicy示例

参考如下TrafficPolicy,放行Sandbox Gateway、Sandbox Manager、Sandbox Controller、CoreDNSCredential Provider。TrafficPolicy的完整配置方法,请参见使用TrafficPolicy管理Agent网络访问

apiVersion: network.alibabacloud.com/v1alpha1
kind: TrafficPolicy
metadata:
  name: sandbox-policy
  namespace: default
spec:
  priority: 100
  selector:
    matchLabels:
      app: sandbox
  ingress:
    rules:
      # 允许来自Sandbox Gateway、Manager和Controller的访问
      - action: allow
        from:
          - service:
              name: sandbox-gateway
              namespace: sandbox-system
          - service:
              name: sandbox-manager
              namespace: sandbox-system
          - service:
              name: sandbox-controller-manager-webhook-service
              namespace: sandbox-system
      # 禁止其他所有来源
      - action: deny
        from:
          - cidr: 0.0.0.0/0
  egress:
    rules:
      # 禁止访问云产品元数据服务
      - action: deny
        to:
          - cidr: 100.100.100.200/32
      # 允许DNS服务,用于解析Credential Provider服务域名
      - action: allow
        to:
          - service:
              namespace: kube-system
              name: kube-dns
      # 允许访问Credential Provider服务,用于获取STS Token
      - action: allow
        to:
          - service:
              namespace: ack-agent-identity
              name: credential-provider
      # 禁止访问私有网络(防止沙箱探测内网)
      - action: deny
        to:
          - cidr: 10.0.0.0/8
      - action: deny
        to:
          - cidr: 172.16.0.0/12
      - action: deny
        to:
          - cidr: 192.168.0.0/16
      # 允许访问公网(用于OSS Endpoint等)
      - action: allow
        to:
          - cidr: 0.0.0.0/0

安全组规则示例

安全组的完整配置方法,请参见Agent Sandbox网络规划与扩容

沙箱安全组入方向规则

来源

协议/端口

用途

策略

集群托管组件网段

TCP/9090、TCP/9100、TCP/10254

Prometheus、node-exporter、Ingress metrics

允许

ICMP

健康探测

允许

TCP/49983

sandbox-controller访问沙箱Pod(envd)

允许

集群非托管组件网段

TCP/49983、TCP/49999

sandbox-managersandbox-gateway访问沙箱Pod(envd、jupyter)

允许

沙箱安全组出方向规则

目标

协议/端口

用途

策略

优先级

100.100.100.200/32

TCP/80、TCP/443

ECS元数据服务

拒绝

1

集群托管组件网段

TCP/6443

API Server

允许

1

TCP/9082

Poseidon托管组件

允许

1

TCP/53、UDP/53

内网DNS(PrivateZone)和DNS上游

允许

1

TCP/8443

Credential Provider

允许

1

集群托管或非托管组件网段

TCP/53、UDP/53

沙箱访问CoreDNS Pod

允许

1

10.0.0.0/8172.16.0.0/12192.168.0.0/16

ALL

私有网络(防止沙箱探测内网)

拒绝

10

0.0.0.0/0

ALL

公网出口(按需开放)

允许

20

完成配置后,可在Sandbox内验证到Credential Provider的连通性:

telnet credential-provider.ack-agent-identity.svc 8443

步骤一:创建RAM角色并配置信任策略

Agent Identity组件依赖RRSA(RAM Roles for Service Account,服务账户角色)扮演RAM角色获取STS临时凭据。此处配置的RAM角色权限是最大权限边界,实际每个Sandbox获得的权限还会被步骤二的CredentialProvider策略进一步收缩。建议将此角色配置为覆盖所有Sandbox可能访问的Bucket范围。

  1. 在目标集群信息页的基本信息页签中的安全与审计区域开启RRSA OIDC

    将鼠标悬浮至RRSA OIDC右侧已开启上面,即可查看提供商的URL链接和ARN信息。image

  2. 访问RAM控制台-创建角色页面,选择信任主体类型身份提供商类型,替换以下模板中的<oidc_issuer_url>提供商 URL<oidc_provider_arn>提供商 ARN

    重要

    在大规模应用场景下,为避免STS Token反复轮转,建议在角色创建完成后,在角色详情页更改最大会话时间,调整至1小时以上。

    若当前RAM用户没有创建角色或策略的相关权限,请联系阿里云账号管理员为当前用户授予AliyunRAMFullAccess等相关权限。详细操作,请参考RAM用户新增授权
    {
      "Statement": [
        {
          "Action": "sts:AssumeRole",
          "Condition": {
            "StringEquals": {
              "oidc:aud": "sts.aliyuncs.com",
              "oidc:iss": "<oidc_issuer_url>",
              "oidc:sub": [
                "system:serviceaccount:ack-agent-identity:credential-provider"
              ]
            }
          },
          "Effect": "Allow",
          "Principal": {
            "Federated": [
              "<oidc_provider_arn>"
            ]
          }
        }
      ],
      "Version": "1"
    }
    oidc:sub中的ack-agent-identity:credential-providerack-agent-identity组件使用的ServiceAccount,不支持自定义。
  3. 为该RAM角色创建自定义权限策略。根据业务需求选择只读或读写策略,将<YOUR-BUCKET-NAME>替换为实际的Bucket名称,如需覆盖多个Bucket可使用通配符或列举多个Resource。

    只读策略

    {
      "Statement": [
        {
          "Action": [
            "oss:GetObject",
            "oss:ListObjects"
          ],
          "Effect": "Allow",
          "Resource": [
            "acs:oss:*:*:<YOUR-BUCKET-NAME>",
            "acs:oss:*:*:<YOUR-BUCKET-NAME>/*"
          ]
        }
      ],
      "Version": "1"
    }

    读写策略

    {
      "Statement": [
        {
          "Action": [
            "oss:GetObject",
            "oss:PutObject",
            "oss:DeleteObject",
            "oss:AbortMultipartUpload",
            "oss:ListMultipartUploads",
            "oss:ListObjects"
          ],
          "Effect": "Allow",
          "Resource": [
            "acs:oss:*:*:<YOUR-BUCKET-NAME>",
            "acs:oss:*:*:<YOUR-BUCKET-NAME>/*"
          ]
        }
      ],
      "Version": "1"
    }
  4. 访问RAM控制台-角色页面,在RAM角色列表的操作列,单击目标角色对应的新增授权,将上一步创建的权限策略授权给该RAM角色。

步骤二:创建Agent Identity相关CR

创建AgentIdentity、CredentialProvider、AgentRole、AgentRoleBinding四种CR,完成Sandbox身份与凭据的授权绑定。

  1. 将以下YAML保存为agent-identity.yaml,定义Agent身份标识:

    apiVersion: agentidentity.alibabacloud.com/v1alpha1
    kind: AgentIdentity
    metadata:
      name: my-storage-agent            # Agent身份名称
      namespace: <YOUR-NAMESPACE>
    spec:
      description: "用于OSS存储挂载的Agent身份"
  2. 将以下YAML保存为credential-provider.yaml,定义每个Sandbox实际获得的STS凭据权限范围。CredentialProvider的策略必须是步骤一RAM角色权限的子集,超出部分不会生效。可按业务场景创建多个CredentialProvider作为不同的权限模板,本文提供只读和读写两种通用模板。

    <YOUR-RAM-ROLE-NAME>替换为步骤一创建的RAM角色名称:

    只读CredentialProvider

    apiVersion: agentidentity.alibabacloud.com/v1alpha1
    kind: CredentialProvider
    metadata:
      name: oss-ro                # 只读场景的CredentialProvider
      namespace: <YOUR-NAMESPACE>
    spec:
      type: RAM
      ram:
        source:
          provider: RRSA
          rrsa:
            roleName: <YOUR-RAM-ROLE-NAME>
            tokenValidity: 1h
            policy: |
              {
                "Statement": [
                  {
                    "Action": [
                      "oss:GetObject"
                    ],
                    "Effect": "Allow",
                    "Resource": {{ build_policy_oss_resource() }}
                  },
                  {
                    "Action": [
                      "oss:ListObjects"
                    ],
                    "Effect": "Allow",
                    "Resource": {{ build_policy_oss_resource(limit_sub_path=false) }},
                    "Condition": {
                      "StringLike": {
                        "oss:Prefix": {{ build_policy_oss_prefix_condition() }}
                      }
                    }
                  }
                ],
                "Version": "1"
              }
    ListObjectsBucket级别的操作,需通过oss:PrefixCondition限制只能列举指定子路径下的对象,否则Sandbox可列举整个Bucket的内容。

    读写CredentialProvider

    apiVersion: agentidentity.alibabacloud.com/v1alpha1
    kind: CredentialProvider
    metadata:
      name: oss-rw                      # 读写场景的CredentialProvider
      namespace: <YOUR-NAMESPACE>
    spec:
      type: RAM
      ram:
        source:
          provider: RRSA
          rrsa:
            roleName: <YOUR-RAM-ROLE-NAME>
            tokenValidity: 1h
            policy: |
              {
                "Statement": [
                  {
                    "Action": [
                      "oss:GetObject",
                      "oss:PutObject",
                      "oss:DeleteObject",
                      "oss:AbortMultipartUpload",
                      "oss:ListMultipartUploads"
                    ],
                    "Effect": "Allow",
                    "Resource": {{ build_policy_oss_resource() }}
                  },
                  {
                    "Action": [
                      "oss:ListObjects"
                    ],
                    "Effect": "Allow",
                    "Resource": {{ build_policy_oss_resource(limit_sub_path=false) }},
                    "Condition": {
                      "StringLike": {
                        "oss:Prefix": {{ build_policy_oss_prefix_condition() }}
                      }
                    }
                  }
                ],
                "Version": "1"
              }

    CredentialProvider策略中使用的模板函数由sandbox-controller根据每个Sandbox实例的挂载配置自动填充,详细说明请参见本文CredentialProvider策略模板函数说明

  3. 将以下YAML保存为agent-role.yaml,通过AgentRole引用所有存储相关的CredentialProvider,并通过AgentRoleBinding将角色绑定到Agent身份:

    apiVersion: agentidentity.alibabacloud.com/v1alpha1
    kind: AgentRole
    metadata:
      name: oss-storage-role
      namespace: <YOUR-NAMESPACE>
    spec:
      rules:
      - effect: Allow
        action: "GetResourceCredential"
        resource: "CredentialProvider/oss-ro"     # 引用只读CredentialProvider
      - effect: Allow
        action: "GetResourceCredential"
        resource: "CredentialProvider/oss-rw"           # 引用读写CredentialProvider
    ---
    apiVersion: agentidentity.alibabacloud.com/v1alpha1
    kind: AgentRoleBinding
    metadata:
      name: my-agent-oss-binding
      namespace: <YOUR-NAMESPACE>
    spec:
      agentRoleRef:
        apiGroup: agentidentity.alibabacloud.com
        kind: AgentRole
        name: oss-storage-role
      subjects:
      - authorizationType: "Agent"
        agentAuthorizationConfiguration:
          agentName: my-storage-agent                   # 与AgentIdentity name一致
  4. 依次应用以上所有YAML文件:

    kubectl apply -f agent-identity.yaml
    kubectl apply -f credential-provider.yaml
    kubectl apply -f agent-role.yaml

权限收缩示例

假设RAM角色允许访问整个my-bucket的所有操作,Sandbox ASandboxClaim声明subPath: user-a-data并引用oss-ro,Sandbox B声明subPath: user-b-data并引用oss-rw。最终Sandbox A仅能只读访问my-bucket/user-a-data/*,Sandbox B可读写my-bucket/user-b-data/*,两者互不可见。

步骤三:配置SandboxSet和创建PV

SandboxSet中启用CSIagent-runtime能力,并创建声明authType: agent-identityPersistentVolume对象。

  1. 将以下YAML保存为sandboxset.yaml(注意dnsPolicy必须为ClusterFirst),执行kubectl apply -f sandboxset.yaml进行应用:

    apiVersion: agents.kruise.io/v1alpha1
    kind: SandboxSet
    metadata:
      name: code-interpreter-ossfs-agent-identity
      namespace: default
    spec:
      replicas: 3
      runtimes:
      - name: csi                        # 启用CSI挂载能力
      - name: agent-runtime              # 注入envd等环境管理工具
      template:
        metadata:
          annotations:
            network.alibabacloud.com/wait-clusterip-ready: "*"
          labels:
            alibabacloud.com/acs: "true"
            alibabacloud.com/compute-class: agent-sandbox
            alibabacloud.com/compute-qos: default
        spec:
          automountServiceAccountToken: false
          dnsPolicy: ClusterFirst        # 必须为ClusterFirst
          containers:
          - image: registry-cn-hangzhou-vpc.ack.aliyuncs.com/acs/code-interpreter:v1.6
            imagePullPolicy: IfNotPresent
            name: sandbox
            resources:
              requests:
                cpu: "1"
                memory: 1Gi
              limits:
                cpu: "1"
                memory: 1Gi
          terminationGracePeriodSeconds: 30
    建议启用network.alibabacloud.com/wait-clusterip-ready注解,确保Sandbox执行动态存储挂载时能够准确解析到Credential Provider和存储服务端的地址。
  2. 将以下YAML保存为oss-pv.yaml,替换Bucket名称、RegionEndpoint为实际值,执行kubectl apply -f oss-pv.yaml创建资源。

    Agent Identity方式下PV无需nodePublishSecretRef,也无需创建Secret。
    apiVersion: v1
    kind: PersistentVolume
    metadata:
      labels:
        alicloud-pvname: oss-pv-sandbox-system
      name: oss-pv-sandbox-system
    spec:
      accessModes:
      - ReadWriteMany
      capacity:
        storage: 50Gi
      csi:
        driver: ossplugin.csi.alibabacloud.com
        volumeAttributes:
          authType: agent-identity                             # 固定值,声明使用Agent Identity认证
          bucket: <YOUR-BUCKET-NAME>                           # 替换为实际Bucket名称
          url: https://oss-cn-hangzhou-internal.aliyuncs.com   # 替换为实际Endpoint,建议使用HTTPS内网端点
          path: /
          otherOpts: "-o sigv4 -o region=cn-hangzhou -o umask=022 -o allow_other"  # 使用签名版本4,region按实际替换
        volumeHandle: oss-pv-sandbox-system                    # 必须与PV的名称一致。 
      persistentVolumeReclaimPolicy: Retain
      volumeMode: Filesystem
    重要

    PVvolumeAttributes创建后不可修改。如需变更鉴权方式,需删除并重建PV。此操作会导致未升级的Sandbox OSS访问失败,请谨慎操作。

    关键字段说明如下:

    参数

    说明

    authType

    固定为agent-identity,表示使用Agent Identity认证。

    bucket

    待挂载的OSS Bucket名称。

    url

    OSS访问域名(Endpoint)。内网格式:https://oss-{region}-internal.aliyuncs.com,建议使用HTTPS端点。

    otherOpts

    ossfs挂载选项。使用签名版本4时须包含-o sigv4-o region=<YOUR-REGION>

    path

    挂载点相对于Bucket根目录的路径,默认为/

步骤四:挂载存储卷

Sandbox上指定挂载配置时,需通过attributes.credentialProviderName指定使用的CredentialProvider,并通过security.agents.kruise.io/agent-name关联步骤二创建的AgentIdentity。ACS支持以下两种触发挂载的方式:

通过E2B SDK挂载

使用e2b.agents.kruise.io/csi-volume-config参数以JSON数组格式指定挂载配置。注意:security.agents.kruise.io/agent-name配置必须与AgentIdentity名称完全一致:

import json
from e2b_code_interpreter import Sandbox

sbx = Sandbox.create(
    template="code-interpreter-ossfs-agent-identity",
    timeout=600,
    metadata={
        "e2b.agents.kruise.io/csi-volume-config": json.dumps([
            {
                "pvName": "oss-pv-sandbox-system",
                "mountPath": "/data-oss",
                "subPath": "user-a-data",
                "attributes": {
                    "credentialProviderName": "oss-ro"
                }
            }
        ]),
        "security.agents.kruise.io/agent-name": "my-storage-agent"
    }
)
print(f"sandbox id: {sbx.sandbox_id}")

通过SandboxClaim挂载

SandboxClaimspec.dynamicVolumesMount字段声明挂载卷列表。注意:security.agents.kruise.io/agent-name配置必须与AgentIdentity名称完全一致。以下示例演示2个只读子目录和1个读写子目录的混合权限挂载:

apiVersion: agents.kruise.io/v1alpha1
kind: SandboxClaim
metadata:
  name: code-interpreter-claim
  namespace: default
spec:
  templateName: code-interpreter-ossfs-agent-identity     # 关联的SandboxSet名称
  replicas: 1
  claimTimeout: 5m
  ttlAfterCompleted: 15m
  annotations:
    # 必须与AgentIdentity名称完全一致
    security.agents.kruise.io/agent-name: my-storage-agent   
  dynamicVolumesMount:
  # 公司只读子目录1
  - pvName: oss-pv-sandbox-system
    mountPath: "/office-skill-readonly"
    subPath: "office-skill-readonly"
    readOnly: true
    attributes:
      credentialProviderName: "oss-ro"
  # 公司只读子目录2
  - pvName: oss-pv-sandbox-system
    mountPath: "/bu-office-skill-sub"
    subPath: "bu-office-skill-sub-readonly"
    readOnly: true
    attributes:
      credentialProviderName: "oss-ro"
  # 每个用户独立的读写子目录
  - pvName: oss-pv-sandbox-system
    mountPath: "/user-owner-dir-rw"
    subPath: "user-a-owner-dir-rw"
    attributes:
      credentialProviderName: "oss-rw"

挂载字段说明如下:

字段

类型

说明

pvName

String

PersistentVolume对象名称。

mountPath

String

挂载到容器内的目录路径,必须为一个空目录。

subPath

String

远端存储的子目录名(相对路径),可选。

readOnly

Boolean

是否以只读方式挂载,可选,默认为false

attributes.credentialProviderName

String

指定该挂载点使用的CredentialProvider名称。Agent Identity方式下必填。

步骤五:验证挂载结果

  1. Sandbox创建成功后,status变为Running即表示Claim与挂载流程已完成。查询已分配出的Sandbox:

    kubectl get sandbox -n default -l agents.kruise.io/claim-name=code-interpreter-claim

    预期输出:

    NAME                                             STATUS    AGE   CLAIMED
    code-interpreter-ossfs-agent-identity-6vh94      Running   22h   true
  2. 替换<POD_NAME>为已分配Sandbox对应的Pod名称,进入容器验证挂载目录可正常列举文件:

    kubectl exec -it <POD_NAME> -- ls /data-oss
    kubectl exec -it <POD_NAME> -- sh -c "echo 'hello agent identity' > /data-oss/test.txt && cat /data-oss/test.txt"

    ls可正常列出OSS Bucket子目录下的文件,且无法写入文件(上一步通过E2B SDK挂载仅配置只读权限),即表示Agent Identity认证的OSS存储卷挂载生效。

使用限制

  • 支持基于E2BCreate接口、休眠或唤醒功能以及原地升级镜像后的运行时存储挂载。

  • Sandbox需使用dnsPolicy: ClusterFirst以便解析Credential Provider服务域名。

  • 在配置网络策略或流量策略时,请务必放行访问OSS Endpoint、CoreDNSCredential Provider服务的出方向流量。

  • 对于单文件并发写场景,OSS的"覆盖上传"特性可能导致数据覆盖,需在应用层保障数据一致性。

  • 初次对大量文件执行readdir操作时,ossfs会一次性加载全部元信息,可能导致进程OOM(Out Of Memory,内存溢出)。建议挂载Bucket子目录而非根目录。

  • 请根据Sandbox实例规模,前往配额中心申请AssumeRoleWithOIDC接口的访问配额,避免因配额不足导致凭据获取失败。

  • CSI(Container Storage Interface,容器存储接口)动态挂载依赖特权容器和宿主机路径(hostPath: /var/run/csi)权限,会打破标准容器安全边界。请遵循以下最佳实践:仅在确需动态挂载时启用,共享存储卷默认使用只读挂载,配合TrafficPolicy和安全组做补偿控制,OSS挂载统一使用HTTPS Endpoint。

root用户挂载配置(mTLS增强模式)

在安全要求更高的场景中,业务容器支持以非root用户身份运行进程,同时通过mTLS(mutual TLS,双向TLS认证)加强Sandbox ManagerRuntime之间的通信安全。mTLS模式下,CSI Socket不再暴露给业务容器,IdToken等配置信息也被从业务容器内移除,进一步收窄攻击面。

组件版本要求

mTLS增强模式需要以下组件版本:

  • ack-agent-sandbox-controller ≥ v0.6.4-release.1

  • ack-sandbox-manager ≥ v0.6.10

  • ack-agent-identity ≥ v0.4.2

组件配置

  1. ack-agent-sandbox-controller组件配置中,勾选identityProviderenableRuntimeTLS配置项,表示开启基于mTLS的访问方式,加强安全访问链路。

  2. ack-sandbox-manager组件配置中,打开Whether to enable mTLS authentication for manager<->runtime communication.开关。

root场景使用限制

以非root用户身份在业务容器中运行进程时,存储挂载存在以下额外限制:

限制一:挂载目录必须为当前用户可写

当业务容器内进程由非root用户拉起时,所配置的按需挂载目录必须是该非root用户具有写权限的目录。例如,若以UID 1000运行,该用户可写/workspace目录,则挂载点必须设置在/workspace目录下,否则挂载将失败。

限制二:OSS存储需调整挂载点文件系统权限

root用户场景下,需要调整OSS挂载点文件系统权限,使非root用户具有OSS存量数据的文件系统权限。例如,通过将umask参数设置为000,可将文件系统权限设置为777。也可按需调整为其他权限,完整的挂载点权限配置说明请参见挂载点权限配置。建议单独创建一个PersistentVolume对象,避免与其他PV冲突。

PV配置示例如下:

apiVersion: v1
kind: PersistentVolume
metadata:
  labels:
    alicloud-pvname: oss-pv-sandbox-system
  name: oss-pv-sandbox-system
spec:
  accessModes:
  - ReadWriteMany
  capacity:
    storage: 50Gi
  csi:
    driver: ossplugin.csi.alibabacloud.com
    volumeAttributes:
      authType: agent-identity                             # 固定值,声明使用Agent Identity认证
      bucket: <YOUR-BUCKET-NAME>                           # 替换为实际Bucket名称
      url: https://oss-cn-hangzhou-internal.aliyuncs.com   # 替换为实际Endpoint,建议使用HTTPS内网端点
      path: /
      otherOpts: "-o sigv4 -o region=cn-hangzhou -o umask=000 -o allow_other"  # umask设置为000
    volumeHandle: oss-pv-sandbox-system                    # 必须与PV的名称一致
  persistentVolumeReclaimPolicy: Retain
  storageClassName: test
  volumeMode: Filesystem
重要

设置umask=000后,挂载目录的文件权限将对所有用户开放。整体的OSS挂载权限控制仍然基于Agent Identity能力,通过CredentialProvider策略将挂载点锁定在用户所配置的子目录范围内。

CredentialProvider策略模板函数说明

CredentialProviderpolicy字段支持以下专用模板函数,由sandbox-controller根据每个Sandbox实例的挂载配置自动填充,无需为每个子路径单独创建CredentialProvider。

模板函数

说明

build_policy_oss_resource()

Sandbox实例的挂载配置自动填充限制到子路径维度的Resource值。

示例结果:

[
  "acs:oss:*:*:bucket-a/sub-path-a",
  "acs:oss:*:*:bucket-a/sub-path-a/*",
  "acs:oss:*:*:bucket-b/sub-path-b",
  "acs:oss:*:*:bucket-b/sub-path-b/*"
]

build_policy_oss_resource(limit_sub_path=false)

Sandbox实例的挂载配置自动填充限制到Bucket维度的Resource值。

示例结果:

[
  "acs:oss:*:*:bucket-a",
  "acs:oss:*:*:bucket-b"
]

build_policy_oss_prefix_condition()

Sandbox实例的挂载配置自动填充限制到子路径前缀维度的oss:Prefix值。

示例结果:

[
  "sub/path/a/*",
  "sub/path/b/*"
]

常见问题

Agent Identity 挂载 OSS 的完整链路可以拆解为三层:Sandbox 通过网络访问 CredentialProvider → CredentialProvider 签发 STS Token → 使用 Token 访问 OSS。三层问题的定位方式和排查手段各不相同,可按以下顺序逐层排查。

通用排查命令

# 查看 token 签发状态
kubectl get pod <POD_NAME> -n <namespace> -o jsonpath='{.metadata.annotations.security\.agents\.kruise\.io/token-status}'

# 查看 csi-agent-sidecar 日志,定位 ossfs 具体报错
kubectl -n <namespace> logs <POD_NAME> -c csi-agent-sidecar

# 在 Sandbox 内验证与 CredentialProvider 的连通性
telnet credential-provider.ack-agent-identity.svc 8443

挂载异常时如何开启调试日志?

如果发现挂载异常,可通过临时开启ossfs调试日志定位问题。执行kubectl edit pv <PV_NAME>,在spec字段下追加以下mountOptions配置,然后重新创建Sandbox:

spec:
  mountOptions:
  - dbglevel=debug
  - curldbg

开启后,csi-agent-sidecar容器日志会全量输出,便于排查问题。问题恢复后,再次编辑PV删除上述调试选项,避免生产环境产生过多日志。

第一层:Sandbox 无法访问 CredentialProvider(网络不通)

现象

csi-agent-sidecar 或 ossfs 日志中出现网络访问超时、DNS 解析失败或连接被拒绝,典型报错如下:

"ossfs exited with error" err="signal: terminated"

Sandbox 已 Running 但挂载目录未生成,或挂载超时失败。

排查步骤

  1. 在 Sandbox 内执行 telnet credential-provider.ack-agent-identity.svc 8443,根据返回结果定位问题:

    • could not resolve host:DNS 解析问题,进入步骤 2。

    • Connection refusedConnection timed out:网络出方向被拦截,进入步骤 3。

    • 返回 Connected to ...:网络层正常,跳转至第二层排查。

  2. 排查 DNS 解析:

    • 检查 SandboxSet 定义:spec.template.spec.dnsPolicy 必须为 ClusterFirst,且 spec.template.metadata.annotations 包含 network.alibabacloud.com/wait-clusterip-ready: "*"

    • 检查 CoreDNS 状态:kubectl -n kube-system get pod -l k8s-app=kube-dns

    • 参考网络放行配置章节,确认 TrafficPolicy 已放行 kube-system/kube-dns,安全组出方向已放行 TCP/UDP 53。

  3. 排查网络出方向:

    • 参考网络放行配置章节,确认 TrafficPolicy 已放行到 ack-agent-identity/credential-provider 的出方向流量。

    • 确认安全组出方向已放行 TCP/8443 到集群托管组件网段。

第二层:CredentialProvider 服务签发 Token 失败

现象

Sandbox 已能访问 CredentialProvider 服务,但服务本身返回错误或未正常运行。csi-agent-sidecar 日志中出现 Token 获取失败报错:

Security Token refresh failed

排查步骤

  1. 参考组件配置章节,确认ack-agent-identityack-agent-sandbox-controllerack-sandbox-manager组件版本和配置勾选情况。

  2. 检查 Pod 是否携带 token-status annotation:

    kubectl get pod <POD_NAME> -n <namespace> -o jsonpath='{.metadata.annotations.security\.agents\.kruise\.io/token-status}'
    • 无输出:Sandbox 创建时未传入 security.agents.kruise.io/agent-name,或该 annotation 未透传到 Pod。请核对 SandboxClaim 的 spec.annotations 或 E2B SDK Sandbox.createmetadata 参数中是否包含 security.agents.kruise.io/agent-name

    • 有输出但状态异常:传入的 agent-name 与集群内 AgentIdentity 资源不匹配(区分大小写),请核对两者名称完全一致。

  3. 若日志出现AssumeRoleWithOIDC 相关错误,前往 RAM 控制台核对:

    • 目标角色信任策略中 oidc:iss 与集群提供商 URL 完全一致。

    • oidc:subsystem:serviceaccount:ack-agent-identity:credential-provider,不支持自定义。

    • oidc:audsts.aliyuncs.com

    • Principal.Federated 为集群提供商 ARN

    详细配置方法请参见步骤一:创建RAM角色并配置信任策略

  4. 若并发创建大量 Sandbox 时出现偶发失败,请前往配额中心申请 AssumeRoleWithOIDC 接口的访问配额。

第三层:使用 STS Token 访问 OSS 被拒绝

现象

Sandbox 已 Running,token 签发正常,但读写挂载目录中的文件时被拒绝,csi-agent-sidecar 日志出现以下报错:

Invalid Credentials(host=xxxx message=xxx.)

常见报错信息如下:

  • You have no right to access...:CredentialProvider 引用的 RAM 角色本身权限不足,最终 Token 缺少目标 Bucket 或对象的访问权限。

  • Access denied by authorizer's policy:CredentialProvider Policy 渲染问题,最终生效的 Policy 未包含请求操作所需的 Action/Resource。

排查步骤

RAM 角色权限不足

  1. 前往 RAM 控制台,找到步骤一创建的 RAM 角色,核对其权限策略是否同时包含 Bucket 级和 Object 级资源:

    "Resource": [
      "acs:oss:*:*:<YOUR-BUCKET-NAME>",
      "acs:oss:*:*:<YOUR-BUCKET-NAME>/*"
    ]
  2. 确认权限策略的 Action 覆盖 Sandbox 实际执行的操作。例如写入操作需要包含 oss:PutObject,删除操作需要包含 oss:DeleteObject,列举操作需要包含 oss:ListObjects。完整策略示例请参见步骤一:创建RAM角色并配置信任策略

  3. 确认 RAM 角色权限策略已通过新增授权成功绑定到目标角色。

CredentialProvider Policy 渲染问题

  1. 核对 CredentialProvider 的 policy 中声明的 Action 是否覆盖 Sandbox 实际执行的操作。CredentialProvider 与 RAM 角色策略的交集才是最终生效权限,任一层缺失都会导致拒绝。

  2. 若为只读挂载执行写入报错,将挂载配置中的 credentialProviderName 改为读写模板(如 oss-rw),并去掉 readOnly: true

  3. 确认 CredentialProvider 的 policy 中正确使用了模板函数:

    • 对象级操作(如 GetObjectPutObject)的 Resource 应使用 {{ build_policy_oss_resource() }}

    • Bucket 级操作(如 ListObjects)的 Resource 应使用 {{ build_policy_oss_resource(limit_sub_path=false) }},并通过 oss:Prefix Condition 限制子路径前缀。

    模板函数的详细说明请参见CredentialProvider策略模板函数说明

  4. 确认 SandboxClaim 或 E2B SDK 声明的 subPath 与预期访问路径一致。模板函数会根据每个 Sandbox 实例声明的 bucketsubPath 自动填充 Resource,声明错误会导致最终 Policy 与实际访问路径不匹配。