Skip to content

网络策略 ​

sandbox 的网络默认拒绝一切:既不能主动连出去,也不能被别人连进来。调用方按需放行要访问的目标,管理员定义规则集和全集群的默认规则。这一页说明规则怎么写、怎么生效,以及边界情况。

前提:节点开启了 sandbox 网络(edges[].network.enabled,单机安装和示例配置都已开启)。没有开启的节点上,sandbox 只有回环接口,network_rules 被忽略。

1. 规则怎么写 ​

network_rules 是一个字典:键是规则,值为 true 放行,false 收回。

规则例子含义
规则集名pypi管理员在 network.rule_sets 里定义的一组目标
域名github.com这个域名及其所有子域名(api.github.com、raw.github.com 等)。写成 *.github.com 效果相同
IPv4 地址1.2.3.4这一个地址
IPv4 网段203.0.113.0/24、10.20.0.0/16整个网段
**所有公网地址(不含内网,见 §4)

每条规则后面可以加 :端口[/协议],只放行这些端口:

写法含义
pypi.org:443只放行 443 端口,TCP 和 UDP 都可以
10.0.0.0/8:5432/tcp只放行 TCP 5432
*:443所有公网地址的 443 端口
example.com:8000-8080端口范围
1.1.1.1:53/udp只放行 UDP 53

规则集里的每一项也可以带端口。

只支持 IPv4:sandbox 只有 IPv4 地址,AAAA 查询返回空结果。

例子 ​

python
# 只能装 Python 包
DSecRunArgs(..., network_rules={"pypi": True})

# 能访问公网,但只能用 HTTPS
DSecRunArgs(..., network_rules={"*:443": True})

# 访问公网,以及内网的一个数据库
DSecRunArgs(..., network_rules={"*": True, "10.20.0.15:5432/tcp": True})

# 集群默认放行公网,这个 sandbox 不要
DSecRunArgs(..., network_rules={"*": False})

# 集群默认放行公网,这个 sandbox 只允许 PyPI 的 443
DSecRunArgs(..., network_rules={"*": False, "pypi.org:443": True, "files.pythonhosted.org:443": True})

命令行用 -net,逗号分隔,! 表示 false:

sh
opendsecctl sandbox create -backend microvm -image root/py:3.12 -net 'pypi,github.com:443'
opendsecctl sandbox create -backend microvm -image root/py:3.12 -net '!*'

2. 规则集与默认规则(管理员) ​

在集群配置的 network 段(配置参考):

json
"network": {
  "rule_sets": {
    "pypi":   ["pypi.org", "files.pythonhosted.org"],
    "npm":    ["registry.npmjs.org"],
    "github": ["github.com", "codeload.github.com", "objects.githubusercontent.com"],
    "mirror": ["10.30.0.10:443/tcp"]
  },
  "default_rules": {"mirror": true},
  "upstream_dns": ["10.0.0.2"]
}
  • 规则集给常用的目标起名字,调用方写 {"pypi": true} 即可,不用记具体域名。规则集只在 network_rules 里用到时才生效。
  • 默认规则对每个 sandbox 生效,sandbox 自己的 network_rules 叠在上面:同一个键以 sandbox 的为准。调用方可以用 false 收回默认规则里的某一项。
    • 让 sandbox 默认能访问公网:"default_rules": {"*": true}。
    • 单机安装(quickstart)的集群没有默认规则:sandbox 默认不能访问任何地方。
    • E2B 网关创建的 sandbox 与 E2B 一致,默认放行公网,除非请求里关闭(见从 E2B 迁移)。
  • 上游 DNS:edge 上的 DNS 代理向这些服务器查询,默认用宿主机的 /etc/resolv.conf。内网有私有 DNS 时在这里指定。

3. 生效方式 ​

