适用场景
手里有若干域名的 DNS、缓存、WAF 都在 Cloudflare 上,日常改一条解析、刷一次缓存、加一条 WAF 规则都要点控制台,重复且容易点错。这套方案把 Cloudflare 的操作封装成一个命令行工具,交给编码智能体(Claude Code、Cursor、各类支持 MCP 的客户端等)去调用,让你用一句自然语言完成批量操作。下面讲的不是"放权",而是"带着缰绳放权":一个专用 AI 词典:Token">Token、一个白名单入口、一份可回滚的备份。
说明:这里的 "Cf" 指代你实际安装的那个 Cloudflare 命令行工具——官方 CLI、官方 MCP server、或者自己用 API 封的小脚本都行,操作范式一致。具体包名和安装命令以官方文档当前版本为准。
环境与前置条件
- 操作系统:macOS、Linux 或 WSL2。Windows 原生终端下部分工具的行为不一致,建议走 WSL2。
- 运行时:如果走 Node 生态的 CLI / MCP server,需要 Node 18 以上(具体下限以官方文档当前版本为准);如果从源码编译 Go 写的官方 CLI,需要 Go 1.21 以上。Python 版本仅在你要写校验脚本时用到,3.9 以上即可。
- 内存与磁盘:常驻占用很小,2 GB 内存、1 GB 磁盘空间足够。真正占空间的是备份文件和历史日志,按域名数量估算,单个 zone 的 BIND 导出通常在几十 KB 量级。
- 网络:需要能访问
api.cloudflare.com。如果在受限网络里,提前把出口放通。 - 账号权限:你需要一个 Cloudflare 账号,并且对该账号下的目标域名有管理权限,能够创建 API Token。
- 前置工具:
curl和python3(用来格式化 JSON 输出)、jq(可选但推荐)。
一个重要的前提认知:不要让智能体使用 Global API Key。Global API Key 等于账号全权,无法收敛权限、无法按 zone 限制、也无法单独吊销。方案的全部安全性建立在"用 API Token 而不是 Global Key"这一点上。
分步骤部署
步骤 1:创建最小权限的 API Token
登录 Cloudflare 控制台,进入 My Profile → API Tokens → Create Token → Create Custom Token。
权限按"够用就好"的原则勾选,一个典型的内容站点可以这样配:
| 用途 | 权限项 | 级别 |
|---|---|---|
| 改解析 | Zone → DNS | Edit |
| 刷缓存 | Zone → Cache Purge | Purge |
| 改站点配置 | Zone → Zone Settings | Edit |
| 改 WAF 自定义规则 | Zone → Zone WAF | Edit |
几个关键点:
- Zone Resources 一定要限定,选 Include → Specific zone → 你的域名,而不是 All zones。这样即使 Token 泄漏,影响面也被锁死在一个域名里。
- TTL 设置到期时间,比如 90 天后过期,逼自己定期轮换。
- 不要勾 Account 级别的权限,除非任务确实需要(比如读审计日志)。账户级权限的影响面远大于 zone 级。
- 不同账号下权限项的显示名称会随产品线调整,以控制台实际列表为准。如果某个能力找不到对应权限项,先确认你的套餐是否包含该功能。
创建完成后,Token 只显示一次,立刻复制。
步骤 2:把 Token 落到本地密钥文件
不要写进 shell 的 ~/.bashrc,也不要提交进 Git 仓库。单独放一个目录:
```bash
mkdir -p ~/cf-agent/backup
umask 077
printf '%s' '把你的Token粘在这里' > ~/cf-agent/token
chmod 600 ~/cf-agent/token
cat > ~/cf-agent/env <<'EOF'
export CF_API_TOKEN="$(cat "$HOME/cf-agent/token")"
export CLOUDFLARE_API_TOKEN="$CF_API_TOKEN"
export CF_ZONE_ID="你的ZoneID"
export CF_ACCOUNT_ID="你的AccountID"
EOF
chmod 600 ~/cf-agent/env
```
CF_API_TOKEN 和 CLOUDFLARE_API_TOKEN 是两个常见环境变量名,不同工具读的不一样,两个都设上比较省事。CF_ZONE_ID 在控制台域名概览页右下角可以找到。
确认权限正确:
```bash
ls -l ~/cf-agent/token
期望输出:-rw------- 1 you you ... token
```
步骤 3:安装 CLI 工具
根据你选定的工具,任选一条路线。安装命令以官方文档当前版本为准,下面只给出范式。
路线 A:官方 Go 版 CLI
```bash
go install <官方仓库的 CLI 包路径>@latest
```
go install 会把二进制放到 $(go env GOPATH)/bin,确认这个目录在 PATH 里:
```bash
echo $PATH | tr ':' '\n' | grep -q "$(go env GOPATH)/bin" && echo "PATH OK"
```
路线 B:官方 MCP server(供支持 MCP 的智能体调用)
```bash
npx -y <官方 MCP server 包名>
```
首次运行会看到它启动并等待 stdio 输入,这属于正常现象,按 Ctrl+C 退出。随后在你的智能体客户端配置里把它注册成一个 MCP server,并把 CF_API_TOKEN 通过 env 字段注入进去。
路线 C:自己封装
如果暂时不想装任何东西,可以直接用 curl 包一层,功能一样:
```bash
cat > ~/cf-agent/cf.sh <<'EOF'
#!/usr/bin/env bash
set -euo pipefail
source "$HOME/cf-agent/env"
curl -sS -H "Authorization: Bearer $CF_API_TOKEN" \
-H "Content-Type: application/json" "$@"
EOF
chmod +x ~/cf-agent/cf.sh
```
步骤 4:写一个白名单入口,把智能体关进笼子
智能体拿到命令行后,可能做出你没预期的操作。给它一个受限脚本,只放行你认可的几类动作,同时记录每一条命令:
```bash
cat > ~/cf-agent/cf-guard.sh <<'EOF'
#!/usr/bin/env bash
智能体的唯一入口,只放行白名单动作,并落审计日志
set -euo pipefail
source "$HOME/cf-agent/env"
LOG="$HOME/cf-agent/audit.log"
CF="${CF_BIN:-cf}" # 换成你实际安装的可执行文件名
log() { printf '%s | %s\n' "$(date -u +%FT%TZ)" "$*" >> "$LOG"; }
case "${1:-}" in
dns-list)
log "dns-list zone=$CF_ZONE_ID"
exec "$CF" dns list --zone "$CF_ZONE_ID"
;;
dns-create)
shift
log "dns-create zone=$CF_ZONE_ID args=$*"
exec "$CF" dns create --zone "$CF_ZONE_ID" "$@"
;;
purge)
shift
log "purge zone=$CF_ZONE_ID args=$*"
exec "$CF" cache purge --zone "$CF_ZONE_ID" "$@"
;;
*)
echo "blocked: '${1:-}' 不在白名单内" >&2
exit 77
;;
esac
EOF
chmod +x ~/cf-agent/cf-guard.sh
```
子命令名称取决于你装的 CLI,先用 cf --help 核对再改上面的分支。
步骤 5:给智能体写一份操作约定
在项目根目录放一个 AGENTS.md(或你的客户端约定的规则文件),内容用大白话写清楚边界:
```markdown
Cloudflare 操作约定
- 只能执行
~/cf-agent/cf-guard.sh,禁止直接调用 api.cloudflare.com。 - 任何写操作前,先把当前状态导出到 ~/cf-agent/backup/,文件名带 UTC 时间戳。
- 删除 DNS 记录、修改 WAF 规则、切换 SSL/TLS 模式属于高风险操作,
必须先输出变更计划,等待人工确认后再执行。
- 单次任务最多改动 5 条 DNS 记录,超过就拆批。
- 收到 403 或 429 立即停止并回报,重试不超过 2 次。
```
步骤 6:建立变更前备份
DNS 记录可以从 API 导出为 BIND 格式的文本,改之前先存一份:
```bash
source ~/cf-agent/env
curl -sS -H "Authorization: Bearer $CF_API_TOKEN" \
"https://api.cloudflare.com/client/v4/zones/$CF_ZONE_ID/dns_records/export" \
> ~/cf-agent/backup/dns-$(date -u +%Y%m%dT%H%M%SZ).txt
head -5 ~/cf-agent/backup/dns-*.txt | tail -5
```
期望看到正常的 zone file 文本($ORIGIN、$TTL、若干 A/CNAME 记录)。需要回滚时按这份文件逐条重建记录;控制台也提供 BIND 文件导入功能,入口位置以控制台当前版本为准。
把这个目录纳入 Git 管理,每次变更都有一次 commit,回滚就是一次 git revert。
验证部署是否成功
1. Token 本身是否有效
```bash
curl -sS https://api.cloudflare.com/client/v4/user/tokens/verify \
-H "Authorization: Bearer $CF_API_TOKEN" | python3 -m json.tool
```
期望输出里 "success": true,且 result.status 为 active。如果这里是 false,先别往下走,去处理 Token 本身。
2. Token 能不能看到目标 zone
```bash
curl -sS "https://api.cloudflare.com/client/v4/zones" \
-H "Authorization: Bearer $CF_API_TOKEN" | python3 -m json.tool
```
期望结果里只出现你限定的那个域名。如果列出了账号下所有域名,说明 Zone Resources 选成了 All zones,回去重建 Token。
3. 权限收敛是否真的生效(负向测试)
用一个未授权的资源做一次调用,确认被拒:
```bash
curl -sS -o /dev/null -w "%{http_code}\n" \
-H "Authorization: Bearer $CF_API_TOKEN" \
"https://api.cloudflare.com/client/v4/accounts"
```
期望输出 403。返回 200 说明 Token 带了账户级权限,收敛没做到位。
4. 白名单入口是否可用
```bash
~/cf-agent/cf-guard.sh rm-rf-everything
期望:blocked: 'rm-rf-everything' 不在白名单内,退出码 77
~/cf-agent/cf-guard.sh dns-list | head
期望:列出你的 DNS 记录
```
5. 审计日志是否在写
```bash
cat ~/cf-agent/audit.log
```
期望看到带 UTC 时间戳的记录行,与刚才执行的命令一一对应。
三项都通过,就可以让智能体接手了。第一次给它一个只读任务,比如"列出 example.com 下所有 TTL 小于 300 秒的记录",核对输出无误后再放开写操作。
常见报错与解决
报错 1:HTTP 403,{"success":false,"errors":[{"code":10000,"message":"Authentication error"}]}
原因:Token 没传、传错,或者 Token 的权限范围不包含这次操作涉及的对象。常见于把 Token 粘进了 ~/.bashrc 但当前 shell 没有重新 source,或者 Zone Resources 选的是 All zones 而目标域名在别的账号下。
解决:
```bash
source ~/cf-agent/env
echo "${CF_API_TOKEN:0:8}..." # 确认变量非空
curl -sS https://api.cloudflare.com/client/v4/user/tokens/verify \
-H "Authorization: Bearer $CF_API_TOKEN"
```
如果 verify 通过但业务请求仍 403,回控制台检查这个 Token 的权限行,确认包含对应产品线和"Edit/Purge"级别。
报错 2:{"code":6003,"message":"Invalid request headers"}
原因:Authorization 头缺少 Bearer 前缀,或者用 Token 的同时又带了 X-Auth-Email / X-Auth-Key 这对老式头部,两种鉴权方式冲突。
解决:统一成一种,Token 场景只保留一行。
```bash
curl -sS -H "Authorization: Bearer $CF_API_TOKEN" \
"https://api.cloudflare.com/client/v4/user/tokens/verify"
```
报错 3:{"code":9109,"message":"Invalid access token"}
原因:Token 已在控制台被撤销或已过期;也可能是写入文件时末尾多了换行符或空格,被当成 Token 的一部分。
解决:重新生成一个 Token,写文件时用 printf 而不是 echo,避免尾随换行。
```bash
printf '%s' '新Token' > ~/cf-agent/token
chmod 600 ~/cf-agent/token
source ~/cf-agent/env
curl -sS https://api.cloudflare.com/client/v4/user/tokens/verify \
-H "Authorization: Bearer $CF_API_TOKEN"
```
报错 4:purge 或 DNS 操作返回类似 Invalid zone identifier / zone 不匹配
原因:CF_ZONE_ID 填成了域名,或者填了另一个 zone 的 ID。zone ID 是一串 32 位十六进制字符,不是域名。
解决:
```bash
curl -sS "https://api.cloudflare.com/client/v4/zones" \
-H "Authorization: Bearer $CF_API_TOKEN" \
| python3 -c "import sys,json; [print(z['name'], z['id']) for z in json.load(sys.stdin)['result']]"
```
把输出的 ID 抄回 ~/cf-agent/env 后重新 source。
报错 5:HTTP 429 Too Many Requests
原因:短时间批量操作触发了 API 频率限制,智能体循环调用时尤其常见。
解决:不要立刻重试。检查响应头里的 Retry-After,按它指定的秒数退避。同时在 AGENTS.md 里明确写上重试上限:
```bash
curl -sS -D - -o /dev/null -H "Authorization: Bearer $CF_API_TOKEN" \
"https://api.cloudflare.com/client/v4/zones" | grep -i retry-after
```
如果经常撞限额,把批量任务拆成小批次,或在脚本里加 sleep。
报错 6:npm error code EACCES 或 Cannot find module
原因:Node 版本低于工具要求,或全局安装目录没有写权限。
解决:优先用 npx 而不是全局安装,避免权限问题;Node 版本用 nvm 之类的方式切换,具体最低版本要求以官方文档当前版本为准。
```bash
node -v
npx -y <包名> --help
```
后续维护
备份与版本管理。 把 ~/cf-agent/backup/ 变成 Git 仓库,每次变更前导出一份 DNS,变更后提交。建议在 crontab 里加一条每日导出,保留最近 30 天:
```bash
0 3 * * * source ~/cf-agent/env && curl -sS -H "Authorization: Bearer \$CF_API_TOKEN" \
"https://api.cloudflare.com/client/v4/zones/\$CF_ZONE_ID/dns_records/export" \
> ~/cf-agent/backup/dns-$(date -u +\%Y\%m\%d).txt
```
Token 轮换。 按 TTL 到期时间提前重建。过渡期做法是同时创建新旧两个 Token,把新 Token 写进配置并验证通过后,再回控制台撤销旧的。轮换当天检查一遍 ~/cf-agent/audit.log,确认没有异常调用。
工具升级。 升级前先看官方仓库的变更说明,重点看子命令是否改名、环境变量是否变化。用 Node 生态的工具时,把版本号固定在 lockfile 里,不要无脑跟最新版;升级后跑一遍"验证部署是否成功"里的四项检查。
日志与监控。 两条线:一是 ~/cf-agent/audit.log,记录智能体发出的每条命令,用 logrotate 按月切分;二是 Cloudflare 侧的审计日志,在控制台 Manage Account → Audit Log 可以看,也可以通过 API 读取,需要具备审计日志读取权限的 Token。关注两个信号:短时间内出现大量 403,说明智能体撞到了权限墙,可能是任务描述不清;出现大量 429,说明任务该拆批了。
高风险操作的流程化。 删除记录、改 WAF 规则、切换 SSL 模式这三类操作,建议让智能体只输出变更计划,由人工执行或人工确认后执行。把这条写进规则文件比写进你的记忆更可靠。
定期做一次"权限体检"。 每季度跑一遍步骤 3 里的负向测试:用当前 Token 去调账户级接口,确认仍然返回 403。权限是会随着控制台改版和 Token 重建悄悄放大的,体检比出事后再排查省事得多。
