使用 Agent Sandbox 隔离 AI 代码执行

您可以部署一个开发者环境,以便在 Google Kubernetes Engine (GKE) 集群上使用 Agent Sandbox Python 客户端。此设置有助于您在沙盒化的 Python 环境中隔离不受信任的代码,从而安全地执行和测试 AI 生成的代码。这种隔离对于保护系统免受 AI 生成代码中潜在漏洞的侵害、提高开发速度和确保安全部署至关重要。如需大致了解 Agent Sandbox 功能如何隔离不受信任的 AI 生成的代码,请参阅关于 GKE Agent Sandbox

费用

在 GKE 中,使用 Agent Sandbox 无需额外付费。 GKE 定价适用于您创建的资源。

准备工作

  1. 在 Cloud de Confiance 控制台的项目选择器页面上,选择或创建 Cloud de Confiance 项目。

    选择或创建项目所需的角色

    • 选择项目:选择项目不需要特定的 IAM 角色,您可以选择已获授角色的任何项目。
    • 创建项目:如需创建项目,您需要拥有 Project Creator 角色 (roles/resourcemanager.projectCreator),该角色包含 resourcemanager.projects.create 权限。了解如何授予角色

    转到“项目选择器”

  2. 验证是否已为您的 Cloud de Confiance 项目启用结算功能

  3. 启用 Artifact Registry 和 Kubernetes Engine API。

    启用 API 所需的角色

    如需启用 API,您需要拥有 Service Usage Admin IAM 角色 (roles/serviceusage.serviceUsageAdmin),该角色包含 serviceusage.services.enable 权限。了解如何授予角色

    启用 API

  4. 在 Cloud de Confiance 控制台中,激活 Cloud Shell。

    激活 Cloud Shell

  5. 验证您是否拥有完成本指南所需的权限
  6. 您必须拥有一个启用了代理沙盒功能的 GKE 集群。如果您没有,请按照在 GKE 上启用代理 Sandbox 中的说明创建新集群或更新现有集群。

所需的角色

如需获得创建和管理沙盒所需的权限,请让您的管理员为您授予项目的 Kubernetes Engine Admin (roles/container.admin) IAM 角色。 如需详细了解如何授予角色,请参阅管理对项目、文件夹和组织的访问权限

您也可以通过自定义角色或其他预定义角色来获取所需的权限。

定义环境变量

为了简化您在本文档中运行的命令,您可以在 Cloud Shell 中设置环境变量。在 Cloud Shell 中,运行以下命令来定义以下有用的环境变量:

export PROJECT_ID=$(gcloud config get project)
export CLUSTER_NAME="agent-sandbox-cluster"
export LOCATION="us-central1"
export NODE_POOL_NAME="agent-sandbox-node-pool"
export MACHINE_TYPE="e2-standard-2"

以下是对这些环境变量的说明:

  • PROJECT_ID:当前 Cloud de Confiance by S3NS 项目的 ID。定义此变量有助于确保所有资源(例如 GKE 集群)都在正确的项目中创建。
  • CLUSTER_NAME:GKE 集群的名称,例如 agent-sandbox-cluster
  • LOCATION:GKE 集群所在的 Cloud de Confiance by S3NS 区域或可用区。如果您使用的是 Autopilot 集群,请将此值设置为区域(例如 us-central1);如果您使用的是 Standard 集群,请将此值设置为可用区(例如 us-central1-a)。
  • NODE_POOL_NAME:将运行沙盒化工作负载的节点池的名称,例如 agent-sandbox-node-pool
  • MACHINE_TYPE:节点池中节点的机器类型,例如 e2-standard-2。如需详细了解不同的机器系列以及如何在不同选项之间进行选择,请参阅机器家族资源和比较指南

部署沙盒环境

本部分介绍了如何创建沙盒蓝图 (SandboxTemplate)、部署必要的网络路由器,以及安装用于与沙盒交互的 Python 客户端。

建议使用 Agentic Sandbox Python 客户端来创建沙盒并与之交互。 此客户端提供了一个接口,可简化沙盒的整个生命周期,从创建到清理。这是一个 Python 库,可用于以程序化方式创建、使用和删除沙盒。

