Cloudflare 边缘入口: 能力分工、Token 和保管
最后更新: 2026-08-17
本文面向操作人员, 说明各组织的外部安全入口由 Cloudflare 的哪三个能力构成、各自负责什么、需要在 Cloudflare 后台创建哪些凭据、如何限制权限, 以及如何存入本机 Vault. 不要把任何 Token、Client Secret 或包含它们的命令粘贴到 Issue、提交、日志或聊天中.
官方参考:
- 创建 API Token
- API Token 权限列表
- 创建 remotely-managed Tunnel
- 获取和轮换 Tunnel Token
- 发布 self-hosted 应用
- 创建 Access Service Token
1. 三个能力的分工
这三者经常被混为一谈, 但管的是互不重叠的事. 想清楚这一点, 权限清单和上线顺序就都是推论:
| 能力 | 负责 | 不负责 |
|---|---|---|
| Tunnel | 连通. 把内网服务接到 Cloudflare, 主机不开任何入站端口 | 不问请求背后是谁 |
| Access | 准入. 在边缘判断这个请求背后是不是我们认可的人或机器 | 不看请求内容是否是攻击 |
| WAF | 攻击面. 注入、恶意 bot、异常速率 | 不知道请求背后是谁 |
推论一: 只开 Tunnel 不开 Access, 等于把 origin 摆到公网上, 安全性完全落在应用自己的登录页上. 对本来就要公开的服务这是正常形态; 对内部服务不是.
推论二: Access 通过后 Cloudflare 会签发 JWT (CF_Authorization cookie). 单独部署时 origin 必须校验这个 JWT, 否则绕过 Cloudflare 直连源站就跳过了整层准入. 本项目的服务一律经 Tunnel 出去、源站不开入站端口, 这条绕过路径天然被堵死 —— 这正是 Tunnel 与 Access 成对出现的原因, 不是两个可以随意取舍的独立选项.
推论三: WAF 挡不住"凭据正确但不该进来的人", Access 挡不住"有权限的人发来的注入". 两者不能互相替代.
2. 归属: ZMUKE 是上级组织, 各业务是其下级组织
组织模型 (2026-08-15 确认): ZMUKE 是上级组织, 大脑主机即本机 (fleet 的控制面主机,
Workspace 划分里管理 Hub A/B、控制面主机、op-hub、business-hub 均属 zmuke).
slaunchx 和 mocalmax 是 ZMUKE 的下级组织:
- 每个组织有自己独立的 Gitea 与域名: slaunchx ->
gitea.slaunchx.cc(部署在别处,
不在大脑主机上); mocalmax -> gitea.mocalmax.cc (旧 gitea.8milex.com 过渡);
zmuke -> 本机 zmuke-gitea 容器 + gitea.zmuke.com.
- 每个组织有自己的 vault 业务域. Cloudflare 只管理一个账号; mocalmax 的在管
zone 是 mocalmax.cc. 8milex.com 是企业邮箱域, 不发 token.
- 归属不得从命名推断 (域名、容器名、profile 名记录的是历史), 必须以部署事实验证.
本文的凭据模板服务于每个组织; 落到 ZMUKE 自身时**这套 Cloudflare 凭据属于 zmuke
业务域**, 用 vault --business zmuke 保管, 与下级组织的凭据分开.
2.1 Cloudflare 侧: 同一账号, 每组织一张管理 token
Tunnel / Access 无法按 zone 切开. 再拆 Account token 与 Zone token 换不来隔离.
每组织一张够用的管理 token, Zone Resources 只含该组织 zone.
本账号服务 zmuke、slaunchx、mocalmax. mocalmax 在管 zone 是 mocalmax.cc.
8milex.com 不管理. 对照见 CLOUDFLARE_ZONES.md.
- 自动化用 Account API Token, 不用 User API Token.
- Zone Resources 禁止 All zones.
- Zero Trust 共用一个 team; Access 按 hostname 归属组织.
- 规则全文见 docs/ZMUKE_ORG_BASELINE.md 第 5 节.
3. 凭据集合
| 凭据 | 何时需要 | Vault 域 | Vault profile | Vault key |
|---|---|---|---|---|
| 组织管理 Token | 该组织 Tunnel / Access / DNS / WAF | 该组织 | cloudflare-<组织>-workspace-admin |
CLOUDFLARE_API_TOKEN, CLOUDFLARE_ACCOUNT_ID |
| CI / Pages Token | 只部署 Workers / Pages | 该组织 | cloudflare-<组织>-workers-deploy |
CLOUDFLARE_API_TOKEN, CLOUDFLARE_ACCOUNT_ID |
| Named Tunnel runtime token | cloudflared connector |
该组织 | cloudflare-<组织>-<服务>-tunnel |
TUNNEL_TOKEN |
| Access Service Token | 机器调用受 Access 保护的接口 | 该组织 | cloudflare-<组织>-access-<caller> |
CF_ACCESS_CLIENT_ID, CF_ACCESS_CLIENT_SECRET |
管理 token 与 CI token 分开, 是为了不让 Gitea Actions 拥有改 DNS / WAF / Tunnel
的能力. mocalmax-workers-deploy 已在 Gitea secret 中, 不要撤销.
存放 (D13, 2026-08-17): 3 张组织管理 token 双机同放 —— 大脑机与 debian-vm
各自 vault 的对应组织业务域, 同名 profile. 任一机器均可直接执行本组织边缘
操作. 此为 D11 双层边界的唯一例外, 决策记录见 zmuke-fleet-prototype
docs/DECISIONS.md D13; 其余管理凭据仍只在大脑机.
Zone ID 不进 vault. 用时 GET /zones?name=<根域名>.
管理 token 不得注入 Fleet Agent 或 cloudflared. 不创建 Global API Key.
凭据不进环境变量, 不进 shell profile. 历史上曾有工具把 Cloudflare 凭据写入 ~/.config/dev-env.sh 并由 ~/.profile source, 使该机器上每个进程和 Agent 都继承了它. 这与 Vault 模型直接冲突, 新 Token 不得重蹈; 发现此类残留应在轮换时一并清除.
4. 创建组织管理 Token
Cloudflare Dashboard -> Manage Account -> API Tokens -> Create Token -> Create Custom Token
名称: <组织>-edge-infra (zmuke / slaunchx / mocalmax 各一张).
| Scope | Permission group | Level |
|---|---|---|
| Account | Cloudflare Tunnel |
Edit |
| Account | Access: Apps and Policies |
Edit |
| Zone | Zone |
Read |
| Zone | DNS |
Edit |
| Zone | Zone WAF |
Edit |
| Zone | Analytics |
Read |
| Account | Cloudflare Pages |
Edit |
| Account | Workers R2 Storage |
Edit |
| Account | Access: Service Tokens |
Edit |
| Account | Account Filter Lists |
Edit |
Account Resources -> Include -> 只选这一个账号
Zone Resources -> Include -> Specific zone -> 只选该组织的 Zone
禁止 All zones. 不要加 API Tokens、Account Settings、
Zone Edit / Zone Settings、Billing. 设 TTL.
Pages / R2 与 Tunnel / Access 同为账号级资源, 无法按组织切 token; 组织归属靠
命名纪律 (项目/桶名带组织前缀). 管理 token 含 Pages/R2 Edit 供人和 Agent 做
项目创建、域名绑定、桶管理; CI 自动部署仍必须用下节的低权 deploy token,
不得把管理 token 放进 Gitea Actions secret.
DNS 代价: 能改该组织 Zone 的任意解析, 含邮件记录. MX/SPF/DKIM/DMARC 仍由人维护.
5. 创建 CI / Pages Token (按需, 已有的不要动)
名称 <组织>-workers-deploy. 只勾实际用到的 Account: Workers Scripts /
Pages / R2 / KV / D1. 不含 Tunnel、Access、WAF、DNS.
mocalmax-workers-deploy 已在 Gitea Actions secret 中, 不要重建或撤销.
6. 创建 Named Tunnel 和 runtime token
6.1 先创建 Tunnel
Cloudflare Dashboard -> Networking -> Tunnels -> Create a tunnel
选择 Cloudflared. 命名规则 <workspace>-<位置>-<服务>, 例如现网的 mocalmax-local-gitea.
创建 Tunnel 后, 先建 Access Application 和默认拒绝策略, 最后才发布 public hostname 和 DNS. 顺序颠倒会留下一个 hostname 已解析、准入尚未生效的裸露窗口.
6.2 提取 Token, 不执行展示命令
Networking -> Tunnels -> <tunnel> -> Add a replica
Cloudflare 会显示包含 Token 的 cloudflared 安装命令. 把命令复制到临时编辑器只取其中 eyJ... 的 Token, 不要执行这条展示命令 —— Token 会进入 shell history 和进程参数. 立即隐藏录入:
vault --business zmuke set cloudflare-zmuke-tunnel-<tunnel> TUNNEL_TOKEN
6.3 Connector 运行原则
- 同一 Tunnel 的多个副本共用该 Tunnel 的 runtime token, 部署在不同故障域; 建议分别靠近 Management Plane A 和 Plane B.
cloudflared只需出站连接, 不开放入站端口.- 禁止
noTLSVerify; connector 到 origin 也必须验证 TLS. - 不把管理 token 注入 connector.
生产 systemd unit 通过受限凭据注入提供 TUNNEL_TOKEN 或 TUNNEL_TOKEN_FILE, 不把 Token 写进 ExecStart.
7. Access Application 和策略
每个对外 hostname 一个 Application. 基本构成:
- 默认拒绝: 先建一条拒绝一切的兜底策略, 再往上加放行.
- 人的放行: 接 IdP (Google Workspace / GitHub / OIDC / SAML), 按邮箱域或 IdP 组放行, 要求 MFA. 无 IdP 时可用 One-time PIN; 配合 Require IP 白名单可作为所有者核定的长期方案 (ZMUKE 2026-08-15 决策), 前提是收件邮箱自身有 MFA.
- 机器的放行: 只有确实存在机器调用时, 才加 Service Auth 策略, 且只 Include 那一个具体 Service Token. 不要配置成允许所有 Service Token.
Access 不是 Fleet 的 RBAC. 通过 Access 只代表可以抵达这个 hostname; Fleet 自身的登录、Workspace 授权、step-up 和审计一个都不能少.
7.1 控制面的例外
Fleet 控制面的设计前提是零公网暴露 —— Agent 只经 OpenVPN overlay 抵达, 管理平面不对外. 把 Fleet 控制台发布到 Tunnel 是对这条前提的改变, 需要单独决策, 不属于常规操作. 若确实要发布:
- Access 是必需的, 不是可选项, 且必须默认拒绝 + 要求 MFA.
- Access 只是叠加的第一道门, 不替代 Fleet 自己的鉴权.
- 发布前后都要从未授权浏览器、授权浏览器和管理 VPN 三种位置分别验证.
8. Access Service Token
浏览器用户通过 IdP/MFA 登录, 不需要 Service Token. 只有 CI/CD 调用受保护接口、外部监控探针访问受保护健康检查等明确登记的自动化场景才创建.
Cloudflare Dashboard -> Zero Trust -> Access controls -> Service credentials -> Service Tokens
每个调用方单独创建, 设有限有效期. Client Secret 只显示一次:
vault --business zmuke set cloudflare-zmuke-access-<caller> CF_ACCESS_CLIENT_ID
vault --business zmuke set cloudflare-zmuke-access-<caller> CF_ACCESS_CLIENT_SECRET
profile 名带调用方, 是为了能单独吊销其中一个而不影响其他.
9. WAF 基线
- 对所有对外 hostname 开启托管规则集.
- 对登录、令牌签发、API 写入这类高风险路径配置速率限制.
- 规则先以 Log 模式观察再转 Block, 避免第一次上线就误伤正常流量.
- WAF 规则的变更经由该组织的
cloudflare-<组织>-workspace-admin, 变更要留记录.
10. 上线顺序
- 创建该组织的
*-edge-infra并存入 Vault. - 创建 Named Tunnel, 保存 runtime token.
- 配置 Tunnel 的 origin service, 使用可验证的 HTTPS.
- 创建 Access Application 和默认拒绝策略.
- 添加人的 Allow 策略, 要求 MFA.
- 仅在存在机器调用时添加具体的 Service Auth 策略.
- 配置 WAF 基线和高风险路径速率限制.
- 最后发布 public hostname 和 DNS 记录.
- 从未授权浏览器、授权浏览器和管理 VPN 分别验证访问行为.
第 8 步排在最后是本节的要点: 准入和防护先就位, 再让这个名字在公网上可解析.
11. 存入 Vault
zmuke 是独立业务域, 首次使用需要 init:
vault --business zmuke init
vault --business zmuke set cloudflare-zmuke-workspace-admin CLOUDFLARE_ACCOUNT_ID
vault --business zmuke set cloudflare-zmuke-workspace-admin CLOUDFLARE_API_TOKEN
vault --business slaunchx set cloudflare-slaunchx-workspace-admin CLOUDFLARE_ACCOUNT_ID
vault --business slaunchx set cloudflare-slaunchx-workspace-admin CLOUDFLARE_API_TOKEN
vault --business mocalmax set cloudflare-mocalmax-workspace-admin CLOUDFLARE_ACCOUNT_ID
vault --business mocalmax set cloudflare-mocalmax-workspace-admin CLOUDFLARE_API_TOKEN
Zone ID 不入库. 使用时 GET /zones?name=<根域名>.
每条命令都是隐藏输入. 检查键名, 不显示值:
vault --business zmuke list
vault --business slaunchx list
vault --business zmuke check
vault --business zmuke run cloudflare-zmuke-workspace-admin -- wrangler whoami
wrangler whoami 不代表每个写权限都已验证. 部署工具应先提供只读检查或 dry-run, 再执行写入.
12. 轮换和撤销
API Token
- 在 Cloudflare 创建权限完全相同的新 Token.
vault --business zmuke rotate <profile> CLOUDFLARE_API_TOKEN隐藏录入.- 运行身份检查和部署 dry-run.
- 确认新 Token 工作后撤销旧 Token.
- 记录轮换时间和下次到期日, 不记录 Token 值.
Tunnel runtime token
- Tunnel 页面选择
Rotate token. vault --business zmuke rotate cloudflare-zmuke-tunnel-<tunnel> TUNNEL_TOKEN.- 逐个重启副本, 每次确认 Tunnel 仍 healthy, 不要同时中断全部 connector.
- 若已泄露, 除轮换外还要在 Cloudflare 端强制断开旧连接.
Access Service Token
到期前刷新或创建替代 Token, 更新调用方后撤销旧的. Client Secret 丢失不可找回, 只能重新生成.
13. 检查清单
操作员手册,不要公开传播。不含 Token / Account ID / Zone ID。HANDOFF 不在此站。