Building a Read-Only Cloudflare Worker AI Security Console A developer built a read-only Cloudflare Worker AI security console that uses Workers AI to summarize security data without granting the model write access. The console provides workflows for natural language queries, approved query catalogues, security digests, and Ray ID investigations, with Cloudflare Access protecting the interface. Security teams already have WAF events, bot signals, access logs, and SIEM pipelines. The problem is not always data collection. The problem is turning that data into a fast, readable operational view without giving a model unsafe authority. This implementation uses a Cloudflare Worker as the control layer and Workers AI as the summarization layer. The Worker is deliberately read-only. It supports four workflows: For staging examples, I will use example.com.dev . Do not treat that as a real environment. The model should not be the administrator. The Worker owns: Workers AI owns: That split matters. If the model is allowed to create arbitrary queries or perform Cloudflare write actions, the tool becomes much harder to govern. php 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 | Workflow | Endpoint | Output | |---|---|---| | Main menu | / | HTML | | Natural language query | /query | HTML table/cards with raw JSON toggle | | Approved query catalogue | /allowed-queries | HTML list with Copy and Use actions | | Security digest | /digest?range=7d | HTML report | | Latest scheduled digest | /digest/latest | HTML report from KV | | Ray ID investigation | /ray | HTML investigation report | | Health check | /healthz | JSON | This implementation should not: The right production pattern is: AI recommends, humans approve, Terraform or approved change control applies. You need: AI .Cloudflare documents Worker deployment through Terraform using cloudflare worker , cloudflare worker version , and cloudflare workers deployment . Worker version modules should use content file where practical to avoid storing large Worker code directly in Terraform state. See Cloudflare Workers IaC https://developers.cloudflare.com/workers/platform/infrastructure-as-code/ . Use these Worker bindings and variables: | Type | Name | Example | |---|---|---| | Workers AI binding | AI | Workers AI Catalog | | KV binding | DIGEST KV | sentinel-cf-uat-digests | | Secret | CF ANALYTICS TOKEN | Redacted | | Plain variable | APP HOSTNAME | sentinel-cf.example.workers.dev | | Plain variable | AI GATEWAY ID | sentinel-cf-gateway | | Plain variable | ALLOWED ZONE TAGS | Zone IDs, comma-separated | | Plain variable | ENVIRONMENT | uat | | Plain variable | DEFAULT DIGEST RANGE | 7d | | Plain variable | DIGEST TITLE | SENTINEL-CF Security Posture Digest | ALLOWED ZONE TAGS must contain Cloudflare Zone IDs, not domain names such as example.com.dev . For UAT, I prefer building the first version in the Cloudflare console. The console path makes it easier to prove each moving part before Terraform becomes the source of truth. The practical order is: In Cloudflare, create a dedicated API token for this Worker: php Manage account - Account API Tokens - Create Token - Create Custom Token Use the minimum read-only permission required by the Analytics GraphQL API: Permission group: Analytics Permission: Read Scope: Selected zone only Zone: example.com.dev Do not grant WAF edit, DNS edit, Access edit, Rules edit, or account administrator permissions. Store the value as: CF ANALYTICS TOKEN You will add it to the Worker as a secret later. Do not paste it into the Worker JavaScript. In Cloudflare: php Workers & Pages - Create Worker - Start with Hello World Use a simple name: sentinel-cf Deploy the starter Worker first. This proves the Worker route exists before adding the full security console code. Before exposing the security console, put Cloudflare Access in front of it. In the Worker creation flow or the Worker Access tab: Protect with Cloudflare Access: On Scope: All traffic Policy action: Allow Policy name: sentinel-cf-bootstrap-admin For a single UAT administrator, use your own verified identity. For a team, use an Access group or identity provider group instead of adding users one by one. A production policy should usually require: Open the Worker: php Workers & Pages - sentinel-cf - Bindings - Add binding - Workers AI Set: Variable name: AI Workers AI bindings allow Worker code to invoke models through env.AI.run ... . See Workers AI bindings https://developers.cloudflare.com/workers-ai/configuration/bindings/ . Create a KV namespace for the latest scheduled digest: php Workers & Pages - KV - Create namespace Use: sentinel-cf-uat-digests Then bind it to the Worker: php Workers & Pages - sentinel-cf - Bindings - Add binding - KV namespace Set: Variable name: DIGEST KV KV namespace: sentinel-cf-uat-digests KV is used only for storing the latest generated digest. It is not used for secrets. Create an AI Gateway for observability and control: php AI - AI Gateway - Create gateway Use: 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 Security analytics can contain sensitive paths, rule names, source geography, and investigation context. Treat AI Gateway logs as security logs and restrict who can read them. Open: php Workers & Pages - sentinel-cf - Settings - Variables and Secrets Add this secret: Type: Secret Name: CF ANALYTICS TOKEN Value: