Volver a la wiki

D19: CF Access Service Token en workflows y scripts de ingest de Biblioteca

D19: CF Access Service Token en workflows y scripts de ingest de Biblioteca

Contexto

La infraestructura de Biblioteca expone endpoints MCP en workspace.crearack.com protegidos por Cloudflare Access. Hasta la sprint s57 (2026-05-12), las políticas de CF Access incluían reglas de tipo bypass-everyone que permitían que los scripts de ingest y los workflows de GitHub Actions alcanzaran los endpoints usando únicamente el BIB_MCP_TOKEN (Bearer token JWT).

Un análisis de CF Security Insights marcó estas reglas bypass como hallazgos Critical, exigiendo su eliminación. Sin ellas, cualquier request que no presente un Service Token válido de CF Access es bloqueada en el edge antes de llegar a los Workers.

Decisión

Añadir soporte condicional para los headers CF-Access-Client-Id y CF-Access-Client-Secret en todos los puntos de llamada HTTP hacia la API MCP de Biblioteca. El soporte es opt-in vía variables de entorno: si CF_ACCESS_CLIENT_ID y CF_ACCESS_CLIENT_SECRET están vacías, el comportamiento es idéntico al anterior (retrocompatible).

Archivos afectados

ArchivoMecanismo
.github/scripts/bib_ingest.pyos.environ.get("CF_ACCESS_CLIENT_ID") → headers dict
.github/workflows/post-merge-ingest.ymlSecrets CF_ACCESS_CLIENT_ID / CF_ACCESS_CLIENT_SECRET → env
.github/workflows/push-drift.ymlSecrets → CF_HEADERS array en curl
scripts/bib_ast.pyos.environ.get("CF_ACCESS_CLIENT_ID") → headers dict
scripts/bib_docs.pyos.environ.get("CF_ACCESS_CLIENT_ID") → headers dict
scripts/bib_openapi.pyos.environ.get("CF_ACCESS_CLIENT_ID") → headers dict
scripts/bib-reindex.ps1[Environment]::GetEnvironmentVariable → $headers dict
scripts/cron-bib-reindex.shArchivos .cf-access-id / .cf-access-secret → CF_HEADERS array

Patrón de implementación (Python)

headers = {
    "Content-Type": "application/json",
    "Authorization": f"Bearer {token}",
    "User-Agent": "CreaRack-Bib.../1.0",
}
cf_id = os.environ.get("CF_ACCESS_CLIENT_ID", "").strip()
cf_secret = os.environ.get("CF_ACCESS_CLIENT_SECRET", "").strip()
if cf_id and cf_secret:
    headers["CF-Access-Client-Id"] = cf_id
    headers["CF-Access-Client-Secret"] = cf_secret

Patrón de implementación (Bash/curl)

CF_HEADERS=()
if [ -n "${CF_ACCESS_CLIENT_ID:-}" ] && [ -n "${CF_ACCESS_CLIENT_SECRET:-}" ]; then
  CF_HEADERS+=(-H "CF-Access-Client-Id: $CF_ACCESS_CLIENT_ID")
  CF_HEADERS+=(-H "CF-Access-Client-Secret: $CF_ACCESS_CLIENT_SECRET")
fi
curl ... "${CF_HEADERS[@]}" "$MCP_URL"

Origen de credenciales por entorno

EntornoFuente de las credenciales
GitHub Actions (post-merge-ingest)Secrets CF_ACCESS_CLIENT_ID / CF_ACCESS_CLIENT_SECRET
GitHub Actions (push-drift)Mismos secrets vía env:
Linux cron (cron-bib-reindex.sh)Archivos $DIR/.cf-access-id y $DIR/.cf-access-secret
Windows dev (bib-reindex.ps1)Variables de entorno de usuario (User scope)
Ejecución local PythonVariables de entorno del proceso

Consecuencias

Positivas:

Negativas / riesgos:

Alternativas descartadas

Estado

Implementado en PR#25, mergeado a main el 2026-05-12. Las políticas bypass-everyone deben eliminarse de CF Access dashboard en sprint s57 tras confirmar que los secrets están configurados en todos los entornos.

Véase también

Subir