GrantBirki/fence
GitHub: GrantBirki/fence
Fence 是一个 GitHub Actions 安全 Action,通过 nftables 防火墙规则限制托管 runner 的出站网络访问,仅允许 GitHub 工作流流量和用户自定义白名单。
Stars: 0 | Forks: 0
# Fence 🛡️
[](https://github.com/GrantBirki/fence/actions/workflows/lint.yml)
[](https://github.com/GrantBirki/fence/actions/workflows/test.yml)
[](https://github.com/GrantBirki/fence/actions/workflows/build.yml)
[](https://github.com/GrantBirki/fence/actions/workflows/acceptance.yml)
[](https://github.com/GrantBirki/fence/actions/workflows/action-acceptance.yml)
[](https://github.com/GrantBirki/fence/actions/workflows/integration.yml)
Fence 首先在 GitHub Actions 作业中运行,仅允许 GitHub 工作流流量和您的 `allowlist`,阻止其他出站网络访问,并默认关闭无密码 sudo 和 Docker。

## 快速开始 ⚡
将 Fence 添加为受支持的 GitHub 托管 Linux 作业中的第一步:
```
- uses: GrantBirki/fence@
```
这一行将以 `block` 模式启动 Fence,并使用一个空的用户 `allowlist`。
Fence 目前支持 GitHub 托管的 `ubuntu-24.04` x64 主机作业。
默认情况下,Fence 允许 Actions 作业报告所需的 GitHub 域名。
它还允许 `github.com`、`api.github.com` 和
`release-assets.githubusercontent.com`,以便 Fence 可以在 checkout 和
常见设置步骤之前运行。这些被允许的 GitHub 域名仍然是后续工作流代码可以发送数据的地方。
GitHub 将作业日志和摘要上传到每次运行对应的 Azure 存储账户。
Fence 最多只授权四个确切的结果存储主机名,并且仅在
DNS 请求来自固定 GitHub runner 进程时才允许。它不允许
通用的 `*.blob.core.windows.net` 域名。
## 示例 🧪
首先在 audit 模式下运行,以查看哪些内容会被阻止:
```
- uses: GrantBirki/fence@
with:
mode: audit
```
允许一个普通的 HTTPS 主机名:
```
- uses: GrantBirki/fence@
with:
allowlist: |
api.example.com
```
允许自定义 TCP 端口上的主机名:
```
- uses: GrantBirki/fence@
with:
allowlist: |
registry.example.com:8443
```
使用显式行格式允许 UDP 或 CIDR 目标:
```
- uses: GrantBirki/fence@
with:
allowlist: |
udp://dns.example.com:53
cidr 192.0.2.0/24 udp 123
cidr 2001:db8::/64 tcp 443
```
保持 Docker/container 访问可用,同时仍然锁定网络和
无密码 sudo:
```
- uses: GrantBirki/fence@
with:
container_policy: unsafe_preserve
```
禁用宽泛的 GitHub Web/API/发布资产 allowlist 条目,同时
保持核心的 GitHub Actions 报告路径处于活动状态:
```
- uses: GrantBirki/fence@
with:
disable_broad_github_domains: true
```
仅在需要精确控制 agent-schema 时才使用原始 JSON:
```
- uses: GrantBirki/fence@
with:
config: >-
{"schema_version":1,"mode":"block","invocation_id":"my-job-1","allowlist":[]}
```
大多数用户不应设置 `invocation_id`。该 Action 会生成一个
`fence-${GITHUB_RUN_ID}-${GITHUB_RUN_ATTEMPT}` 格式的 ID。如果您使用原始 JSON,请为该作业运行将
`invocation_id` 设置为小写的唯一 slug。
## Allowlist 行 📝
原生 `allowlist` 输入接受每行一个条目:
```
example.com
example.com:8443
tcp://example.com:443
udp://dns.example.com:53
hostname example.com tcp 443
ip 192.0.2.10 tcp 443
cidr 192.0.2.0/24 udp 123
cidr 2001:db8::/64 tcp 443
```
空行和以 `#` 开头的行将被忽略。主机名快捷方式默认
使用 `tcp` 端口 `443`。IPv6 或非主机名条目应使用显式的
`ip` 或 `cidr` 格式。
Fence 会在锁定就绪前解析确切的主机名条目,并在作业运行期间
刷新其已批准的地址。随着 DNS 答案的变化,每个主机名都会保留您
配置的协议和端口。
## 工作原理 🔧
1. 您的工作流以 `uses: GrantBirki/fence@` 开始。
2. 该 Action 使用 root 用户拥有的、
只读的挂载来保护其作业后代码和捆绑的 agent。
3. 该 Action 在 `/run/fence/` 下写入一个由 root 拥有的微型配置。
4. 捆绑的 Fence agent 通过 `sudo` 和 `systemd` 启动。
5. Fence 检查 runner 是否符合受支持的 GitHub 托管 Linux 形态。
6. 在默认的 `block` 模式下,Fence 允许 GitHub 工作流流量和您的
`allowlist`,阻止其他出站网络访问,关闭无密码
sudo,并禁用 Docker/container 访问。
7. Fence 会持续运行直到 runner 被销毁,并记录本地证据。
网络发现可能包含有限的、尽力而为的本地进程归因。
8. 受保护的作业后 hook 会打印一份简明的 **Fence Summary**,其中包含控制
结果和观察到的网络活动,如果 Fence 发现
严重偏差,则会导致作业失败。
```
flowchart TD
start["GitHub-hosted Linux job starts"] --> action["Fence Action runs first"]
action --> input["Read native Action inputs
default: block mode + empty allowlist"] input --> protect["Protect Action runtime
root-owned + read-only"] protect --> config["Write root-owned config
under /run/fence/"] config --> launch["Launch bundled agent
with sudo + systemd"] launch --> support["Check supported runner shape"] support --> plan["Build network plan
GitHub workflow traffic + allowlist"] plan --> network["Apply Linux nftables rules
and local DNS handling"] network --> gate["Release approved DNS answers
after matching firewall access is verified"] gate --> mode{"Selected mode"} mode --> block["block
turn off passwordless sudo
turn off Docker"] mode --> degraded["unsafe_preserve
turn off passwordless sudo
keep Docker"] mode --> audit["audit
observe only
keep sudo and Docker"] block --> ready["Write ready/report files"] degraded --> ready audit --> ready ready --> resident["Fence keeps running
checks controls every 5 seconds"] resident --> post["Protected post hook
verifies runtime + evidence"] post --> summary["Render Fence Summary
fail on critical drift"] summary --> teardown["Runner teardown removes the VM"] ``` ## 模式 🎛️ | 模式 | 作用 | 使用时机 | | --- | --- | --- | | `block` | 阻止 GitHub 工作流流量和您的 `allowlist` 之外的网络流量;关闭无密码 sudo 和 Docker。 | 用于锁定作业的默认选项。 | | `block` 配合 `container_policy: unsafe_preserve` | 阻止网络流量并关闭无密码 sudo,但保留 Docker/container 访问权限。 | 当工作流需要 Docker 且您接受较弱的安全声明时。 | | `audit` | 不阻止流量。记录在转向 `block` 之前需要审查的内容。 | 在调整工作流时。 | ## 安全说明 🔒 Fence 减少了后续工作流步骤可以发送数据的位置,并移除了常见的 解除锁定的方法。它不是一个完整的沙盒,也不能使 runner 实现完美的密封。 默认的 GitHub allowlist 是一种可用性权衡。它保持正常的 GitHub Actions 报告、checkout、API 和发布资产流程正常工作,但后续的 工作流代码也可以将数据发送到这些允许的 GitHub 目标。如果您想从默认 allowlist 中移除 `github.com`、 `api.github.com` 和 `release-assets.githubusercontent.com`,请设置 `disable_broad_github_domains: true`。GitHub 确切的 runner 授权结果存储账户也 将成为作业其余部分的可访问目标;Fence 在本地记录该 授权并将其限制为 TCP 端口 `443`。 Fence 目前仅支持 GitHub 托管的 `ubuntu-24.04` x64 主机作业。 `ubuntu-latest` canary 是有用的信号,但它不会扩大支持 声明。请将 Fence 固定到完整的不可变 commit SHA,而不是 `@main`。 Fence 不会上传遥测数据。当它记录被阻止或将被阻止的 连接时,它可能会添加本地进程 ID、可执行文件基本名称、actor 类别 以及最多四个父可执行文件基本名称。进程竞争或共享套接字可能 导致 `not_found` 或 `ambiguous` 归因。Fence 从不记录命令 参数、完整的可执行路径、环境变量、工作目录或数据包 负载。 ## 故障排除 🧯 Fence 会在设置期间打印简短的进度日志,并在作业结束时打印一份简明的 **Fence Summary**,其中包含控制和网络活动表格。如果设置失败 且您需要更多详细信息,请通过将仓库密钥 `ACTIONS_STEP_DEBUG` 设置为 `true` 来启用 标准的 GitHub Actions 调试标志。调试日志包含有限的服务状态和 Fence 专有的诊断信息,但它们避免了原始配置主体、环境 值、数据包负载和不相关的系统日志。 ## 本地开发 ✈️ Fence 遵循 [Hermetic Builds](https://software.birki.io/posts/hermetic-builds/) 中描述的 飞机测试模型。请慎重准备 工具链,然后使用固定的 vendored 输入运行正常的项目命令。 ``` script/prepare-rust script/bootstrap script/test script/lint script/build ``` ## CLI 🧰 大多数用户应该使用该 Action。捆绑的 Rust agent 还公开了一个狭窄的 仅限 JSON 的 CLI: ``` fence --version fence check-support fence render-plan --config policy.json fence run --config /run/fence/example/config.json ``` 直接运行 `fence run` 会被拒绝,除非它是通过受信任的 Action/systemd 路径启动的。 ## 延伸阅读 📚 - [Fence v0 安全契约](docs/v0.md) - [威胁模型](docs/threat-model.md) - [安全策略](SECURITY.md) - [安全审查](docs/security-review.md) - [实施历史](docs/history.md) - [仓库设置](docs/repository-settings.md) - [Hermetic Builds](https://software.birki.io/posts/hermetic-builds/) ## 许可证 ⚖️ Fence 基于 [MIT License](LICENSE) 发布。
default: block mode + empty allowlist"] input --> protect["Protect Action runtime
root-owned + read-only"] protect --> config["Write root-owned config
under /run/fence/"] config --> launch["Launch bundled agent
with sudo + systemd"] launch --> support["Check supported runner shape"] support --> plan["Build network plan
GitHub workflow traffic + allowlist"] plan --> network["Apply Linux nftables rules
and local DNS handling"] network --> gate["Release approved DNS answers
after matching firewall access is verified"] gate --> mode{"Selected mode"} mode --> block["block
turn off passwordless sudo
turn off Docker"] mode --> degraded["unsafe_preserve
turn off passwordless sudo
keep Docker"] mode --> audit["audit
observe only
keep sudo and Docker"] block --> ready["Write ready/report files"] degraded --> ready audit --> ready ready --> resident["Fence keeps running
checks controls every 5 seconds"] resident --> post["Protected post hook
verifies runtime + evidence"] post --> summary["Render Fence Summary
fail on critical drift"] summary --> teardown["Runner teardown removes the VM"] ``` ## 模式 🎛️ | 模式 | 作用 | 使用时机 | | --- | --- | --- | | `block` | 阻止 GitHub 工作流流量和您的 `allowlist` 之外的网络流量;关闭无密码 sudo 和 Docker。 | 用于锁定作业的默认选项。 | | `block` 配合 `container_policy: unsafe_preserve` | 阻止网络流量并关闭无密码 sudo,但保留 Docker/container 访问权限。 | 当工作流需要 Docker 且您接受较弱的安全声明时。 | | `audit` | 不阻止流量。记录在转向 `block` 之前需要审查的内容。 | 在调整工作流时。 | ## 安全说明 🔒 Fence 减少了后续工作流步骤可以发送数据的位置,并移除了常见的 解除锁定的方法。它不是一个完整的沙盒,也不能使 runner 实现完美的密封。 默认的 GitHub allowlist 是一种可用性权衡。它保持正常的 GitHub Actions 报告、checkout、API 和发布资产流程正常工作,但后续的 工作流代码也可以将数据发送到这些允许的 GitHub 目标。如果您想从默认 allowlist 中移除 `github.com`、 `api.github.com` 和 `release-assets.githubusercontent.com`,请设置 `disable_broad_github_domains: true`。GitHub 确切的 runner 授权结果存储账户也 将成为作业其余部分的可访问目标;Fence 在本地记录该 授权并将其限制为 TCP 端口 `443`。 Fence 目前仅支持 GitHub 托管的 `ubuntu-24.04` x64 主机作业。 `ubuntu-latest` canary 是有用的信号,但它不会扩大支持 声明。请将 Fence 固定到完整的不可变 commit SHA,而不是 `@main`。 Fence 不会上传遥测数据。当它记录被阻止或将被阻止的 连接时,它可能会添加本地进程 ID、可执行文件基本名称、actor 类别 以及最多四个父可执行文件基本名称。进程竞争或共享套接字可能 导致 `not_found` 或 `ambiguous` 归因。Fence 从不记录命令 参数、完整的可执行路径、环境变量、工作目录或数据包 负载。 ## 故障排除 🧯 Fence 会在设置期间打印简短的进度日志,并在作业结束时打印一份简明的 **Fence Summary**,其中包含控制和网络活动表格。如果设置失败 且您需要更多详细信息,请通过将仓库密钥 `ACTIONS_STEP_DEBUG` 设置为 `true` 来启用 标准的 GitHub Actions 调试标志。调试日志包含有限的服务状态和 Fence 专有的诊断信息,但它们避免了原始配置主体、环境 值、数据包负载和不相关的系统日志。 ## 本地开发 ✈️ Fence 遵循 [Hermetic Builds](https://software.birki.io/posts/hermetic-builds/) 中描述的 飞机测试模型。请慎重准备 工具链,然后使用固定的 vendored 输入运行正常的项目命令。 ``` script/prepare-rust script/bootstrap script/test script/lint script/build ``` ## CLI 🧰 大多数用户应该使用该 Action。捆绑的 Rust agent 还公开了一个狭窄的 仅限 JSON 的 CLI: ``` fence --version fence check-support fence render-plan --config policy.json fence run --config /run/fence/example/config.json ``` 直接运行 `fence run` 会被拒绝,除非它是通过受信任的 Action/systemd 路径启动的。 ## 延伸阅读 📚 - [Fence v0 安全契约](docs/v0.md) - [威胁模型](docs/threat-model.md) - [安全策略](SECURITY.md) - [安全审查](docs/security-review.md) - [实施历史](docs/history.md) - [仓库设置](docs/repository-settings.md) - [Hermetic Builds](https://software.birki.io/posts/hermetic-builds/) ## 许可证 ⚖️ Fence 基于 [MIT License](LICENSE) 发布。
标签:GitHub Actions, 可视化界面, 开源安全防护, 网络访问控制, 自动笔记, 运行环境隔离, 通知系统