使用 E2B SDK 管理 Agent Sandbox 出口流量访问策略

更新时间:
复制 MD 格式

基于 enhanced-traffic-policy 和 agents.kruise.io TrafficPolicy,以单个 Sandbox 为粒度管控 Agent Sandbox 出站 TCP 流量,支持配置出站流量白名单。

功能介绍

E2B SDK 在创建 Sandbox 时,支持传入 network config 参数配置 Sandbox 的出口流量访问策略,具体信息,请参见E2B 官方文档。

本文基于 enhanced-traffic-policy 和 agents.kruise.io TrafficPolicy 实现,介绍使用 E2B SDK network config 管理 Agent Sandbox 出口流量访问策略的最佳实践。

network config 支持以下字段:

  • allow_out:允许访问的目标列表,元素可为域名(FQDN)、IP 或 CIDR。

  • deny_out:拒绝访问的目标列表,元素仅可为 IP 或 CIDR。

服务端按 network config 为该 Sandbox 单独创建 priority 为 100 的 TrafficPolicy,仅对该 Sandbox 生效。

当前推荐仅依赖以下几种行为:

  1. 不传 network config,保持 TCP 默认开放。

  2. 显式指定 deny_out=["0.0.0.0/0"],拒绝全部 IPv4 TCP。

  3. 显式指定allow_out 并搭配 deny_out=["0.0.0.0/0"],建立 TCP 白名单。

  4. 显式指定deny_out并搭配agents.kruise.io/allow-internet-access: "true",建立TCP黑名单。

适用范围

组件要求

  • ack-agent-sandbox-controller >= 0.5.22。

  • ack-sandbox-manager >= 0.6.11。

    • 已启用配置项 enhancedTrafficManagement 。

  • 安装 Poseidon组件。

  • 已完成 E2B SDK 接入,包括安装 e2b 包和配置 E2B_DOMAIN、E2B_API_KEY 环境变量。具体操作,请参见使用E2B SDK接入Agent Sandbox。

默认 TrafficPolicy / GlobalTrafficPolicy 配置

创建 Sandbox 时,用户可以通过 allow-internet-access 绑定默认网络策略。默认网络策略需管理员预先在集群中配置,优先级需低于 per-Sandbox 规则优先级(默认priority为100,数值越大则优先级越低)。allow-internet-access=true 或未显式指定时,Sandbox 会添加 agents.kruise.io/allow-internet-access: "true" label;allow-internet-access=false 时,Sandbox 会添加 agents.kruise.io/allow-internet-access: "false" label。管理员可据此创建默认网络策略。

enhanced-traffic-policy 模式同时支持 agents.kruise.io 和 network.alibabacloud.com 两个 API Group 下的 TrafficPolicy。两个版本能力完全兼容,区别仅为 agents.kruise.io 版本的 Action 字段仅支持 allow 和 reject。更多信息,请参见为Agent Sandbox配置增强型出口流量管理。

参考策略配置如下:

allow-internet-access: "true":

kubectl apply -f - <<'EOF'
apiVersion: agents.kruise.io/v1alpha1
kind: GlobalTrafficPolicy
metadata:
  name: e2b-allow-internet
  labels:
    app.kubernetes.io/name: e2b-allow-internet
    app.kubernetes.io/managed-by: kubectl
spec:
  priority: 900
  selector:
    matchLabels:
      agents.kruise.io/allow-internet-access: "true"
  egress:
    rules:
    - action: allow
      to:
      - cidr: 0.0.0.0/0
EOF

allow-internet-access: "false":

kubectl apply -f - <<'EOF'
apiVersion: agents.kruise.io/v1alpha1
kind: GlobalTrafficPolicy
metadata:
  name: e2b-deny-internet
  labels:
    app.kubernetes.io/name: e2b-deny-internet
    app.kubernetes.io/managed-by: kubectl
spec:
  priority: 900
  selector:
    matchLabels:
      agents.kruise.io/allow-internet-access: "false"
  egress:
    rules:
    - action: reject
      to:
      - cidr: 0.0.0.0/0
EOF

Template 配置

在创建任何预热 Sandbox 之前,将 annotation 配置在声明源对象上。