客户端使用沙盒路由器作为所有流量的中央入口点。在本文档所述的示例中,客户端使用命令 kubectl port-forward 创建通往此路由器的隧道,这样您就不需要公开任何公共 IP 地址。请注意,使用 kubectl port-forward 并不是一种安全的解决方案,应仅限于开发环境中使用。

创建 SandboxTemplateSandboxWarmPool

现在,您可以通过创建 SandboxTemplateSandboxWarmPool 资源来定义沙盒的配置。SandboxTemplate 充当可重用的蓝图,供 Agent Sandbox 控制器用于创建一致的预配置沙盒环境。SandboxWarmPool 资源有助于确保指定数量的预热 Pod 始终处于运行状态,并随时可供声明。预热沙盒是已初始化的正在运行的 Pod。这种预初始化可让新沙盒在不到一秒的时间内创建完成,并避免启动常规沙盒时出现的启动延迟:

  1. 在 Cloud Shell 中,创建一个名为 sandbox-template-and-pool.yaml 的文件,其中包含以下内容:

    apiVersion: extensions.agents.x-k8s.io/v1alpha1
    kind: SandboxTemplate
    metadata:
      name: python-runtime-template
      namespace: default
    spec:
      podTemplate:
        metadata:
          labels:
            sandbox: python-sandbox-example
        spec:
          runtimeClassName: gvisor
          automountServiceAccountToken: false # Required
          securityContext:
            runAsNonRoot: true # Required
          nodeSelector:
            sandbox.gke.io/runtime: gvisor # Required
          tolerations:
          - key: "sandbox.gke.io/runtime"
            value: "gvisor"
            effect: "NoSchedule" # Required
          containers:
          - name: python-runtime
            image: registry.k8s.io/agent-sandbox/python-runtime-sandbox:v0.1.0
            ports:
            - containerPort: 8888
            readinessProbe:
              httpGet:
                path: "/"
                port: 8888
              initialDelaySeconds: 0
              periodSeconds: 1
            resources:
              requests:
                cpu: "250m"
                memory: "512Mi"
              limits:
                cpu: "500m"
                memory: "1Gi" # Required
            securityContext:
              capabilities:
                drop: ["ALL"] # Required
          restartPolicy: "OnFailure"
    ---
    apiVersion: extensions.agents.x-k8s.io/v1alpha1
    kind: SandboxWarmPool
    metadata:
      name: python-sandbox-warmpool
      namespace: default
    spec:
      replicas: 2
      sandboxTemplateRef:
        name: python-runtime-template
    
  2. 应用 SandboxTemplateSandboxWarmPool 清单:

    kubectl apply -f sandbox-template-and-pool.yaml
    

部署沙盒路由器

您将用于创建沙盒环境并与之交互的 Python 客户端使用名为“沙盒路由器”的组件与沙盒进行通信。

在此示例中,您将使用客户端的开发者模式进行测试。此模式适用于本地开发,并使用 kubectl port-forward 命令在本地机器与集群中运行的沙盒路由器服务之间建立直接隧道。这种隧道方法无需使用公共 IP 地址或复杂的入站流量设置,并简化了从本地环境与沙盒的交互。

请按照以下步骤部署沙盒路由器:

  1. 在 Cloud Shell 中,创建一个名为 sandbox-router.yaml 的文件,其中包含以下内容:

    # A ClusterIP Service to provide a stable endpoint for the router pods.
    apiVersion: v1
    kind: Service
    metadata:
      name: sandbox-router-svc
      namespace: default
    spec:
      type: ClusterIP
      selector:
        app: sandbox-router
      ports:
      - name: http
        protocol: TCP
        port: 8080 # The port the service will listen on
        targetPort: 8080 # The port the router container listens on (from the sandbox_router/Dockerfile)
    ---
    # The Deployment to manage and run the router pods.
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: sandbox-router-deployment
      namespace: default
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: sandbox-router
      template:
        metadata:
          labels:
            app: sandbox-router
        spec:
          # Ensure pods are spread across different zones for HA
          topologySpreadConstraints:
            - maxSkew: 1
              topologyKey: topology.kubernetes.io/zone
              whenUnsatisfiable: ScheduleAnyway
              labelSelector:
                matchLabels:
                  app: sandbox-router
          containers:
          - name: router
            image: us-central1-docker.pkg.dev/k8s-staging-images/agent-sandbox/sandbox-router:latest-main
            ports:
            - containerPort: 8080
            readinessProbe:
              httpGet:
                path: /healthz
                port: 8080
              initialDelaySeconds: 5
              periodSeconds: 5
            livenessProbe:
              httpGet:
                path: /healthz
                port: 8080
              initialDelaySeconds: 10
              periodSeconds: 10
            resources:
              requests:
                cpu: "100m"
                memory: "512Mi"
              limits:
                cpu: "1000m"
                memory: "1Gi"
          securityContext:
            runAsUser: 1000
            runAsGroup: 1000
    
  2. 应用清单以将路由器部署到集群:

    kubectl apply -f sandbox-router.yaml
    
  3. 验证沙盒路由器部署是否正常运行:

    kubectl get deployment sandbox-router-deployment
    

    等待部署在 READY 列中显示 2/2 或 1/1。

安装 Python 客户端

现在,沙盒路由器等集群内组件已部署完毕,最后一步准备工作是在本地机器上安装 Agentic Sandbox Python 客户端。请注意,此客户端是一个 Python 库,可让您以程序化方式创建、使用和删除沙盒。您将在下一部分中使用它来测试环境:

  1. 创建并激活 Python 虚拟环境:

    python3 -m venv .venv
    source .venv/bin/activate
    
  2. 安装客户端软件包:

    pip install k8s-agent-sandbox
    

测试沙盒

在所有设置组件就绪后,您现在可以使用 Agentic Sandbox Python 客户端创建沙盒并与之交互。

  1. agent-sandbox 目录中,创建一个名为 test_sandbox.py 的 Python 脚本,其中包含以下内容:

    from k8s_agent_sandbox import SandboxClient
    from k8s_agent_sandbox.models import SandboxLocalTunnelConnectionConfig
    
    # Automatically tunnels to svc/sandbox-router-svc
    client = SandboxClient(
        connection_config=SandboxLocalTunnelConnectionConfig()
    )
    
    sandbox = client.create_sandbox(template="python-runtime-template", namespace="default")
    try:
        print(sandbox.commands.run("echo 'Hello from the sandboxed environment!'").stdout)
    except Exception as e:
        print(f"An error occurred: {e}")
    
  2. 在终端中(虚拟环境仍处于活跃状态),运行测试脚本:

    python3 test_sandbox.py
    

您应该会看到“Hello from the sandboxed environment!”消息,这是沙盒的输出。

恭喜!您已成功在安全沙盒中运行 shell 命令。使用 sandbox.run() 方法,您可以执行任何 shell 命令,而 Agent Sandbox 会在安全屏障内运行该命令,从而保护集群的节点和其他工作负载免受不信任代码的侵害。这为 AI 代理或任何自动化工作流提供了一种安全可靠的任务执行方式。

运行脚本时,SandboxClient 会为您处理所有步骤。它会创建 SandboxClaim 资源来启动沙盒,等待沙盒准备就绪,然后使用 sandbox.run() 方法在安全容器内执行 bash shell 命令。然后,客户端会捕获并输出来自该命令的 stdout。程序运行后,沙盒会自动删除。

创建 SandboxClaim 资源时,系统会从温池中分配一个可用的 Pod 给沙盒对象,并将声明标记为就绪。然后,SandboxWarmPool 会自动补充自身,以维持配置的副本数量。

如需验证特定沙盒是否已被声明或可用,请检查沙盒 pod 元数据中的 ownerReferences - 如果 kind 字段的值为 Sandbox,则表示该 pod 正在使用中。如果 kind 字段的值为 SandboxWarmPool,则表示 Pod 处于空闲状态,等待被声明。

在生产环境中运行沙盒

在本文档中,您将使用 Cloud Shell 从集群外部与沙盒进行交互。Python 客户端使用您的用户凭据向集群进行身份验证并管理沙盒资源,同时使用 kubectl port-forward 命令与沙盒建立连接。这些步骤非常适合开发场景。

在生产场景中,控制器应用(例如 AI 编排器)负责创建和管理沙盒资源。如需在生产环境中使用代理沙盒,请考虑以下事项:

  • 身份验证:控制器应用必须向集群 API 服务器进行身份验证,才能运行沙盒。身份验证的配置方式取决于控制器应用的运行位置,如下所示:

    • 如果控制器应用作为 Pod 在同一集群中运行,请使用 Kubernetes RBACWorkload Identity Federation for GKE 与 IAM 政策一起向 Pod 的 Kubernetes 服务账号授予观看沙盒或发现网络端点所需的权限。
    • 如果控制器应用在集群外部运行,请使用工作负载身份联合或 IAM 服务账号为应用提供可在允许政策中引用的身份。
  • 路由:控制器应用中的 Python 客户端发出的请求必须到达集群中的沙盒路由器。在生产环境中,请使用以下方法之一来建立网络连接:

    • 如果控制器应用在同一集群中运行,请使用 SandboxDirectConnectionConfig 函数来指定 Sandbox Router 服务使用的网址和端口。
    • 如果控制器应用在集群外部运行,请使用 GKE Gateway API 创建内部或外部负载均衡器。在客户端代码中,使用 SandboxGatewayConnectionConfig 函数引用网关。

    如需详细了解这些路由方法,请参阅 GitHub 上的使用示例路由器的网关部署步骤

  • 沙盒对 Cloud de Confiance 资源的访问权限:如果您的沙盒代码需要向 Cloud de Confiance API(例如 Cloud Storage)发送请求,请使用包含适用于 GKE 的工作负载身份联合的 IAM 政策,向沙盒 Pod 使用的 Kubernetes ServiceAccount 授予该访问权限所需的权限。由于默认网络政策会阻止访问 Cloud de Confiance by S3NS 元数据服务器 (169.254.169.254),因此您必须自定义网络政策以允许此流量。

  • 网络政策限制:默认情况下,Agent Sandbox 会强制执行严格的默认安全网络姿态 (networkPolicyManagement: Managed)。在此姿态下,适用以下限制:

    • 入站流量会被阻止,但指定沙盒路由器除外。
    • 允许出站流量流向公共互联网,但明确禁止出站流量流向专用 LAN 范围 (RFC 1918)、内部集群 DNS (CoreDNS) 和云提供商元数据服务器 (169.254.0.0/16)。

    如需使用适用于 GKE 的工作负载身份联合或访问其他私有资源,您必须在 SandboxTemplate 中定义自定义网络政策。如需详细了解配置细节和可自定义的模板(例如隔离的沙盒或 Workload Identity Federation for GKE 集成),请参阅代理沙盒网络政策管理

沙盒安全政策

为了帮助确保默认安全的环境,GKE 代理沙盒插件使用 Kubernetes 验证准入政策 (VAP) 来对 SandboxSandboxTemplate 资源强制执行安全限制。这些政策会自动应用。

该插件将安全执行分为双层政策模型,以提高灵活性。以下部分介绍了这些政策:严格管理的内核政策和可自定义的强化政策。

核心安全政策 (sandbox-core-policy)

核心安全政策会强制执行隔离要求,以帮助保护沙盒的完整性。此政策包含需要使用 gVisor、网络隔离(例如停用 hostNetwork)和文件系统隔离(例如屏蔽 hostPath)的规则。由于 GKE 通过 addonmanager.kubernetes.io/mode: Reconcile 设置管理此政策,因此您无法修改或覆盖这些核心规则。

强化安全政策 (sandbox-hardening-policy)

强化安全政策可提供额外的安全最佳实践和管理选项。它会强制执行各种限制,例如丢弃所有功能、防止添加新功能,以及要求容器以非 root 用户身份运行并设置资源限制。GKE 通过 addonmanager.kubernetes.io/mode: EnsureExists 设置以 EnsureExists 模式部署此政策。此设置意味着,如果缺少政策,GKE 会创建该政策,但您可以根据需要修改或删除该政策或其绑定。

