安全团队用 Cloudflare Worker 构建只读控制层,配合 Workers AI 做自然语言安全查询和态势摘要,模型无写权限,通过固定 GraphQL 查询和区域白名单保障安全边界。
安全团队已经有 WAF 事件、机器人信号、访问日志和 SIEM 管道。问题往往不在于数据收集,而在于如何把这些数据转化成一个快速、可读的运营视图,同时又不赋予模型不安全的权限。
本实现使用 Cloudflare Worker 作为控制层,Workers AI 作为汇总层。Worker 是刻意设计为只读的。
它支持四个工作流:
自然语言安全查询。
经批准的查询目录,用于授权分析师提问。
AI 安全态势摘要。
Ray ID / 请求调查器。
分期示例中使用的是 example.com.dev,不要将其视为真实环境。
模型不应该是管理员
边界认证。
固定 GraphQL 查询。
在意图分类不够确定性时的意图分类。
安全态势摘要。
这个划分很重要。如果允许模型创建任意查询或执行 Cloudflare 写操作,这个工具就变得很难治理。
高层架构
flowchart TD
A[Security analyst] --> B[Cloudflare Access]
B --> C[sentinel-cf Worker]
C --> D[Scope and input validation]
D --> E[Cloudflare Analytics GraphQL]
D --> F[Workers AI via AI Gateway]
E --> G[Normalized metrics]
F --> H[Summary or explanation]
G --> I[HTML report]
H --> I
C --> J[Workers KV latest digest]
Worker 可以做什么
Worker 绝对不能做什么
本实现不应:
自动封禁 IP。
禁用托管规则。
修改 Access 策略。
查询任意 zone。
在源代码中存储密钥。
将 AI 输出当作正式的事件证据。
正确的生产模式是:AI 建议,人类审批,Terraform 或已批准的变更控制生效。
所需的 Cloudflare 组件
名为 AI 的 Workers AI 绑定。
Cloudflare Analytics GraphQL 访问。
用于存储定时摘要的 Workers KV 命名空间。
可选的 Cron Trigger 用于定时报告。
Cloudflare 通过 Terraform 部署 Worker,使用 cloudflare_worker、cloudflare_worker_version 和 cloudflare_workers_deployment。Worker 版本模块应尽可能使用 content_file,以避免将大型 Worker 代码直接存储在 Terraform 状态中。参见 Cloudflare Workers IaC。
运行时配置
使用以下 Worker 绑定和变量:
ALLOWED_ZONE_TAGS 必须包含 Cloudflare Zone ID,而不是域名,例如 example.com.dev。
先从控制台实现
对于 UAT,我更倾向于先在 Cloudflare 控制台中构建第一个版本。控制台路径使得在 Terraform 成为事实来源之前,更容易验证每个移动部件。
实际顺序是:
创建只读分析令牌。
引导 Worker。
用 Cloudflare Access 保护 Worker。
添加 KV 键值对。
添加运行时变量和密钥。
部署并测试 Worker。
然后用 Terraform 编纂已验证的设计。
在 Cloudflare 中,为此 Worker 创建一个专用 API 令牌:
Manage account -> Account API Tokens -> Create Token -> Create Custom Token
使用 Analytics GraphQL API 所需的最小只读权限:
Permission group: Analytics
Permission: Read
Scope: Selected zone only
Zone: example.com.dev
不要授予 WAF 编辑、DNS 编辑、Access 编辑、规则编辑或账户管理员权限。
CF_ANALYTICS_TOKEN
稍后你会将其作为密钥添加到 Worker 中。不要将其粘贴到 Worker JavaScript 中。
Workers & Pages -> Create Worker -> Start with Hello World
sentinel-cf
首先部署入门 Worker。这证明了 Worker 路由存在,然后才添加完整的安全控制台代码。
在暴露安全控制台之前,在其前面加上 Cloudflare Access。
在 Worker 创建流程或 Worker Access 选项卡中:
Protect with Cloudflare Access: On
Scope: All traffic
Policy action: Allow
Policy name: sentinel-cf-bootstrap-admin
对于单个 UAT 管理员,使用你自己已验证的身份。对于团队,使用 Access 组或身份提供商组,而不是逐一添加用户。
生产策略通常应要求:
企业身份提供商登录。
指定安全组成员身份。
短会话时长,例如 6 或 12 小时。
Workers & Pages -> sentinel-cf -> Bindings -> Add binding -> Workers AI
Variable name: AI
Workers AI 绑定允许 Worker 代码通过 env.AI.run(...) 调用模型。参见 Workers AI bindings。
为最新的定时摘要创建一个 KV 命名空间:
Workers & Pages -> KV -> Create namespace
sentinel-cf-uat-digests
然后将其绑定到 Worker:
Workers & Pages -> sentinel-cf -> Bindings -> Add binding -> KV namespace
Variable name: DIGEST_KV
KV namespace: sentinel-cf-uat-digests
KV 仅用于存储最新生成的摘要。不用于存储密钥。
创建 AI Gateway 用于可观测性和控制:
AI -> AI Gateway -> Create gateway
Gateway ID: sentinel-cf-gateway
Collect logs: On, if approved by your security policy
Cache responses: Off for security analytics
Rate limit requests: On for production
Spend limits: On for production
Authenticated Gateway: On where available
安全分析可能包含敏感路径、规则名称、来源地理和调查上下文。将 AI Gateway 日志视为安全日志,并限制谁可以读取它们。
Workers & Pages -> sentinel-cf -> Settings -> Variables and Secrets
Type: Secret
Name: CF_ANALYTICS_TOKEN
Value: <the read-only analytics token>
添加这些纯变量:
APP_HOSTNAME=sentinel-cf.example.workers.dev
AI_GATEWAY_ID=sentinel-cf-gateway
ALLOWED_ZONE_TAGS=<cloudflare-zone-id>
ENVIRONMENT=uat
DEFAULT_DIGEST_RANGE=7d
DIGEST_TITLE=SENTINEL-CF Security Posture Digest
ALLOWED_ZONE_TAGS 必须是 Cloudflare Zone ID,而不是域名。如果允许多个 zone,使用逗号分隔的列表:
ALLOWED_ZONE_TAGS=<zone-id-1>,<zone-id-2>
Workers & Pages -> sentinel-cf -> Edit code
用 sentinel-cf-worker.js 实现替换入门 Worker 代码并部署它。
部署的 Worker 默认应渲染 HTML。JSON 只在有意暴露的地方可用,例如 /healthz 或查询结果中的 Show raw JSON 部分。
https://sentinel-cf.example.workers.dev/healthz
{
"status": "ok",
"mode": "read_only",
"features": ["nlq", "allowed_query_catalog", "digest", "ray_id_investigator"]
}
https://sentinel-cf.example.workers.dev/allowed-queries
页面应显示已批准的分析师问题,包括:
使用 opens /query 并预填充所选问题和默认时间窗口。Worker 仍会强制执行固定只读意图和 zone 白名单。
https://sentinel-cf.example.workers.dev/query
尝试已批准的安全防御问题,例如:
Show me top source countries today
Show potential SQL injection events
Show blocked WAF events in the last 24 hours
Show top targeted URLs this week
Show noisy WAF rules in the last 7 days
安全 NLQ 页面应默认返回可读的卡片和表格,而不是原始 JSON。原始 JSON 仍可在 Show raw JSON 后获取以供验证。
https://sentinel-cf.example.workers.dev/digest?range=7d
返回的安全事件总数。
被阻止或挑战的计数。
嘈杂规则及其规则名称和规则 ID(如果有)。
AI 执行摘要。
https://sentinel-cf.example.workers.dev/ray
输入 Cloudflare 安全事件或响应头中的 Ray ID。
Cloudflare Ray ID 可用于跨安全事件、日志浏览器和服务器日志关联请求,但 Cloudflare 指出它们在所有情况下都不能保证唯一。参见 Cloudflare Ray ID。
手动摘要测试工作后,添加每周 Cron Trigger:
Workers & Pages -> sentinel-cf -> Settings -> Trigger events -> Cron triggers -> Add
使用每周 UTC 计划:
0 1 * * 1
Cloudflare Cron Trigger 在 UTC 时间运行,可能需要几分钟才能传播。参见 Cron Triggers。
当 cron 运行时,Worker 应生成摘要并将最新副本存储在:
DIGEST_KV
https://sentinel-cf.example.workers.dev/digest/latest
以确认存储的摘要可以渲染。
Terraform 实现第二步
控制台部署工作后,使用 Terraform 使设置对 UAT 和生产环境可重复。Terraform 应代表已验证的控制台配置,而不是引入单独的设计。
干净的 Terraform 交接应包括:
main.tf
variables.tf
outputs.tf
terraform.tfvars.example
sentinel-cf-worker.js
cron-trigger.tf.example
README.md
将 Worker JavaScript 保留在 sentinel-cf-worker.js 中并从 Terraform 引用它。这保持代码可审查,避免将大型 Worker 代码埋在 Terraform 内部。
重要的资源是:
resource "cloudflare_worker" "sentinel_cf" {
account_id = var.cloudflare_account_id
name = "sentinel-cf"
}
resource "cloudflare_workers_kv_namespace" "sentinel_cf_digests" {
account_id = var.cloudflare_account_id
title = "sentinel-cf-${var.environment}-digests"
lifecycle {
prevent_destroy = true
}
}
Worker 版本应绑定 Workers AI、KV、纯变量和只读密钥:
bindings = [
{
type = "ai"
name = "AI"
},
{
type = "kv_namespace"
name = "DIGEST_KV"
namespace_id = cloudflare_workers_kv_namespace.sentinel_cf_digests.id
},
{
type = "plain_text"
name = "APP_HOSTNAME"
text = var.app_hostname
},
{
type = "plain_text"
name = "AI_GATEWAY_ID"
text = var.ai_gateway_id
},
{
type = "plain_text"
name = "ALLOWED_ZONE_TAGS"
text = join(",", var.allowed_zone_tags)
},
{
type = "plain_text"
name = "ENVIRONMENT"
text = var.environment
},
{
type = "plain_text"
name = "DEFAULT_DIGEST_RANGE"
text = var.default_digest_range
},
{
type = "plain_text"
name = "DIGEST_TITLE"
text = var.digest_title
},
{
type = "secret_text"
name = "CF_ANALYTICS_TOKEN"
text = var.cf_analytics_token
}
]
将重要 URL 作为输出暴露:
output "worker_url" {
value = "https://${var.app_hostname}"
}
output "allowed_queries_url" {
value = "https://${var.app_hostname}/allowed-queries"
}
output "digest_url" {
value = "https://${var.app_hostname}/digest?range=${var.default_digest_range}"
}
output "ray_investigator_url" {
value = "https://${var.app_hostname}/ray"
}
terraform init
terraform fmt -recursive
terraform validate
terraform plan
如果 Worker 或 Access 应用已从仪表板存在,请在 apply 之前导入现有资源。在没有明确批准的情况下,不要让 Terraform 销毁和重新创建 Access 控制。
推荐的生產迁移是:
在 UAT 的控制台中构建和验证。
将最终 Worker 代码和 Terraform 文件放入版本控制。
在需要时导入现有的 Cloudflare 资源。
运行 terraform plan 并审查提议的更改。
只有在了解 Access、令牌范围、KV、AI 绑定和路由所有权后才能应用。
运营验证
使用单独的生产令牌。
使用单独的生产 Access 策略。
使用单独的 KV 命名空间。
保持 Terraform 状态加密和访问控制。
将 AI Gateway 日志限制为已批准的管理员。
确认 Worker 日志不暴露原始问题或密钥。
根据保留的 Logpush 或 SIEM 记录进行验证。
这是一个有用的模式,因为它为分析师提供了一种更快的方式来理解 Cloudflare 安全活动,而不会赋予自动化不安全的权限。
Worker 是护栏。AI 是分析师助手。Terraform 是控制平面。这种划分使设计在运营上可信。
对于进一步的操作,你可以考虑阻止此人并/或报告滥用