Volver a la wiki

CF Access Service Token headers en workflows CI y scripts del Workspace

CF Access Service Token headers en workflows CI y scripts del Workspace

Resumen

Implementación del patrón de autenticación CF Access Service Token en los 8 workflows y 3 scripts del repo CreaRackSL-workspace que llaman a endpoints internos protegidos por Cloudflare Access. Introducido en PR#29 (2026-05-12) como Parte 2/2 de la migración a CF Access.

Motivación

Los endpoints workspace.crearack.com/api/biblioteca/, /api/maintenance/* y /api/mcp están protegidos por Cloudflare Access. Sin credenciales de CF Access, los workflows dependían de la policy bypass everyone — un hallazgo Critical en el informe CF Security Insights 2026-05-11.

Patrón de implementación

La estrategia es headers opcionales: si los secrets CF_ACCESS_CLIENT_ID / CF_ACCESS_CLIENT_SECRET no están definidos en el entorno, las requests funcionan igual que antes (sin los headers). Esto garantiza retrocompatibilidad y rollout seguro.

Bash (workflows con curl directo)

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 -sS -X POST \
  -H "Authorization: Bearer $MCP_TOKEN" \
  -H "Content-Type: application/json" \
  "${CF_HEADERS[@]}" \
  "https://workspace.crearack.com/api/mcp"

Los secrets se exponen al step via env: del workflow:

env:
  MCP_TOKEN: ${{ secrets.MCP_TOKEN }}
  CF_ACCESS_CLIENT_ID: ${{ secrets.CF_ACCESS_CLIENT_ID }}
  CF_ACCESS_CLIENT_SECRET: ${{ secrets.CF_ACCESS_CLIENT_SECRET }}

Python (urllib)

import os, urllib.request

headers = {
    "Authorization": f"Bearer {token}",
    "Content-Type": "application/json",
    "User-Agent": "Bibliotecario-Ingest/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

req = urllib.request.Request(url, data=payload, headers=headers, method="POST")

JavaScript / Node.js (fetch)

const headers = {
  'Content-Type': 'application/json',
  Authorization: `Bearer ${token}`,
  'User-Agent': 'bib-ast-ts/1.0',
};
const cfId = (process.env.CF_ACCESS_CLIENT_ID || '').trim();
const cfSecret = (process.env.CF_ACCESS_CLIENT_SECRET || '').trim();
if (cfId && cfSecret) {
  headers['CF-Access-Client-Id'] = cfId;
  headers['CF-Access-Client-Secret'] = cfSecret;
}
const res = await fetch(mcpUrl, { method: 'POST', headers, body });

Inventario de archivos modificados

Workflows con curl directo

ArchivoStep(s) afectado(s)Endpoint destino
.github/workflows/drift-cron.ymlInvoke /api/biblioteca/drift-run/api/biblioteca/drift-run
.github/workflows/wiki-curator.ymlInvoke wiki_curator_review via MCP/api/mcp
.github/workflows/wiki-lint.ymlwiki_lint_bulk (step 1) + wiki_lint_contradictions (step 2)/api/mcp
.github/workflows/wiki-lint-consolidation.ymlInvoke wiki_lint_contradictions mode=full/api/mcp
.github/workflows/wiki-utility.ymlInvoke wiki_utility_recompute via MCP/api/mcp

Scripts externos con sus workflows

ScriptWorkflow que lo invocaLenguajeUser-Agent
scripts/bib_ast_ts.mjsbib-reindex-ts.ymlNode.jsbib-ast-ts/1.0
.github/scripts/bib_ingest.pypost-merge-ingest.ymlPythonBibliotecario-Ingest/1.0
scripts/generate-weekly-report.pywiki-weekly-report.ymlPythonBibliotecario-Weekly-Report/1.0

Secrets de repositorio

SecretUso
CF_ACCESS_CLIENT_IDHeader CF-Access-Client-Id
CF_ACCESS_CLIENT_SECRETHeader CF-Access-Client-Secret

Añadidos manualmente via gh secret set. Corresponden al service token CF Access con ID 4879f9f4-... (duración forever).

Endpoints protegidos cubiertos

EndpointApp CF Access
https://workspace.crearack.com/api/biblioteca/biblioteca
https://workspace.crearack.com/api/biblioteca/drift-runbiblioteca
https://workspace.crearack.com/api/mcpmcp

Estado de despliegue

Véase también

Subir