SandboxSet 示例:

apiVersion: agents.kruise.io/v1alpha1
kind: SandboxSet
metadata:
  name: code-interpreter
  namespace: default
spec:
  runtimes:
  - name: csi           
  - name: agent-runtime 
  replicas: 4
  template:
    metadata:
      annotations:
        network.alibabacloud.com/network-policy-mode: enhanced-traffic-policy
      labels:
        alibabacloud.com/acs: "true"
        alibabacloud.com/compute-class: agent-sandbox 
        alibabacloud.com/compute-qos: default 
    spec:
      containers:
      - name: sandbox
        image: <sandbox-image>

独立 SandboxTemplate 使用同一位置:

apiVersion: agents.kruise.io/v1alpha1
kind: SandboxTemplate
spec:
  template:
    metadata:
      annotations:
        network.alibabacloud.com/network-policy-mode: enhanced-traffic-policy

使用说明

以下示例均使用 E2B Python SDK 创建 Sandbox,通过 network 参数配置出口流量访问策略,并在 Sandbox 内发起请求验证策略效果。示例中的 template="code-interpreter" 需替换为实际的 SandboxSet 或 SandboxTemplate 名称,输出中的 http_code=000 表示 TCP 连接被拒绝。

各场景的 network 参数写法如下:

  • 默认开放:不传 network 参数。

  • 拒绝全部 IPv4 TCP:deny_out=["0.0.0.0/0"]。

  • TCP 白名单:allow_out 搭配 deny_out=["0.0.0.0/0"]。

  • TCP 黑名单:allow_internet_access=True 搭配 deny_out=[具体 IP 或 CIDR]。

TrafficPolicy 从创建到下发至数据面存在秒级延迟,示例中通过 time.sleep(10) 等待策略生效后再验证。

默认开放

需求:不限制 Sandbox 出站 TCP。

创建 Sandbox 时不传 network 参数。完整示例:

from e2b import Sandbox

sandbox = Sandbox.create(
    template="code-interpreter",
    timeout=900,
)

try:
    print(f"sandbox_id={sandbox.sandbox_id}")

    result = sandbox.commands.run(
        "curl --max-time 10 -sS -o /dev/null -w '%{http_code}' https://example.com 2>/dev/null || true"
    )
    print(f"http_code={result.stdout}")
finally:
    sandbox.kill()

预期输出:

sandbox_id=default--code-interpreter-xhmbv
http_code=200

未传 allow_internet_access 时,服务端默认按 true 处理,并在 Sandbox 与 Pod 上写入 agents.kruise.io/allow-internet-access=true 标签。因此“未传”与显式传入 allow_internet_access=True 等价,该默认值控制平台 fallback 的选择范围,本身不会创建 TrafficPolicy。

也可以显式传入空的 network 配置,但没有必要:

sandbox = Sandbox.create(
    template="code-interpreter",
    timeout=900,
    network={},
)

预期:

  • 不创建 per-Sandbox TrafficPolicy。

  • TCP 保持默认开放。

  • UDP、ICMP 按底层网络默认行为通信。

拒绝全部 IPv4 TCP

需求:Sandbox 不能建立外部 TCP 应用连接。

推荐显式指定 deny_out=["0.0.0.0/0"]。完整示例:

import time

from e2b import Sandbox

sandbox = Sandbox.create(
    template="code-interpreter",
    timeout=900,
    network={
        "deny_out": ["0.0.0.0/0"],
    },
)

try:
    print(f"sandbox_id={sandbox.sandbox_id}")

    # 等待出口流量策略下发到数据面
    time.sleep(10)

    result = sandbox.commands.run(
        "curl --max-time 10 -sS -o /dev/null -w '%{http_code}' https://example.com 2>/dev/null || true"
    )
    print(f"http_code={result.stdout}")

    result = sandbox.commands.run("getent hosts example.com | head -1")
    print(f"dns={result.stdout}")
finally:
    sandbox.kill()

预期输出:

sandbox_id=default--code-interpreter-fp247
http_code=000
dns=104.20.23.154   example.com

