Vai al contenuto

Cloudflare Access

A cosa serve

Cloudflare Access autentica identità umane e machine-to-machine prima che raggiungano l'API o l'Editorial MCP. Il public site è pubblico, ma il suo origin contenuti backend è server-to-server e non viene esposto al browser.

Componenti che lo usano

API Worker, Editorial MCP Worker e public-site Vercel server-side usano Access con applicazioni e identità separate per ambiente. Il browser non è un consumer dell'applicazione content.

Dati e artefatti scambiati

Access scambia assertion validate e identità normalizzate verso l'API. Il consumer Vercel invia i due header Service Token solo all'edge Cloudflare. D1 e i payload applicativi non contengono credenziali.

Boundary per ambiente

Consumer DEV PROD Capacità
Fra app Admin DEV app Admin PROD capability applicative owner
Postman/automazione approvata token e policy Admin DEV token e policy Admin PROD capability complete dell'operatore dopo verifica Access
Editorial MCP token MCP DEV token MCP PROD capability MCP controllata
Public site Vercel token, Rule Group e due shard content DEV token, Rule Group e due shard content PROD sole GET bounded di Issue, Topic, Knowledge Asset e Glossary Term
Release API smoke riuso token public-site DEV riuso token public-site PROD sole GET bounded, nessuna capability Admin o mutativa