每台 edge 用 nftables 和一个 DNS 代理执行规则:

  • 出站:sandbox 发出的每个包都进入它自己的规则链,按以下顺序判断:
    1. 放行规则里写明的地址和网段(含端口限制);
    2. 丢弃内网、链路本地和组播地址;
    3. 放行 DNS 代理为它解析过的、属于放行域名的地址;
    4. 其余丢弃。
  • DNS:sandbox 的 DNS 请求被重定向到 edge 的 DNS 代理。
    • 放行的域名:转发给上游解析,结果里的 IPv4 地址先加入这个 sandbox 的放行列表,再把应答交给 sandbox。所以连接总能用上刚解析到的地址。
    • 没有放行的域名:返回 NXDOMAIN(域名不存在)。
    • 放行了 * 时所有域名都能解析。
    • 解析学到的地址闲置 1 小时后过期,再次解析时重新加入。
  • 入站:任何主动连向 sandbox 的新连接都被丢弃,无论来自其他 sandbox、宿主机还是外部。sandbox 主动发起的连接,回包照常通过。
  • 地址伪造:sandbox 用伪造的源地址发包,匹配不到任何规则,被丢弃。
  • 宿主机服务:除 DNS 外,sandbox 连不到宿主机上的任何服务。
  • 出口:sandbox 的流量经宿主机做地址转换(masquerade)后发出,外部看到的是节点的地址。

要访问 sandbox 里运行的服务,不要走网络,用 SDK 的 sb.http()、API 的 ConnectPort,或者 E2B 网关的端口转发:这些都在 edge 上通过 sandbox 的网络命名空间访问,不经过上面的规则。

4. 内网地址 ​

以下地址段只有用地址或网段规则明确写出时才能访问:

0.0.0.0/8、10.0.0.0/8、100.64.0.0/10、127.0.0.0/8、169.254.0.0/16(含云元数据地址 169.254.169.254)、172.16.0.0/12、192.0.0.0/24、192.168.0.0/16、198.18.0.0/15、224.0.0.0/4、240.0.0.0/4

  • * 不包括它们。
  • 通过域名解析得到的内网地址一律拦截:即使放行了某个域名,它解析到内网地址时也连不上。这防止用 DNS 绕过规则访问内网。
  • 需要访问内网的某个服务(数据库、私有镜像源、模型服务),用网段规则写明地址和端口,例如 10.30.0.10:443/tcp。请只放行确实需要的地址和端口:放行整段内网会让 sandbox 里运行的代码能访问到集群节点和其他内部服务。

5. 运行中修改 ​

python
await sb.update_network({"github": True})                 # 合并:在现有规则上加一条
await sb.update_network({"github": False})                # 收回
await sb.update_network({"pypi": True}, replace=True)     # 替换:只保留这一条(默认规则仍然生效)
sh
opendsecctl sandbox network $ID github
opendsecctl sandbox network $ID '!github'
opendsecctl sandbox network $ID pypi -replace
  • 需要 sandbox.operate。
  • 放行立即生效。
  • 收回立即生效,并且切断已有的连接:连接的后续包也要经过规则链。
  • 新规则写在 sandbox 的规格里,get_sandbox 能看到当前的规则。

6. 排查 ​

现象可能的原因检查
Could not resolve host / 域名不存在域名没有放行(DNS 代理返回 NXDOMAIN)看 sb.info.spec.network_rules 和集群的 default_rules;注意子域名包含在内,父域名不包含
能解析但连接超时端口限制不匹配;目标解析到了内网地址换成不带端口的规则试一下;getent hosts <域名> 看解析结果
访问内网服务超时内网地址需要明确的网段规则加 <地址>:<端口>/tcp
规则写法报 invalid不是合法的域名、IPv4 地址或网段;端口不在 1 到 65535;协议不是 tcp 或 udp看错误信息里指出的那一项
所有规则都不起作用,sandbox 只有 lo节点没有开启 sandbox 网络管理员检查 edges[].network.enabled
pip 走代理或镜像源失败镜像源的域名不在规则里把镜像源加进规则集,或者用网段规则

在 sandbox 里自查:

sh
cat /etc/resolv.conf                      # DNS 指向 sandbox 的网关
getent hosts pypi.org                     # 放行的域名能解析
python3 -c 'import urllib.request as u; print(u.urlopen("https://pypi.org/simple/", timeout=5).status)'

基于论文 DeepSeek Elastic Compute (DSec)(arXiv:2609.22978)实现。本项目独立开发,与 DeepSeek 没有关系。