TCP 连接被拒绝,UDP DNS 解析不受影响。服务端为该 Sandbox 创建的 TrafficPolicy 如下(名称由服务端随机生成):

apiVersion: agents.kruise.io/v1alpha1
kind: TrafficPolicy
metadata:
  name: tp-9lv7k
  namespace: default
spec:
  priority: 100
  selector:
    matchLabels:
      agents.kruise.io/sandbox-name: <SANDBOX-POD-NAME>
  egress:
    rules:
    - action: reject
      to:
      - cidr: 0.0.0.0/0

当前数据面只控制 TCP。该配置不能阻止:

  • UDP DNS。

  • 其他 UDP 应用。

  • ICMP。

  • 其他未经过增强 TCP 数据面的协议。

TCP 白名单

需求:只允许访问明确批准的 TCP 域名、IP 或 CIDR。

完整示例:

import time

from e2b import Sandbox

sandbox = Sandbox.create(
    template="code-interpreter",
    timeout=900,
    network={
        "allow_out": [
            "example.com",
            "1.1.1.1",
            "10.0.0.0/8",
        ],
        "deny_out": ["0.0.0.0/0"],
    },
)

try:
    print(f"sandbox_id={sandbox.sandbox_id}")

    # 等待出口流量策略下发到数据面
    time.sleep(10)

    result = sandbox.commands.run(
        "for url in https://example.com http://1.1.1.1 https://www.aliyun.com; do "
        "  code=$(curl --max-time 10 -sS -o /dev/null -w '%{http_code}' \"$url\" 2>/dev/null || true); "
        "  echo \"$url http_code=$code\"; "
        "done"
    )
    print(result.stdout, end="")
finally:
    sandbox.kill()

预期输出:

sandbox_id=default--code-interpreter-67fdk
https://example.com http_code=200
http://1.1.1.1 http_code=301
https://www.aliyun.com http_code=000

服务端为该 Sandbox 创建的 TrafficPolicy 如下,allow 规则始终排在 reject 规则之前:

apiVersion: agents.kruise.io/v1alpha1
kind: TrafficPolicy
metadata:
  name: tp-ncn5j
  namespace: default
spec:
  priority: 100
  selector:
    matchLabels:
      agents.kruise.io/sandbox-name: <SANDBOX-POD-NAME>
  egress:
    rules:
    - action: allow
      to:
      - cidr: 1.1.1.1/32
      - cidr: 10.0.0.0/8
      - fqdn: example.com
    - action: reject
      to:
      - cidr: 0.0.0.0/0

行为:

  • allow_out 命中目标允许。

  • 其他 IPv4 TCP 被拒绝。

  • allow 和 deny 重叠时 allow 优先。

  • bare IP 自动规范化为 /32。

  • FQDN 只能出现在 allow_out,deny_out 只接受 IP 或 CIDR,传入域名时创建请求返回 400。

  • 不支持泛域名,传入 *.example.com 时创建请求返回 400。

TCP 黑名单

需求:仅拒绝特定 IP 或网段,其余出站流量保持放行。

该用法依赖放行类默认策略兜底,需同时满足两个条件:

  • 集群中已按适用范围中的默认 TrafficPolicy / GlobalTrafficPolicy 配置,创建 allow-internet-access: "true" 的放行类默认策略。

  • 创建 Sandbox 时 allow_internet_access 为 True,使 Sandbox 命中该放行类默认策略。

完整示例:

import time

from e2b import Sandbox

sandbox = Sandbox.create(
    template="code-interpreter",
    timeout=900,
    allow_internet_access=True,
    network={
        "deny_out": ["1.0.0.0/8"],
    },
)

try:
    print(f"sandbox_id={sandbox.sandbox_id}")

    # 等待出口流量策略下发到数据面
    time.sleep(10)

    result = sandbox.commands.run(
        "for url in http://1.0.0.1 https://example.com; do "
        "  code=$(curl --max-time 10 -sS -o /dev/null -w '%{http_code}' \"$url\" 2>/dev/null || true); "
        "  echo \"$url http_code=$code\"; "
        "done"
    )
    print(result.stdout, end="")
finally:
    sandbox.kill()

预期输出:

sandbox_id=default--code-interpreter-cx77n
http://1.0.0.1 http_code=000
https://example.com http_code=200

服务端为该 Sandbox 创建的 TrafficPolicy 只包含 reject 规则,未命中该规则的流量继续匹配 priority 更大的默认策略:

apiVersion: agents.kruise.io/v1alpha1
kind: TrafficPolicy
metadata:
  name: tp-99wgd
  namespace: default
spec:
  priority: 100
  selector:
    matchLabels:
      agents.kruise.io/sandbox-name: <SANDBOX-POD-NAME>
  egress:
    rules:
    - action: reject
      to:
      - cidr: 1.0.0.0/8

allow 与 deny 网段重叠

可以将具体例外放入 allow_out,将更大范围放入 deny_out。完整示例:

import time

from e2b import Sandbox

sandbox = Sandbox.create(
    template="code-interpreter",
    timeout=900,
    network={
        "allow_out": ["1.1.1.1"],
        "deny_out": ["1.0.0.0/8"],
    },
)

try:
    print(f"sandbox_id={sandbox.sandbox_id}")

    # 等待出口流量策略下发到数据面
    time.sleep(10)

    result = sandbox.commands.run(
        "for url in http://1.1.1.1 http://1.0.0.1 https://example.com; do "
        "  code=$(curl --max-time 10 -sS -o /dev/null -w '%{http_code}' \"$url\" 2>/dev/null || true); "
        "  echo \"$url http_code=$code\"; "
        "done"
    )
    print(result.stdout, end="")
finally:
    sandbox.kill()

预期输出:

sandbox_id=default--code-interpreter-v5v9m
http://1.1.1.1 http_code=301
http://1.0.0.1 http_code=000
https://example.com http_code=200

实测行为:

  • allow_out 命中的目标放行,即使该目标同时落在 deny_out 网段内。

  • deny_out 命中且未被 allow_out 覆盖的目标被拒绝。

  • 两个列表都未命中的流量不会创建默认拒绝规则,而是继续匹配 priority 更大的默认策略。集群中存在放行类默认策略时,该部分流量被放行。

多目标白名单

需求:一次放行多个域名、IP 和 CIDR。每个 allow_out 或 deny_out 列表不能超过 20 项。完整示例:

import time

from e2b import Sandbox

sandbox = Sandbox.create(
    template="code-interpreter",
    timeout=900,
    network={
        "allow_out": [
            "example.com",
            "1.1.1.1",
            "10.0.0.0/8",
            "198.51.100.0/24",
        ],
        "deny_out": ["0.0.0.0/0"],
    },
)

try:
    print(f"sandbox_id={sandbox.sandbox_id}")

    # 等待出口流量策略下发到数据面
    time.sleep(10)

    result = sandbox.commands.run(
        "for url in https://example.com http://1.1.1.1 https://mirrors.aliyun.com; do "
        "  code=$(curl --max-time 10 -sS -o /dev/null -w '%{http_code}' \"$url\" 2>/dev/null || true); "
        "  echo \"$url http_code=$code\"; "
        "done"
    )
    print(result.stdout, end="")
finally:
    sandbox.kill()

预期输出:

sandbox_id=default--code-interpreter-lqljt
https://example.com http_code=200
http://1.1.1.1 http_code=301
https://mirrors.aliyun.com http_code=000

列表超过 20 项时,创建请求失败且 Sandbox 被自动清理,错误信息如下:

SandboxException: 500: failed to create network policy: failed to create TrafficPolicy:
TrafficPolicy.agents.kruise.io "tp-xqqqg" is invalid:
[spec.egress.rules[0].to: Too many: 21: must have at most 20 items]

使用限制

  • 不支持隔离 UDP、ICMP。

  • 不支持泛域名。

  • 单个 allow_out 或 deny_out 列表不支持超过 20 项。

  • 不支持动态切换 allow_internet_access。Sandbox 创建后调用 update_network 传入该字段不会报错,但标签与策略均不发生变化。

  • TrafficPolicy 下发至数据面存在秒级延迟,创建 Sandbox 后立即发起的请求可能仍按旧策略处理。

相关文档