Cloudflare rifiuta più di cinque destinazioni in una singola application. La boundary content di ogni ambiente usa quindi due shard provider non semantici:

  • Shard A: /issues, /issues/*, /topics e /topics/*;
  • Shard B: /knowledge-assets, /knowledge-assets/*, /glossary e /glossary/*.

Il parent esatto e il relativo wildcard per i discendenti sono destinazioni separate: nessun prefix wildcard può quindi includere parzialmente una route sibling. La partizione mantiene ogni coppia parent/discendenti nello stesso shard e non crea una seconda identità, capability o authority.

Entrambi gli shard referenziano la stessa policy riutilizzabile Service Auth, che include il Rule Group public-site dello stesso ambiente, e restituiscono 401 quando l'autenticazione fallisce. Non usare Any Access Service Token, Everyone o Bypass. /admin/*, /f/*, /newsletter/unsubscribe, le route di sistema e il namespace rimosso /public/v1/* non appartengono a nessuno shard.

Autenticazione e autorizzazione

Vercel invia CF-Access-Client-Id e CF-Access-Client-Secret a ogni fetch server-side. Non usa il cookie Access come contratto e non inoltra header, assertion o secret al browser, all'HTML o ai log pubblici.

Il GitHub Environment dello stesso ambiente può custodire una copia cifrata della medesima coppia con i nomi PUBLIC_CONTENT_ACCESS_CLIENT_ID e PUBLIC_CONTENT_ACCESS_CLIENT_SECRET. Soltanto lo step smoke API la riceve: non è disponibile al job scope, alle migration, ai deploy, allo smoke MCP o all'evidenza. Il canale non crea token, policy, identity o capability ulteriori.

Access autentica e ammette l'identità alla boundary. L'API resta responsabile di metodo, costo bounded e visibilità PUBLISHED/accepted. La public-site identity non è ammessa alla application Admin. Dopo la verifica di firma, issuer e audience Admin, una service identity non-MCP riceve la capability completa dell'operatore senza una seconda allowlist o mappa permessi nel Worker. Il solo Client ID applicativo conservato è AUTH_MCP_SERVICE_CLIENT_ID, necessario a riconoscere e limitare l'identità MCP prima del default operator. Una configurazione MCP mancante o malformata non blocca un operatore Admin non-MCP valido: il binding serve soltanto a riconoscere e limitare l'identità MCP dedicata.

Cosa possiede il provider

Cloudflare possiede Service Token, scadenza e revoca, Rule Group, applicazioni, policy Service Auth, audience, verifica edge e log Access.

Cosa possiede Architecture Coffee

Il repository possiede destinazioni attese, separazione DEV/PROD, contratto dei metodi GET, visibilità editoriale, mapping Admin residuo, naming, sequenza di validazione e rollback. Vercel possiede la custodia server-side della coppia secret consumer; il GitHub Environment corrispondente può custodirne la copia cifrata smoke-only.

Naming operativo

Risorsa DEV PROD
Service Token Architecture Coffee Public Site REST - DEV Architecture Coffee Public Site REST - PROD
Rule Group Architecture Coffee Public Site REST Consumers - DEV Architecture Coffee Public Site REST Consumers - PROD
Access application Shard A Architecture Coffee Public Content REST Shard A - DEV Architecture Coffee Public Content REST Shard A - PROD
Access application Shard B Architecture Coffee Public Content REST Shard B - DEV Architecture Coffee Public Content REST Shard B - PROD
Service Auth policy Public Site REST Service Auth - DEV Public Site REST Service Auth - PROD

Le coppie consumer sono distinte per ambiente. Il solo Client ID usato dal resolver Admin è quello MCP, custodito come secret Worker cifrato e non come variabile vars versionata.

Creazione e verifica

Prima di ogni mutazione registrare candidate SHA, inventario corrente e rollback. Per DEV, creare token, Rule Group, policy e i due shard applicativi; configurare i secret Vercel solo quando il consumer può usarli. Verificare in ordine:

  1. token DEV corretto su una GET bounded di ogni shard: successo;
  2. nessun token, token sconosciuto e token PROD sulla boundary DEV: 401;
  3. token public-site DEV su /admin/*: negato;
  4. metodo mutativo sui path content: nessuna route e nessun effetto;
  5. entrambi gli shard usano la stessa policy e il medesimo Rule Group;
  6. log ed evidenza privi di credenziali e payload.

Lo smoke repository-owned esegue sempre il controllo anonimo della protected front door. Con la coppia configurata esegue le letture e i filtri bounded, nega /admin/* e prova il fallimento cross-environment; senza la coppia opzionale registra esplicitamente not-run. Una coppia parziale o richiesta ma mancante fallisce chiusa. Il target credenziale è fissato all'origin ufficiale dell'ambiente, senza redirect, e non viene inviato alcun metodo mutativo.

Production usa la stessa sequenza soltanto nella finestra prevista dalle Issue mergiate. ADR-031 rende il merge Fra l'unico gate umano ordinario; una finestra di dipendenza non è un secondo go/no-go.

Operazioni automatiche, manuali e protette

La verifica Access per richiesta è automatica. Creazione, aggiornamento, rotazione, revoca e secret configuration sono operazioni provider distinte, esplicite e protette. Dopo il merge dell'Issue che le descrive, Codex le esegue senza un secondo gate ordinario e valida ogni stage prima del successivo.

Rotazione, revoca e rollback

La rotazione è create-before-revoke:

  1. creare il replacement token nello stesso ambiente;
  2. aggiungerlo al Rule Group senza rimuovere il token corrente;
  3. aggiornare la coppia Vercel e la copia GitHub Environment smoke-only dello stesso ambiente;
  4. validare letture autorizzate e negazioni;
  5. rimuovere il token precedente dal gruppo;
  6. revocarlo solo dopo evidenza deterministica.

Prima della revoca, il rollback ripristina secret e membership precedenti. Dopo una risposta provider ambigua, rileggere lo stato; non ripetere ciecamente la mutazione. La revoca d'emergenza rimuove prima il token dalla boundary e poi lo revoca, accettando che le letture Vercel falliscano chiuse fino al replacement.

Osservabilità sanitizzata

Registrare soltanto ambiente, nome risorsa, scadenza, famiglia route, outcome e correlation ID provider. Non registrare client secret, client ID raw, assertion, cookie, payload contenuto, email o risposta provider privata.

Fallimenti e comportamento fail-closed

Token mancante, scaduto, sconosciuto o cross-environment, Rule Group o policy errata, audience non valida e client Admin non esplicitamente configurato falliscono chiusi. Un effetto provider ambiguo richiede readback e non viene ritentato automaticamente.

Verifiche operative

Verificare sempre successo con il token corretto, 401 senza token e con token dell'altro ambiente, negazione di /admin/*, assenza di metodi mutativi sui path content, scadenza nominale, membership del solo Rule Group atteso e log sanitizzati. Lo smoke repository-owned riconosce separatamente il challenge Managed OAuth same-origin e la negazione Service Auth vincolata all'host con evidenza Access deterministica; un 401 generico non è prova del boundary.

Riferimenti canonici

brain/adr/ADR-032-cloudflare-access-service-to-service-content-boundary.json, brain/adr/ADR-035-reusable-protected-public-content-release-smoke.json, src/security/, docs/architecture/security.md, il runbook dello smoke e ADR-023 per il boundary MCP.