修改或移除强化限制

由于强化政策是以 EnsureExists 模式部署的,因此如果该政策缺失,GKE 会创建该政策,但不会覆盖您的修改。如果您的工作负载需要免于遵守这些强化规则,您可以修改政策以移除特定限制,也可以完全删除政策绑定。

如需修改强化政策并移除特定限制条件(例如,允许容器以 root 身份运行或省略资源限制),请修改 ValidatingAdmissionPolicy 资源:

kubectl edit validatingadmissionpolicy sandbox-hardening-policy

在打开的文本编辑器中,找到 validations 部分,然后移除或修改阻止工作负载的限制表达式。

或者,如果您想完全停用集群的强化政策,请删除政策绑定:

kubectl delete validatingadmissionpolicybinding sandbox-hardening-binding

已知问题

本部分介绍了在 GKE 中使用代理沙盒时的已知问题,以及如何解决或规避这些问题。

使用服务网格时,安全政策会屏蔽功能

如果您尝试部署与服务网格边车(例如 Envoy 或 Istio)集成的沙盒,强化安全政策可能会阻止沙盒的创建,并显示如下错误:

sandbox create error: sandboxes.agents.x-k8s.io "claude-cli-claim-managed" is forbidden:
ValidatingAdmissionPolicy 'sandbox-hardening-policy' with binding 'sandbox-hardening-binding'
denied request: Security Violation: Capabilities.add must be empty. You cannot add capabilities.
  • 原因:服务网格边车通常使用 init 容器,例如 istio-initproxy-init。这些 init 容器需要 NET_ADMINNET_RAW 等功能来配置 iptables 规则,以实现透明的出站路由。 默认情况下,GKE sandbox-hardening-policy 会阻止所有容器类型中添加任何功能。
  • 解决方法:由于 GKE 加固政策是在 EnsureExists 模式下部署的,因此您可以修改 ValidatingAdmissionPolicy 以允许特定的受信任 init 容器请求 NET_ADMINNET_RAW 功能。如需了解如何修改或移除这些强化限制,请参阅修改或移除强化限制。 例如,您可以更新政策的验证表达式或变量,以使受信任的容器名称不受功能规则的限制。

通过 IPv6 连接到 Google API 时出现的出站延迟或超时

沙盒中的工作负载在尝试连接到外部资源或 Google API(例如 Vertex AI 或 Cloud Storage)时,可能会遇到连接超时或高延迟(高达两分钟)。

  • 原因:如果您的 GKE 集群已启用双栈 IPv6,则 Google API 的 DNS 解析会同时返回 IPv4 (A) 和 IPv6 (AAAA) 地址。运行时引擎(例如 Node.js)中的某些算法会尝试先通过 IPv6 进行连接。如果您的 GKE VPC 没有有效的 IPv6 出站流量路由(例如 Cloud NAT 或 IPv6 的互联网网关),TCP 连接会停止响应(如需了解详情,请参阅 https://developers.google.com/style/word-list#hang),直到 TCP SYN 超时过期。然后,TCP 连接会回退到 IPv4。
  • 解决方法:如需解决此问题,请执行以下某项操作:

    • 配置 IPv6 出站流量:如需允许出站 IPv6 流量返回到集群,请在 VPC 网络中配置有效的 IPv6 Cloud NAT 或互联网网关。
    • 在工作负载中首选 IPv4:如需首选 IPv4 DNS 解析,请配置工作负载的运行时。例如,在 Node.js 应用中,您可以在 SandboxTemplate 定义中设置以下环境变量:

      env:
      - name: NODE_OPTIONS
        value: "--dns-result-order=ipv4first --no-network-family-autoselection"
      

清理资源

为避免系统向您的 Cloud de Confiance by S3NS 账号收取费用,您应删除创建的 GKE 集群:

gcloud container clusters delete $CLUSTER_NAME --location=$LOCATION --quiet

后续步骤