关于 generate-sandbox-policy
此 Agent skill 根据自然语言需求和 API 文档生成沙箱网络策略 YAML,面向需要控制应用网络访问范围的用户。它支持从主机级规则到按端点细分的 L7 规则,并可输出网络中间件配置。
主要功能
- 01按需求粒度生成策略
- 02支持 L4 与 L7 规则
- 03利用 API 文档细化端点规则
- 04生成网络中间件配置
- 05提供范围澄清与策略校验指导
适用场景
- 01为指定二进制设置只读 API 访问
- 02根据部分路径限制 HTTP 方法
- 03依据 OpenAPI 文档生成端点规则
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ nvidia/ openshell --skill generate-sandbox-policy安装后在 Claude Code 中输入/generate-sandbox-policy确认已加载。
附带文件examples.md
详细介绍
生成沙箱策略
根据 API 文档和自然语言用户需求,生成 YAML 沙箱网络策略和网络中间件配置。
概述
此技能会将用户的自然语言策略意图转换为有效的沙箱策略。用户提供的详细程度决定了生成策略的粒度——可以是宽泛的 L4 或基于预设的策略(仅需主机名和端口),也可以是细粒度的逐端点 L7 规则(完整 API 文档)。
输出包括 network_policies YAML 块、可选的 network_middlewares 块,以及可选的、符合沙箱策略架构的完整策略文件。
步骤 1:收集输入
确定详细程度
用户的输入分为三个层级。根据用户提供的信息进行处理——不要要求超出所需层级的信息。
| 层级 | 用户提供的信息 | 可生成的内容 |
|---|---|---|
| 最简 | 主机名和自然语言意图 | 仅 L4 策略,或采用访问预设(read-only、read-write、full)的 L7 策略 |
| 中等 | 主机名 + 一些已知 URL 路径或资源 | 针对已知路径的 L7 定向 glob 规则,其余部分使用预设 |
| 完整 | 完整 API 文档(OpenAPI、Swagger、Markdown、URL) | 采用具体方法和路径组合的细粒度逐端点 L7 规则 |
最简层级(仅主机名 + 意图)
用户提供 API 端点和宽泛意图。无需 API 文档。
示例:
- “允许 curl 访问 api.github.com,只读”
- “让 claude 完全访问 api.anthropic.com”
- “允许 /usr/bin/myapp 与 internal-svc:8080 通信,但仅限读取”
以下策略已足够:
- 仅 L4 策略(主机名和端口 + 二进制文件检查,不包含方法或路径规则)
- 基于预设的 L7 策略(对所有路径使用
read-only、read-write或full)
对于此层级,默认规则如下:
- 用户说“读取”“浏览”“查看”“查询”或“获取”时,使用
access: read-only - 用户说“读写”“创建”或“更新”(但不包括“删除”)时,使用
access: read-write - 用户说“完全访问”“所有内容”或“不受限制”时,使用
access: full - 用户说“只要允许访问”“直接通过”或“无需
检查”时,仅使用 L4。对于显式代理客户端,省略
protocol。只有当工作负载必须使用原生 DNS 和直接套接字 调用、端点具有有效的 DNS 主机名,且所选运行时支持(目前为 Docker 和 Podman)时,才使用protocol: tcp。
中等层级(主机名 + 部分路径信息)
用户知道一些 API 路径,但没有完整文档。
示例:
- “允许对 integrate.api.nvidia.com 上的 /api/v1/models 执行 GET,对 /api/v1/completions 执行 POST”
- “对 api.github.com 上的 /repos/** 设为只读,但也允许对 /repos///issues 执行 POST”
对已知路径生成显式的 rules。如果用户还需要访问特定路径之外的更多内容,可以组合使用兜底规则,或改用预设。
完整层级(完整 API 文档)
用户提供完整 API 文档。接受以下格式:
| 格式 | 使用方式 |
|---|---|
| URL | 使用 Agent 的网页访问功能获取文档并解析端点列表 |
| 文件路径 | 读取文件(OpenAPI JSON/YAML、Markdown 等) |
| 粘贴文本 | 从对话中直接解析 |
| OpenAPI/Swagger 规范 | 提取所有方法和路径组合的 paths 对象 |
根据 API 文档,构建端点清单,即 (method, path, description) 元组列表。按逻辑分组(例如按资源或标签分组)。然后生成精确规则,仅允许用户意图所需的操作。
策略意图
无论属于哪个级别,都要从用户的描述中提取(或推断)以下信息:
| 方面 | 需要识别的内容 | 是否必需? |
|---|---|---|
| 范围 | API 主机和端口 | 是 — 始终需要 |
| 访问级别 | 大致意图:只读、读写、完整访问或自定义 | 是 — 不明确时询问 |
| 方法 | 要允许的具体 HTTP 方法 | 仅适用于自定义/细粒度配置 |
| 路径 | 具体 URL 路径或模式 | 仅适用于自定义/细粒度配置 |
| 执行方式 | enforce 还是 audit?默认为 enforce。 | 否 — 有默认值 |
| 二进制文件 | 应获得访问权限的二进制文件/进程 | 是 — 未说明时询问 |
| 中间件 | 是否需要对准入的 HTTP 请求、最终 HTTP 响应或客户端 WebSocket 文本消息进行有序处理;处理阶段可以是内置的,也可以由操作员运行 | 否 |
如果主机和访问级别明确,但未指定二进制文件,请询问用户哪个二进制文件或进程会发起请求。建议使用常见默认值,例如 /usr/bin/curl、/usr/local/bin/claude 等。
步骤 2:细化范围(澄清流程)
生成策略前,主动提出澄清问题,帮助用户尽可能缩小策略范围。目标是在满足用户需求的前提下,制定限制最严格的策略。
必要的澄清
如果用户尚未说明以下信息,务必询问:
| 缺少的信息 | 要问的问题 |
|---|---|
| 未指定二进制文件 | “哪个二进制文件或进程会发起这些请求?(例如,/usr/bin/curl、/usr/local/bin/claude)” |
| 未指定端口 | “此 API 使用哪个端口?(HTTPS 通常使用 443)” |
| 未说明执行方式 | “策略违规时应予以阻止(enforce),还是仅记录下来供审核(audit)?如果你不确定,我会默认使用 enforce。” |
缩小范围的问题
当用户的意图宽泛且还有进一步细化的空间时,询问以下问题:
| 用户的说法 | 用于缩小范围的问题 |
|---|---|
| “完整访问”/“允许所有操作” | “你确实需要 DELETE 访问权限吗?还是说只需读写权限(除 DELETE 之外的所有操作)就够了?” |
| “允许访问 api.example.com”(未指定方法/路径) | “你知道需要哪些具体 API 路径或操作吗?如果知道,我可以将策略限制为仅允许这些内容。否则我会使用宽泛的预设。” |
| 仅 L4/“直接透传即可” | “仅 L4 意味着代理不会应用任何方法或路径规则——任何方法和路径都会被允许。你确定不需要至少限制为只读或读写吗?” |
通配二进制文件(/usr/bin/*) | “二进制文件通配模式意味着该目录中的任何二进制文件都可以使用此策略。可以将范围缩小到特定的二进制文件吗?” |
| 一个策略中包含多个主机 | “这些主机是否都需要相同的访问级别?如果其中一些需要更严格的限制,我可以将它们拆分为单独的策略。” |
access: full 且 enforcement: audit | “完整访问配合审计模式意味着实际上不会施加任何限制——所有流量都会通过,违规行为只会被记录下来。这是你有意设置的吗?还是你想要强制执行限制?” |
所有规则的路径 glob 均为 ** | “对所有路径使用 ** 会允许任何 URL 路径。你知道需要哪些具体的 API 路径前缀吗(例如,/api/v1/)?” |
| 目标为私有/内部 IP | “此服务解析到私有 IP 吗(10.x、172.16.x、192.168.x)?精确主机名无需 allowed_ips 即可访问其私有地址,但通配主机或无主机端点需要设置它。是否应将端点限定在特定的 CIDR 范围内?” |
自动发现知名服务的 API 文档
当用户提到一个可识别的 API 主机,但未提供文档,且当前级别为 Minimal 时,尝试在线搜索 API 文档,将级别提升为 Full。
触发条件:
- 主机是知名的公共 API(例如
api.github.com、api.anthropic.com、api.openai.com、integrate.api.nvidia.com、api.stripe.com、api.slack.com、api.gitlab.com) - 用户尚未提供 API 文档
- 用户未明确要求使用宽泛预设(“只读就行,不需要复杂功能”)
操作方法:
- 告诉用户:“我可以查找 [service] 的 REST API 文档,以便生成更精确的策略。要我查找吗?”
- 如果用户同意(或尚未拒绝),搜索文档:
- 使用类似
"[service name] REST API documentation endpoints"或"[service name] OpenAPI spec"的查询词搜索网络 - 在搜索结果中查找官方文档 URL
- 使用类似
- 获取文档页面并提取端点清单(方法 + 路径)
- 根据发现的端点提供更精细的范围:“我在 [service] API 中找到 [N] 个端点。根据你的意图,我可以将策略范围缩小到 [subset]。要我这样做,还是保留更宽泛的预设?”
跳过条件:
- 用户明确要求使用宽泛预设,或表示“不用查文档”
- API 是内部、私有的,或没有公开文档
- 无法识别该主机为知名服务
- 之前针对该主机的搜索未返回有用结果
平稳回退: 如果搜索未找到可用的 API 文档(结果不相关、文档需要身份验证,或页面太大而无法解析),则不必停滞,直接回退到当前级别。说明:“我找不到 [host] 的可用 API 文档,因此会使用 [preset/L4] 方法生成策略。你之后也可以提供文档,以进一步缩小范围。”
用户无法进一步缩小范围时
如果用户确认策略必须保持宽泛(他们不知道路径、确实需要宽泛访问权限等),接受这一要求,但指出其范围较广。不要阻止策略生成,只需确保输出中清楚显示相关警告(参见步骤 6)。
迭代
可能需要来回沟通几轮。保持流程简洁:
- 一次提出一组澄清问题(将相关问题归为一组)
- 根据回答更新你的理解
- 如果回答显示还有进一步缩小范围的机会,提出后续问题
- 用户确认范围或表示可以继续时,停止提问
不要过度盘问。 如果用户提出的要求清晰、具体,就跳过澄清并直接生成。只有确实存在歧义,或有机会显著缩小攻击面时,才提出问题。
步骤 3:阅读策略架构
在生成或更改策略前,请阅读已发布的策略架构参考。已发布的文档是当前架构的权威来源;不要根据此技能中的示例推断字段。
需要参考的关键部分:
- 策略架构参考 — 顶层结构
network_policies— 规则结构NetworkEndpoint字段 — host、port、protocol、tls、enforcement、access、rules、allowed_ipsL7Rule/L7Allow— 方法 + 路径匹配- 访问预设 —
read-only、read-write、full - 通过
allowed_ips访问私有 IP — 私有 IP 空间的 CIDR 允许列表 - 网络中间件 - 顶层中间件配置、排序、主机选择和故障行为
- 验证规则 — 哪些组合有效或无效
需要中间件时,也请阅读已发布的监督程序中间件指南。
有关强制执行机制和随附基线的信息,请阅读沙箱策略和默认策略参考。默认策略内置于 OpenShell 运行时中,并在未提供显式策略时生效。
验证预期的提供方组合以及编写的策略。
镜像端点在提供方组合后可能会变为需要凭据的端点,并导致启动时出现 ConfigurationInvalid。请使用已发布的策略工作流修复完整策略或提供方选择;不要仅为了绕过启动错误而添加
allow_uninspected_credentials。
步骤 4:选择策略形式
根据细节层级和用户意图,遵循以下决策树:
Is L7 inspection needed?
├─ No (user wants pass-through / "just allow it")
│ ├─ Explicit-proxy client → omit protocol
│ └─ Native DNS/socket client with a DNS hostname on a supported runtime → protocol: tcp
│
└─ Yes (user wants method/path control)
│
├─ Does a preset match the intent exactly?
│ ├─ Read-only (GET, HEAD, OPTIONS) → access: read-only
│ ├─ Read-write (no DELETE) → access: read-write
│ └─ Everything → access: full
│
└─ No preset fits (specific paths, mixed broad+narrow, exclude certain paths)
└─ Build explicit rules list
└─ Requires either known paths from the user or full API docs
原则:始终选择能够满足意图的最简单形式。如果预设能够覆盖使用场景,应优先选择预设,而不是显式规则。
TLS 决策
无论端口为何,都不要在任何端点上设置 tls:代理会自动检测 TLS,并终止 TLS 连接以进行检查。skip 是唯一可接受的非空值,仅适用于需要客户端证书 mTLS 或非 HTTP 协议的上游。
不要通过将被拒绝的值(包括已移除的 terminate 和 passthrough 写法)改为 skip 来“修正”它;应直接移除该字段。skip 会停止对该端点进行检查、凭据注入和 L7 规则强制执行,因此会在不显眼的情况下扩大该端点的允许范围。
中间件决策
仅当用户要求检查、转换、脱敏或独立授权已获准的 HTTP 请求、最终 HTTP 响应或客户端 WebSocket 文本消息时,才添加 network_middlewares。请求中间件在网络和 L7 策略准入后、提供方凭证注入前运行。响应中间件在最终响应返回沙盒前,对与之匹配的响应运行。
- 对 UTF-8 HTTP 请求正文或完整的客户端到上游 WebSocket 文本消息进行固定模式脱敏时,使用
openshell/regex,无需在网关注册。 - 仅当某个由运维人员拥有的中间件名称已在
[[openshell.supervisor.middleware]]下注册,且网关与沙盒监督程序均可访问时,才使用该名称。 - 确认服务在
Describe中声明了所需绑定,且运维人员的binding_policy授权了该绑定。例如,如果服务声明了两个 HTTP 钩子,但注册项仅允许http_response_pre_return,那么即使设置了on_error: fail_closed,匹配的请求也会跳过此中间件。 - 若要强制检查请求,请让运维人员在
bindings中加入http_request_pre_credentials,并设置binding_policy = "allowlist"或"exact"。默认的dynamic策略遵循服务声明的绑定;仅靠沙盒策略无法要求不存在的绑定。依赖绑定策略前,请确认网关和所有监督程序均支持这些策略。 - WebSocket 中间件仅检查客户端文本消息,适用于
ws://和wss://。二进制消息和上游到客户端的消息不会经过检查,即使设置了fail_closed也是如此。 on_error控制所选阶段发生故障时的处理方式。显式拒绝始终会阻止流量。WebSocket 阶段在fail_open下发生故障后,该阶段在连接剩余期间可能会被绕过。- 默认将
on_error设为fail_closed。仅当绕过该阶段仍能满足用户明确提出的安全要求时,才使用fail_open。 - 为完整策略中的配置指定唯一的
order值。数值越小越先运行,最多可选择 10 个配置。 - 尽可能使用
endpoints.include精确匹配目标主机;选择器范围较广且存在可信例外时,使用exclude。 - 对
tls: skip端点,不要选择故障时关闭的中间件,因为监督程序无法检查此类流量。
将路径映射为 Glob 模式(构建显式规则时)
仅 Moderate 和 Full 层级需要此步骤。将 API 路径参数转换为 glob 模式:
| API 路径 | Glob 模式 |
|---|---|
/repos/{owner}/{repo} | /repos/*/* |
/repos/{owner}/{repo}/issues | /repos/*/*/issues |
/repos/{owner}/{repo}/issues/{id} | /repos/*/*/issues/* |
/api/v1/models/{model_id}/versions/{version} | /api/v1/models/*/versions/* |
/api/v1/ 下的所有子路径 | /api/v1/** |
在 REST 规则路径中,* 不会跨越 /,而完整路径段中的 ** 会跨越 /。
例如,/api/v1/** 会匹配其下级路径,但不包括 /api/v1 本身;需要时,请为该路径添加
一条显式规则。? 匹配除 / 之外的一个字符,
并支持 [0-9] 等方括号字符类。
端点 path 选择器采用单独的语义:/api/v1/** 包含
/api/v1 本身,而其他模式中的 * 可以跨越 /。这些语义既适用于
选择端点配置,也适用于判断哪些端点的允许和拒绝规则生效。参见已发布策略架构中的
匹配器语义。
构建显式规则列表
对于每项允许的操作,创建一个 allow 条目:
rules:
- allow:
method: GET
path: "/api/v1/models/*"
- allow:
method: POST
path: "/api/v1/completions"
使用能够覆盖意图的最具体模式。已知 API 结构时,优先使用范围较窄的 glob,而不是 **。
步骤 5:生成策略
输出格式
生成一个完整的 network_policies 条目。使用此模板:
network_policies:
<policy_key>:
name: <policy_key>
endpoints:
- host: <api_host>
port: <port>
protocol: rest # Required for L7 inspection
enforcement: enforce # or audit
# Use ONE of: access OR rules (never both)
access: <preset> # read-only | read-write | full
# OR
rules:
- allow:
method: <METHOD>
path: "<glob_pattern>"
# Optional: restrict resolved addresses (CIDR or exact IP). Required
# for private IPs on wildcard or hostless endpoints.
# allowed_ips:
# - "10.0.5.0/24"
binaries:
- { path: <binary_path> }
需要中间件时,将其添加为单独的顶层映射,而不是嵌套在网络策略下:
network_middlewares:
<config_key>:
name: <human_readable_name>
middleware: <built_in_or_registered_name>
order: 10
config: {}
on_error: fail_closed
endpoints:
include: ["<api_host>"]
# exclude: ["<trusted_host>"]
映射键是策略本地的稳定标识。中间件的选择独立于允许请求通过的网络策略条目。
拒绝规则
使用 deny_rules 阻止特定的危险操作,同时允许广泛访问。拒绝规则在允许规则之后评估,并具有优先权。这与 rules 方法相反——不是枚举每个允许的操作,而是授予广泛访问权限,并阻止少数危险操作。
# Example: Allow full access to GitHub but block admin operations
github_api:
name: github_api
endpoints:
- host: api.github.com
port: 443
protocol: rest
enforcement: enforce
access: read-write
deny_rules:
- method: POST
path: "/repos/*/pulls/*/reviews"
- method: PUT
path: "/repos/*/branches/*/protection"
- method: "*"
path: "/repos/*/rulesets"
binaries:
- { path: /usr/bin/curl }
拒绝规则支持与允许规则相同的匹配功能:method、path 和 query 参数匹配器。生成策略时,如果用户需要广泛访问,同时只阻止少数操作,优先使用拒绝规则——与枚举 60 多条允许规则相比,这样生成的策略更短、更易维护。
私有 IP 目标地址
代理的 SSRF 防护会根据端点指定主机名的方式,对私有(RFC 1918)目标地址进行不同处理:
- 精确主机名(
host: api.internal.corp)——连接可以访问该主机名解析出的私有地址,无需设置allowed_ips。 - 通配符主机名、未指定主机名的端点或策略顾问提案——除非
allowed_ips包含这些地址,否则会阻止解析出的私有地址。
使用 allowed_ips 固定端点可访问的地址。设置后,所有解析出的地址都必须在列表范围内,包括公共地址:
- 主机名 + 允许列表:
host+allowed_ips——域名必须解析为允许列表中的 IP - 不指定主机名的允许列表:仅使用
allowed_ips(不设置host)——只要域名解析为允许列表中的 IP,就允许访问该端口上的任何域名
监督程序解析器是仅基于主机名进行授权时的权威来源。在 Linux 显式代理部署中,如果工作负载进程的命名空间对监督程序开放,那么普通端点只有在将 allowed_ips 设置为精确 IP 或较窄的 CIDR 时,才会遵循沙盒的 /etc/hosts 条目(例如 Kubernetes 的 hostAliases 映射)。OpenShell 由驱动程序管理的主机网关别名使用单独的可信 IP 固定机制。
环回地址(127.0.0.0/8)、链路本地地址(169.254.0.0/16)、未指定地址和云元数据地址始终会被阻止用作上游目标地址,无论是否设置 allowed_ips。
Google Cloud 元数据模拟器会在 Linux 沙盒中保留 127.0.0.1:8174。OpenShell 通过监督程序在本地处理 SDK 发现;不要添加 allowed_ips 例外,也不要授予对主机云元数据服务的访问权限。请参阅 Google 提供商文档。
# Example: Pin an internal service to a known private IP range
internal_api:
name: internal_api
endpoints:
- host: api.internal.corp
port: 8080
allowed_ips:
- "10.0.5.0/24"
binaries:
- { path: /usr/bin/curl }
策略键命名
使用描述性的 snake_case 键:github_api、nvidia_inference、internal_service_readonly。
多个端点
如果用户需要访问多个主机,或同一主机的不同规则,请选择以下任一方式:
- 同一策略——如果二进制文件集相同,则在
endpoints中使用多个条目 - 单独的策略——如果二进制文件集不同,则使用不同的策略键
第 6 步:验证并警示
向用户展示策略之前,请验证其正确性,并指出范围过宽的问题。
严重错误(会阻止沙箱启动)
- 同一端点上未同时设置
rules和access - 如果设置了 L7
protocol,则还必须设置rules或access;protocol: tcp仅适用于 L4,且不得包含这两个字段 - 每个
protocol: tcp端点都有有效的 DNS 主机名;主机名不能缺失、不能是 IP 字面量、不能以点结尾,也不能是格式错误的 DNS 选择器 -
tls要么省略,要么设为skip;不接受其他值 - 存在
rules时,其列表不能为空 - 每个中间件配置都必须包含非空的
middleware名称和非空的endpoints.include - 中间件
order值必须唯一,且任何选定链的阶段数不得超过 10 - 任何故障时关闭的中间件选择器都不能覆盖
tls: skip端点 - 如果必须由操作员运行的服务进行检查,则注册必须要求相应绑定(
http_request_pre_credentials、http_response_pre_return或websocket_message_pre_credentials),该服务必须声明支持此绑定,且附加项必须使用on_error: fail_closed - 用户了解 V1 WebSocket 中间件仅检查客户端文本消息
- 凭据提供方贡献的端点不得仅适用于 L4 或设为
tls: skip,除非明确设置allow_uninspected_credentials: true记录此例外
架构警告(仅记录日志,但应修复)
-
tls: skip未与端口 443 上的 L7 规则同时使用;无法检查加密流量 - HTTP 方法为标准方法:GET、HEAD、POST、PUT、DELETE、PATCH、OPTIONS 或
* - 凭据目标也由附加的提供方配置文件端点覆盖;仅通过策略准入并不能授权凭据解析
结构检查
- 每个策略都包含
name、endpoints和binaries - 每个端点都包含
host和port - 每个二进制文件都包含
path - 策略键与
name字段相匹配 - 每个中间件选择器的
include和exclude模式总数不超过 32
范围过宽警告
评估生成的策略是否授予了过宽的访问权限,并在输出中向用户显示警告。这些警告不会阻止生成,但用户必须看到。
| 条件 | 要显示的警告 |
|---|---|
仅 L4(没有 protocol,或 protocol: tcp) | “此策略允许所有应用方法和路径。省略 protocol 时会使用显式代理行为,且不应用任何方法或路径规则。使用默认 TLS 处理方式时,代理会终止检测到的 TLS,并检查其解析的 HTTP 请求中的 authority;但其他 CONNECT 负载(例如 HTTP/2 先验知识或非 HTTP 协议)可以通过原始中继传输;tls: skip 也会绕过终止和解析。protocol: tcp 仅在声明了完整底层能力的运行时(目前为 Docker 和 Podman)上启用策略 DNS 和透明 TCP;其 hostname 限制连接路由,而非应用层 authority,因此兼容的共享基础设施可能会暴露其他租户或服务。如果你需要 HTTP 方法级或 authority 控制,请考虑使用带预设的 protocol: rest。” |
access: full | “此策略允许所有 HTTP 方法(包括 DELETE)访问所有路径。如果不需要 DELETE,read-write 更安全。如果只需要读取,read-only 限制最严格。” |
access: full + enforcement: audit | “审计模式下的完全访问不会提供任何实际限制——所有流量都会通过。这实际上是一项仅用于监控的策略。” |
用户尚未确认需要写入时使用 access: read-write | “此策略允许对所有路径执行 POST、PUT 和 PATCH。如果只需要读取数据,read-only 的限制更严格。” |
通配符二进制文件(二进制文件路径中含 * 或 **) | “此策略允许任何与 glob 模式匹配的二进制文件。该目录中遭入侵或意外出现的二进制文件可能会使用此策略。请考虑列出具体的二进制文件路径。” |
所有显式规则均使用 ** 路径 glob | “所有规则都使用 ** 路径模式,可匹配任意 URL 路径。这等同于使用预设——请考虑使用 access: read-only(或类似设置)以明确意图,或者在了解 API 结构后缩小路径范围。” |
| 一项策略中包含多个宽泛端点 | “此策略向 N 个不同主机授予相同的宽泛访问权限。如果以后需要对其中任何主机施加更严格的限制,就必须拆分策略。” |
不含主机的 allowed_ips(没有 host 字段,且没有 protocol: tcp) | “此端点没有 host——任何解析到此端口上允许的 IP 范围内的域名,都可以通过旧版代理。请考虑添加 host 字段,以限制哪些域名可以使用此允许列表。” |
宽泛的 allowed_ips CIDR(例如 10.0.0.0/8) | “此 allowed_ips 条目覆盖的范围非常宽泛。请考虑缩小到特定子网(例如 10.0.5.0/24),以尽量减少暴露面。” |
on_error: fail_open | “此中间件在不可用、拒绝配置、返回无效结果或超出其正文限制时,可能会被绕过。除非可用性比此控制更重要,否则请使用 fail_closed。” |
| 宽泛的中间件主机选择器 | “无论哪个网络规则允许访问,此中间件都会独立附加到每个匹配的目标。对于由运维人员运行的中间件,只有服务声明且注册允许的绑定才能运行。如果并非每个匹配主机都需要附加中间件,请缩小 endpoints.include 的范围或添加排除项。” |
allow_uninspected_credentials: true | “此端点可能会在 OpenShell 无法检查或改写的流量中携带提供方凭据。请优先使用可检查的协议并改写凭据;仅在需要原始流量时保留此例外。” |
请在输出中清晰显示范围过宽警告,例如:
⚠️ Breadth warning: This policy uses `access: full`, which allows all HTTP
methods (including DELETE) on all paths. If you don't need DELETE, consider
using `read-write` instead.
如果没有范围过宽警告,请明确说明:“没有范围方面的顾虑——此策略的范围设置恰当。”
第 7 步:确定输出模式
需要将策略写入某处。确定适用的模式:
| 信号 | 模式 |
|---|---|
| 用户指定了一个现有策略文件(例如“添加到 my-sandbox-policy.yaml”) | 更新现有文件 |
| 用户说“更新我的策略”或“将此添加到我的策略文件” | 更新现有文件 — 询问要更新哪个文件 |
| 用户要求按名称修改现有策略规则 | 更新现有文件 — 就地编辑指定策略 |
| 用户说“创建一个新的策略文件”或指定了一个不存在的文件 | 创建新文件 |
| 未提供文件上下文 | 仅展示 — 显示 YAML,并询问用户是否要将其写入文件 |
模式 A:更新现有策略文件
-
读取现有文件以了解当前状态:
network_policies下已有的策略filesystem_policy、landlock和process部分的内容- 文件采用紧凑样式(
{ host: ..., port: ... })还是展开的 YAML 样式
-
检查冲突:
- 是否已存在具有相同键的策略?如果有,询问用户是要替换它、将新端点/二进制文件合并到其中,还是使用其他键。
- 是否有现有端点选择器与新选择器重叠?兼容的重叠是允许的,并且可以有意聚合允许和拒绝规则。对于同样具体、但连接或请求处理元数据不一致的重叠,应拒绝或修订,包括 TLS、目标约束、协议/解析器行为、强制执行或凭据处理。更具体的路径选择器可以覆盖更宽泛的请求处理元数据。
- 如果沙箱使用了附加的提供商凭据,请确认提供商配置文件也声明了预期的主机、端口和路径。沙箱策略中的允许规则不能扩展配置文件中的静态凭据绑定。
- 对于
credential_signing,请确认附加的、包含端点的配置文件声明了AWS_ACCESS_KEY_ID和AWS_SECRET_ACCESS_KEY,并涵盖已签名的端点。对于不含端点的 AWS 配置文件,请添加credential_binding.provider,并填写确切的附加提供商名称。
-
应用更改:
- 添加新策略:在
network_policies下插入新的策略块,并保持文件现有的缩进和样式。 - 修改现有策略:就地编辑指定策略 — 添加/移除端点、更改访问预设、更新规则、添加二进制文件等。规则会授权其列出的每个二进制文件访问其列出的每个端点和端口,因此,添加一个二进制文件会授予它访问该规则所有端点的权限;添加一个端点则会授予该规则中的所有二进制文件访问该端点的权限。写入前,向用户说明最终的对应关系。如果用户只想让某个二进制文件访问规则中的部分端点,请将该二进制文件和这些端点放入单独的规则中,而不要扩展现有规则。空的
binaries列表表示适用于任何二进制文件,因此省略该列表会将规则扩大到所有进程。 - 移除策略:如果用户提出要求,则删除该策略块。
- 添加新策略:在
-
保留其他所有内容:除非用户明确提出要求,否则不要修改
filesystem_policy、landlock、process或其他策略。
模式 B:创建新的策略文件
生成一个完整、独立的策略文件。使用完整的架构框架:
version: 1
filesystem_policy:
include_workdir: true
read_only:
- /usr
- /lib
- /proc
- /dev/urandom
- /app
- /etc
- /var/log
read_write:
- /tmp
- /dev/null
landlock:
compatibility: best_effort
network_policies:
# <generated policies go here>
上面的 filesystem_policy 和 landlock 部分是合理的默认值。
省略进程身份,以便所选计算驱动程序决定身份。对于
Docker 和 Podman,每个省略的身份字段都会回退到镜像的 OCI
USER。请告知用户这些是默认值,可能需要根据其环境进行调整。网关推断通过 openshell inference set/get 单独配置。生成的 network_policies 块是主要输出。
当用户明确请求 process.run_as_user 或
process.run_as_group 时,接受 sandbox 或介于 1 到
4294967294 之间的数字 UID/GID。拒绝 root(0)和无效身份哨兵值
(4294967295)。警告用户,较小的数字身份会继承镜像文件、挂载卷或设备上授予相同 ID 的权限。
对于 MicroVM,数字选择器必须与沙盒可写覆盖层解析出的所有者匹配。用户和组分别检查;任一不匹配都会阻止启动。如果所有者 UID:GID 未知,则省略选择器或使用 sandbox,以便驱动程序保留该身份。不要选择其他数字身份,也不要建议策略可以更改现有覆盖层的所有者。例如,所有者为 1000:1000 时,必须拒绝 UID 10000 的请求,并说明原因以及省略选择器或使用 sandbox 的替代方案,而不是生成会导致虚拟机无法启动的策略。
如果用户提供了文件路径,则写入该路径。否则,询问文件应放在哪里。常见做法是在项目本地放置策略文件(例如 sandbox-policy.yaml),并通过 openshell sandbox create --policy <path> 传入,或通过 OPENSHELL_SANDBOX_POLICY 环境变量设置。
模式 C:仅展示(不写入文件)
展示生成的策略 YAML,并包含:
- 摘要 — 用通俗语言说明策略允许和拒绝的内容
- YAML — 完整的
network_policies块,可直接粘贴 - 集成指南:
- 保存到本地文件,并通过
openshell sandbox create --policy <path>传入,或设置OPENSHELL_SANDBOX_POLICY=<path> - 用于生产环境:通过网关配置
- 保存到本地文件,并通过
- 注意事项 — 说明所作的假设,以及用户需要核实的内容
第 8 步:确认并完善
展示或应用策略后,询问用户是否想要:
- 收紧或放宽任何规则
- 添加更多端点或二进制文件
- 在 enforce/audit 模式之间切换
- 从预设切换为显式规则(或反向切换)
- 将策略应用到文件(仅展示时)
- 为其他 API 创建更多策略
快速参考:常见模式
仅 L4(无方法或路径规则)
my_api:
name: my_api
endpoints:
- { host: api.example.com, port: 443 }
binaries:
- { path: /usr/bin/curl }
使用只读预设的 HTTPS API
my_api_readonly:
name: my_api_readonly
endpoints:
- host: api.example.com
port: 443
protocol: rest
enforcement: enforce
access: read-only
binaries:
- { path: /usr/bin/curl }
使用显式规则的 HTTPS API
my_api_custom:
name: my_api_custom
endpoints:
- host: api.example.com
port: 443
protocol: rest
enforcement: enforce
rules:
- allow:
method: GET
path: "/api/v1/**"
- allow:
method: POST
path: "/api/v1/data"
binaries:
- { path: /usr/bin/curl }
- { path: /usr/local/bin/myapp }
HTTP(非 TLS)内部 API
internal_svc:
name: internal_svc
endpoints:
- host: api.internal.svc
port: 8080
protocol: rest
enforcement: enforce
rules:
- allow:
method: GET
path: "/health"
- allow:
method: POST
path: "/api/v1/jobs"
binaries:
- { path: /usr/bin/curl }
私有 IP 访问(主机 + 允许列表)
internal_db:
name: internal_db
endpoints:
- host: db.internal.corp
port: 5432
allowed_ips:
- "10.0.5.0/24"
binaries:
- { path: /usr/bin/curl }
私有 IP 访问(无主机 — 范围内的任意域名)
private_services:
name: private_services
endpoints:
- port: 8080
allowed_ips:
- "10.0.5.0/24"
- "10.0.6.0/24"
binaries:
- { path: /usr/bin/curl }
其他资源
- 策略架构
- 沙盒策略
- 默认策略
- Supervisor 中间件
- 默认策略:内置于 OpenShell 运行时
- 如需真实 API 文档中的翻译示例,请参阅 examples.md