Mapa crítico · Credenciales, dependencias y rotación entre plataformas
Para qué sirve esta página
Mapa único y vivo de todas las credenciales, tokens, claves API, deploy keys SSH, GitHub Apps y Service Tokens que conectan las plataformas del proyecto, junto con el grafo de dependencias entre ellas y los procedimientos de rotación/auditoría.
Complementa al [[entity—ops—catalogo-servicios-externos]] (que cubre qué pagamos y a quién) respondiendo a una pregunta distinta: qué credenciales tenemos en circulación, dónde viven, qué depende de cada una, cómo regenerarlas, cómo auditarlas.
Grado: 🔴 Crítico. La pérdida o expiración descontrolada de cualquier item de este mapa rompe partes del pipeline. La última crisis (migración GitHub User→Org · sesiones 74-76, 19/20-05-2026) reveló que sin un mapa unificado tardamos horas en detectar qué dejó de funcionar.
Mantenimiento: lifecycle: refresh-30d — el Bibliotecario marca esta página como pendiente de verificación cada 30 días. Owner: Edu.
✅ Inventario RE-VERIFICADO el 24-07-2026 (s235) contra las fuentes vivas: GitHub API (deploy keys, secrets, apps, toggle Org) + SSH a OPS (
100.96.245.233) y STAGE (100.96.254.204). Cambios estructurales desde la versión de mayo, ya incorporados abajo: Tailscale → NetBird (s85) · crons migrados de STAGE a OPS (s174-s201, deploy keys viejas 152056708/152056710 revocadas → 1 keycrearack-opspor repo) · firewalls solo-NetBird (s222) · rotaciones CF Access (s222-s223, playbook §9) y MCP_TOKENS (s216) · el deploy del workspace es un cron de OPS (el workflow “CF Pages Deploy” estádisabled_manually). El secret huérfanoCLAUDE_METHOD_DEPLOY_KEYdetectado en la verificación quedó RESUELTO el mismo día (decisión de Edu, opción a: secret borrado + workflow eliminado — ver §1.2).
Cuándo consultar este doc
- Auditoría rutinaria (mensual) — recorrer las secciones y validar que cada credencial sigue activa, dentro de su expiración y con scope correcto.
- Tras incidente de plataforma (transferencia de cuentas, cambios de Org, rotación masiva, leak sospechoso) — usar la matriz de dependencias para detectar qué se ha podido romper en cascada.
- Onboarding de nuevo dev — explicarle dónde vive cada credencial y por qué.
- Antes de regenerar una credencial — ver en la matriz qué se va a ver afectado y avisar a Dani/Txell si aplica.
- Cuando el Help Widget, Pulse, widget CI Pipeline, MCP handlers o cualquier integración externa empiece a dar
401/403/404desde un día concreto — es casi siempre un token caducado o desactivado por cambio de cuenta upstream.
Cómo usarlo
- Buscar qué credencial usa una funcionalidad → tabla “Matriz de dependencias plataforma → credencial” abajo.
- Ver scope y dónde está almacenada una credencial → tabla “Inventario” en su categoría (PATs, Deploy Keys, OAuth, API Keys, Service Tokens, GitHub Apps).
- Regenerarla → sección “Procedimientos de rotación” con el paso a paso de cada tipo.
- Validar el sistema entero post-cambio → script de auditoría al final de la página.
Mapa visual de plataformas raíz
Las 11 plataformas raíz de las que dependen las 3 plataformas del proyecto (CreaRack Pro, Workspace, claude-method):
flowchart LR
GH[GitHub Org<br/>CreaRackSL]
CF[Cloudflare<br/>Workers + Pages + DNS + Access]
HET[Hetzner<br/>PROD + STAGE + OPS + Object Storage]
DOK[Dokploy<br/>en PROD + STAGE]
AI_G[Google AI Studio<br/>Gemma 4]
AI_A[Anthropic API<br/>Claude Haiku]
RES[Resend<br/>email transaccional]
ZOH[Zoho<br/>Calendar + Mail]
HOL[Holded<br/>facturación]
NB[NetBird<br/>VPN mesh solo-NetBird]
UR[UptimeRobot<br/>monitoring externo]
GH -->|deploy| CF
GH -->|deploy keys SSH| HET
GH -->|App| DOK
CF -->|D1 + R2 + Vectorize + AI binding| CF
CF -->|CF Access JWT| HET
HET -->|crons OPS| GH
HET -->|VictoriaMetrics scrape| HET
DOK -->|deploy| HET
CreaRackPro[CreaRack Pro<br/>SaaS Django] --> HET
CreaRackPro --> AI_G
CreaRackPro --> AI_A
CreaRackPro --> RES
Workspace[Workspace<br/>Astro + Pages Functions] --> CF
Workspace --> GH
Workspace --> AI_G
Workspace --> AI_A
Workspace --> ZOH
Workspace --> HOL
Workspace --> RES
UR -.->|check| CreaRackPro
1 · Inventario de credenciales por categoría
1.1 GitHub Personal Access Tokens (PATs)
Tokens fine-grained emitidos por Esquembri (cuenta personal Owner del Org CreaRackSL) con resource owner = CreaRackSL Org.
| Token | Almacenado en | Repos accedidos | Scopes | Expira | Última regeneración | Usado por |
|---|---|---|---|---|---|---|
| GH_PAT | CF Pages workspace env var (crearacksl-workspace, environment production) | CreaRack-Pro, CreaRackSL-workspace, claude-method | Contents:Read+Write (workspace) · Contents:Read (Pro+method) · Actions:Read (Pro) · Issues:Read+Write · Pull requests:Read · Metadata:Read | 2027-05-20 | 2026-05-20 (s76) | Widget CI Pipeline (/api/health), Pulse hot-cache.ts fetchRecentCommits, /api/wiki/translate, /api/wiki/content, MCP handlers wiki.ts/github.ts/docs.ts, /api/biblioteca/wiki-titles |
WORKSPACE_REPO_TOKEN (⚠️ el secret se llama así, NO WORKSPACE_REPO_PAT — verificado 24-07) | GitHub Actions secret en repo CreaRack-Pro (creado 28-05-2026) | CreaRackSL-workspace (read-only) | Contents:Read · Metadata:Read | ~2027-05 | 2026-05-28 | Workflow audit-docs-drift.yml (lee estructura de wikis para auditoría) |
| routine-maintenance-weekly | claude.ai routine (cuenta Edu) | 3 repos (read-only) | read-only | ~2027-05-13 | 2026-05 | Routine Maintenance-Weekly (memoria reference_github_pat_routine_maintenance) |
| ghcr-pull-crearack-base | /root/.docker/config.json en STAGE+PROD (+ env GHCR_PULL_TOKEN PC de Edu) | GHCR (classic read:packages) | pull de ghcr.io/crearacksl/crearack-base | classic (revisar) | 2026-07-17 (s224/s227) | Deploys Dokploy: FROM crearack-base (playbook §10; si un deploy falla en el FROM con unauthorized → re-login) |
| ATLAS_CHECK_PAT | GitHub Actions secret workspace (01-07-2026) | CreaRack-Pro (read) | contents read | sin fecha registrada | 2026-07-01 | Cron atlas-check (lunes 07:00 UTC) |
Regla operativa: cualquier PAT nuevo del proyecto debe crearse con resource owner = Org CreaRackSL, NUNCA bajo cuenta personal de un dev. El motivo está documentado en el footgun gh_cli_token_owner_removal (s75): si un PAT está atado al usuario y ese usuario deja el Org, el PAT pierde scope silenciosamente.
1.2 Deploy keys SSH (read-only) · ✅ VERIFICADO 24-07-2026
Estado real post-migración a OPS (las 2 keys de la era STAGE — staging-bib-reindex 152056708 y Bibliotecario Reindex (Oraculo Fase 2) 152056710 — fueron revocadas en s201):
| Deploy key (GitHub) | Repo | ID | Estado | Privkey (en OPS /root/.ssh/) | Host alias | Usada por |
|---|---|---|---|---|---|---|
| crearack-ops (read-only) | CreaRack-Pro | 156242312 | enabled · RO · alta 03-07-2026 | github_crearack | github-crearack | Cron bib-reindex de OPS (git pull del Pro cada 10 min) |
| crearack-ops (read-only) | CreaRackSL-workspace | 156242314 | enabled · RO · alta 03-07-2026 | github_workspace | github-workspace | Crons bib-reindex-ws + cf-pages-deploy de OPS |
| crearack-ops (read-only) | claude-method | 156242315 | enabled · RO · alta 03-07-2026 | github_claude_method | github-claude-method | Cron bib-reindex-ws claude-method de OPS (lun/jue 00:30) |
✅ Resuelto 24-07-2026 (decisión de Edu, opción a): el secret
CLAUDE_METHOD_DEPLOY_KEY(huérfano — su pubkey 152056710 fue revocada en s201) se borró del workspace, y el workflowbib-reindex-claude-method.yml(sin runs desde 16-06, dispatch manual roto) se eliminó del repo. El reindex de claude-method lo cubre el cronbib-reindex-wsde OPS. Reversible: el.ymlsigue en el historial de git y una deploy key nueva se emite en 1 min si algún día se quiere el fallback en Actions.
Toggle Org obligatorio (verificado true 24-07): la Org CreaRackSL tiene deploy_keys_enabled_for_repositories: true. Si vuelve a false (default al crear Org Free), TODAS las deploy keys quedan en enabled: false silenciosamente. Toggle a nivel Org → https://github.com/organizations/CreaRackSL/settings/security_analysis (o via API gh api -X PATCH orgs/CreaRackSL -F deploy_keys_enabled_for_repositories=true).
Footgun documentado en s76: tras transferir un repo desde User a Org, las deploy keys que tenía el User quedan asociadas con added_by: <user-bridge> y aunque el toggle Org esté activo, GitHub puede devolver enabled: false hasta re-añadirlas. Procedimiento de recuperación abajo.
1.2bis Crons por servidor · ✅ VERIFICADO por SSH 24-07-2026
Inventario canónico completo: AUTOMATISMOS.md del workspace. Foto verificada:
OPS (crearack-ops · 100.96.245.233) — TODOS los crons de mantenimiento:
Cron (/etc/cron.d/) | Horario | Qué hace |
|---|---|---|
bib-reindex | cada 10 min (+extras :30 · communities 04:00) | Reindex AST del Pro al grafo |
bib-reindex-ws | supercontext 00:45 · ts+claude-method lun/jue 00:15-00:30 · chunks 01:30 · wiki 01:00 (full dom 02:00) | Reindex corpus workspace/método |
biblioteca-crons | lint 04:30 · lint-cons dom 03:00 · curator lun/jue 05:00 · utility L-X-V 06:00 · drift 06:00 · escriba 04:15 · enrich 04:50 | Mantenimiento del Bibliotecario |
cf-pages-deploy | cada 10 min | Deploy real del workspace (pushes a main desplegados en ≤10 min) |
gh-actions-watchdog | cada 5 min | Vigila workflows de Actions |
cron-heartbeat | cada 30 min | Telemetría de que los crons viven |
docker-prune | dom 05:30 | Limpieza runners CI |
STAGE (crearack-staging · 100.96.254.204) — limpio tras la F3 (s201), solo DR:
| Cron | Horario | Qué hace |
|---|---|---|
cron-dr-backup.sh | diario 00:00 | Export D1 del workspace a /opt/dr-backups/ |
cron-gdrive-sync.sh | dom 03:00 | Sync offsite |
cron-stale-check.sh | diario 08:00 | Vigila frescura de los backups |
dr-backups-purge | sáb 04:30 | Retención |
(+ /opt/workspace-mirror = mirror DR estático :8090.)
Workflows de GitHub Actions: siguen activos Ingest (post-merge), Catalog, Curator*, Lint*, Utility*, Drift-Check*, Weekly-Report, Reindex-TS/Supercontext*, D1 Cleanup, atlas-check, CI, Rotate-MCP-Tokens (*varios con schedule comentado — la ejecución real es el cron OPS; queda workflow_dispatch). CF Pages Deploy y Escriba drift cron están disabled_manually (migrados a OPS) y bib-reindex-claude-method.yml fue eliminado (24-07, opción a).
1.3 OAuth tokens (Zoho per-user)
3 tokens OAuth almacenados en D1 tabla zoho_oauth del workspace (multi-user desde migración s68 0027). Cada miembro del staff autoriza su propia cuenta Zoho.
| Usuario | refresh_token | access_token | Scopes |
|---|---|---|---|
| Edu | guardado en D1 (singleton legacy migrado fila Edu) | refrescado on-demand, ~1h vida | ZohoCalendar.event.ALL · ZohoCalendar.calendar.READ · ZohoMail.tasks.READ · ZohoMail.accounts.READ · ZohoMail.messages.READ+CREATE |
| Dani | guardado en D1 | idem | idem |
| Txell | guardado en D1 | idem | idem |
App OAuth Zoho (Server-based) registrada en api-console.zoho.com cuenta esfericlabs.com. client_id + client_secret viven en CF Pages env vars ZOHO_CLIENT_ID + ZOHO_CLIENT_SECRET. Detalle en [[runbook—zoho-integration-end-to-end]].
Procedimiento re-autorización (cuando un refresh_token deja de funcionar tras revoke manual desde Zoho UI o tras cambio de scopes): cada usuario va a https://workspace.crearack.com/settings/integrations/zoho y pulsa “Autorizar mi cuenta”. El admin puede actuar por delegación con ?as=Edu|Dani|Txell (requiere ADMIN_EMAILS env var del workspace que incluya al actor). IMPORTANTE: en flujos admin, hacer logout en mail.zoho.eu entre cada ?as= para no contaminar el token con cuenta cruzada (footgun s68 feedback_zoho_logout_between_admin_oauth).
1.4 API keys de proveedores externos
Claves de proveedores third-party. No son PATs ni OAuth; son tokens estáticos con scope total sobre la cuenta. Política: NUNCA commitearlas, NUNCA en plain text en docs, SIEMPRE en secrets de plataforma.
| Servicio | Variable | Almacenada en | Usado por | Owner billing |
|---|---|---|---|---|
| Anthropic API | ANTHROPIC_API_KEY | CF Pages workspace + GitHub Actions secret workspace + Pro + Dokploy env var PROD + STAGE | Workspace MCP handlers Tutor/CNS · Bibliotecario Curator/Lint Haiku 4.5 · CreaRack Pro alternativa CNS/Tutor/Explain | Edu (pay-as-you-go) |
| Google AI Studio (Gemma 4) | GOOGLE_AI_API_KEY | CF Pages workspace + GitHub Actions secret workspace + Dokploy env var CreaRack-Pro PROD + STAGE | Workspace Oráculo/Tutor/Help · Wiki-Translate cron · CreaRack Pro Auto-Plan + Help Widget (via google-genai SDK) | Edu (pay-per-use) |
| Resend | RESEND_API_KEY | Dokploy env var CreaRack-Pro PROD + STAGE + CF Pages workspace | Django Anymail (transaccional outbound) · workspace /api/mcp send_maintenance_email | Edu (free tier) |
| Holded | HOLDED_API_KEY | CF Pages workspace env var | MCP handlers holded_* del workspace (lista contactos, invoices, leads, products, expenses, treasury) | Txell (Esferic Labs SL) |
| Cloudflare API | CLOUDFLARE_API_TOKEN (scope Pages) + CLOUDFLARE_D1_TOKEN (scope D1) + CLOUDFLARE_ACCOUNT_ID | GitHub Actions secrets workspace | Workflow D1 Cleanup · scripts wrangler manuales (el deploy del workspace ya NO va por Actions — cron OPS) | Edu |
| CF_CLAUDE_TOKEN | CF_CLAUDE_TOKEN | env var User del perfil de Edu | Huecos del MCP de Cloudflare (Security Center, Rulesets — el MCP no cubre Access) | Edu |
| MCP_TOKENS workspace | MCP_TOKENS (formato nombre:token,... · rotados s216: 3 personales + CI) | CF Pages workspace + GitHub Actions secret MCP_TOKEN en ambos repos (rotado 10-07) + env var User de cada perfil (BIB_MCP_TOKEN) | Bearer auth de los endpoints /api/mcp/* desde Claude Code MCP connector + crons Bibliotecario | Edu |
| MAINTENANCE_AGENT_TOKEN | MAINTENANCE_AGENT_TOKEN | CF Pages workspace env var | Bearer estático adicional para routines claude.ai headless que no pueden completar OAuth interactivo (s69) | Edu |
| Hetzner API | HETZNER_API_TOKEN | CF Pages workspace env var | MCP get_servers_status (resto de gestión = panel manual) | Edu |
| NetBird | (no usada programáticamente · panel app.netbird.io) | n/a | gestión manual de la VPN: peers, grupos, setup keys | Edu |
| UptimeRobot | (no usada programáticamente · solo panel) | n/a | monitoring externo de PROD | Edu |
Secrets por repo verificados 24-07-2026 — Pro: ANTHROPIC_API_KEY · CF_ACCESS_CLIENT_ID/SECRET (secret 14-07 ✓ rotación s222) · MCP_TOKEN (10-07 ✓ rotación s216) · WORKSPACE_REPO_TOKEN. Workspace (9 tras borrar el huérfano CLAUDE_METHOD_DEPLOY_KEY): los anteriores + ATLAS_CHECK_PAT · CLOUDFLARE_ACCOUNT_ID/API_TOKEN/D1_TOKEN · GOOGLE_AI_API_KEY. claude-method: vacío ✓.
1.5 Cloudflare Access Service Tokens
⚠️ Rotado en s222-s223 (14-07-2026): el secret vigente y el inventario de las 6 copias a sincronizar en cada rotación viven en el playbook canónico [[crearack-tech—guides—secret-rotation-playbook]] §9. La policy de
/api/mcpes Service Auth (un token en policy Bypass NO autentica — footgun s223).
Tokens emitidos desde el panel CF Zero Trust → Service Auth → Service Tokens. Cada uno autoriza llamadas headless a un endpoint protegido por CF Access sin pasar por OAuth de Google/GitHub.
| Service Token | App CF Access | Scope (path) | Almacenado en | Usado por |
|---|---|---|---|---|
Workspace API - Bibliotecario crons + MCP (Client ID c0cfca1ac691...access) | CreaRackSL Workspace (policy “Service Tokens (crons)”) + Workspace MCP API + API Biblioteca | workspace.crearack.com (todo) + /api/mcp + /api/biblioteca/ | Ver inventario de 6 copias en playbook §9 (GH secrets ×2 repos · OPS · /opt/dr-backups/.cf-access STAGE · Dokploy PROD+STAGE · env vars User) | Backend Django /help widget proxy · pre-commit hook bib_report_check.py · cron DR backup (STAGE) · crons bib-reindex (OPS) |
| Maintenance Weekly Agent | CreaRackSL Workspace (policy “Service Tokens (crons)”) + Workspace MCP API (extendida con MAINTENANCE_AGENT_TOKEN Bearer) | workspace.crearack.com + /api/mcp | claude.ai routine “Maintenance Weekly” en cuenta Edu (panel routines) | Bypass OAuth headless de routine claude.ai (s69). Se combina con MAINTENANCE_AGENT_TOKEN Bearer estático |
Toggle bypass-everyone: el endpoint /.well-known/cloudflare-access-protected-resource/* y /.well-known/version.json tienen política “Bypass Everyone” (público) para que el banner detector versión y OAuth discovery funcionen sin auth. Cualquier otro endpoint del workspace está detrás de CF Access standard.
Arquitectura policies a nivel cuenta (s78 · 21-05-2026): la UI actual de CF Zero Trust trata las policies como objetos a nivel cuenta reutilizables. La policy Service Tokens (crons) (acción Service Auth) se asocia simultáneamente a varias apps. Eliminada en s78 la app específica DR Backup Service (workspace.crearack.com/api/maintenance/*) tras causar bucle de redirect 302 para usuarios staff: la app más específica tumbaba el SSO de CreaRackSL Workspace. Path /api/maintenance/* ahora cubierto por la app principal (policy “Team only” para users + “Service Tokens (crons)” para tokens). Footguns relacionados: [[footguns_cf_access_app_path_specificity]] · [[footguns_cf_access_service_token_requires_service_auth_action]] · [[footguns_cf_access_account_policies_need_app_link]] (memorias locales staff).
1.6 GitHub Apps instaladas en Org · ✅ VERIFICADO 24-07-2026
| App | Repos | Por qué |
|---|---|---|
Cloudflare Workers and Pages (cloudflare-workers-and-pages) | all | Status checks PR + eventos push para CF Pages dashboard. NO es la vía de deploy del workspace — el deploy real es el cron cf-pages-deploy de OPS (cada 10 min). |
Dokploy PROD (dokploy-2026-05-25-xsayav) | selected | Webhooks de auto-deploy del panel Dokploy de PROD (alta 25-05-2026). |
Dokploy STAGE (dokploy-2026-05-25-9dn7kh) | selected | Idem para STAGE. |
Webhooks salientes clásicos en repos: 0 (esperado — las Apps los reemplazan).
1.5.bis Cloudflare Access · policy de usuarios (login del staff)
Además de los Service Tokens (1.5), la app CreaRackSL Workspace tiene una policy de usuarios humanos que define quién puede entrar a workspace.crearack.com con su login Google/GitHub. Es lo que valida el acceso de Edu, Dani y Txell al workspace.
| Policy | App CF Access | Tipo | Emails autorizados (estado esperado) |
|---|---|---|---|
| Email staff (o “Team only”) | CreaRackSL Workspace | Include → Emails | eesquembri@esfericlabs.com · dfuentes@esfericlabs.com · tfuentes@esfericlabs.com |
Caso Dani (verificar en panel): existió un desajuste histórico por el cual el login de Dani usaba el email legacy
dfuentes@edomo.netmientras la policy exigíadfuentes@esfericlabs.com. Acción de verificación (no hay forma de comprobarlo desde docs): en CF Zero Trust → Access → Policies → policy “Email staff” de la app “CreaRackSL Workspace”, confirmar que (a) la lista incluyedfuentes@esfericlabs.comy NOdfuentes@edomo.net, y (b) el email con el que Dani autentica realmente vía Google/GitHub OAuth coincide con el de la policy. Si Dani entra y recibe 403, casi siempre es este desajuste email-policy. (Nota: Dani verificado operativo al 100% el 15-07, task #199 — el riesgo residual es solo si se recrea la policy.)
Regla: cualquier alta/baja de miembro del staff toca esta policy. Mantener los 3 emails @esfericlabs.com alineados con la allowlist Resend (1.7 / email-routing) y con los onboardings.
1.7 Otros secretos críticos del workspace
| Secret | Tipo | Almacenado en | Uso |
|---|---|---|---|
| CSRF cookies + session secrets Django | env var | Dokploy CreaRack-Pro PROD + STAGE | Sesiones cookies del SaaS |
| PostgreSQL credentials | env var | Dokploy CreaRack-Pro PROD + STAGE | Conexión pgbouncer → db (app conecta como crearack_app NOSUPERUSER desde s215 — RLS activo) |
| Valkey password | env var | Dokploy CreaRack-Pro PROD + STAGE | Conexión cache + broker Huey |
| CF_ACCESS_AUD | env var | CF Pages workspace + CreaRack-Pro PROD/STAGE | Validación JWT CF Access (audience tag) |
R2 bucket task-attachments | binding wrangler.toml | wrangler.toml del workspace + secret CF Pages | Almacenamiento adjuntos tasks workspace |
Vectorize index bib-chunks | binding wrangler.toml | wrangler.toml del workspace | Embeddings BGE-M3 del corpus Bibliotecario (1644 vectors backfilled s73) |
2 · Matriz de dependencias plataforma → credencial
Permite responder rápido: “si rompo X, ¿qué deja de funcionar?”.
| Plataforma raíz | Credenciales que la conectan al sistema | Si la credencial cae… |
|---|---|---|
GitHub Org CreaRackSL | GH_PAT (workspace) · WORKSPACE_REPO_TOKEN (Pro) · 3 deploy keys crearack-ops · Apps CF + Dokploy ×2 | Widget CI Pipeline DIM · Pulse sin commits · wiki translate/edit roto · crons de reindex de OPS no pulean · audit-docs-drift falla · auto-deploys Dokploy no reciben push events |
| Cloudflare | CLOUDFLARE_API_TOKEN + CLOUDFLARE_D1_TOKEN + CLOUDFLARE_ACCOUNT_ID · Service Tokens (Help Widget + Maintenance Agent) · App CF Workers and Pages | Cron D1 Cleanup falla · Help Widget Django sin acceso a MCP workspace · routine Maintenance Weekly sin acceso a MCP |
| Hetzner PROD | SSH key Edu vía NetBird (100.96.156.31 — SSH público cerrado desde s222) | Pérdida acceso shell · gestión solo via panel Dokploy (también tras NetBird) |
| Hetzner STAGE | SSH key Edu vía NetBird (100.96.254.204) | Dokploy panel STAGE inaccesible · DR backups (00:00) + gdrive-sync + stale-check paran · mirror DR nginx:8090 inaccesible |
| Hetzner OPS | SSH key Edu vía NetBird (100.96.245.233) · 3 privkeys deploy /root/.ssh/github_* | Runners CI parados (CI vuelve a minutos de Actions) · TODOS los crons de mantenimiento parados · deploy del workspace parado (cron cf-pages-deploy) |
| Anthropic API | ANTHROPIC_API_KEY | Tutor MCP roto · Bibliotecario Curator/Lint roto (Haiku 4.5) · CreaRack Pro CNS/Tutor/Explain (alternativo) sin fallback Claude · routines claude.ai siguen porque usan plan Max, no API |
| Google AI Studio | GOOGLE_AI_API_KEY | Oráculo de EL roto · Wiki-Translate roto · CreaRack Pro Auto-Plan + Help Widget rotos · Tutor sin chain de fallback |
| Resend | RESEND_API_KEY | Email transaccional CreaRack Pro roto (verificación cuenta + reset password + alertas) · workspace send_maintenance_email roto · routine Maintenance Weekly no manda informe |
| Zoho | OAuth refresh_tokens (3 usuarios) + ZOHO_CLIENT_ID + ZOHO_CLIENT_SECRET | Auto-events de ciclo de vida task (crear/cerrar/reabrir/borrar) no sincronizan a Calendar · widget agenda+tasks home workspace vacío · acciones ”+ Crear evento” / ”+ Vincular email” desde TaskModal rotas |
| Holded | HOLDED_API_KEY | MCP handlers holded_* rotos (financial summary, listar invoices/leads/expenses, etc.) · Edu/Txell pierden vista financiera desde workspace · facturación manual desde panel Holded sigue funcionando |
| NetBird | grupo servers + dispositivos staff (SSO) | Pérdida de TODO el acceso de gestión a los servidores (firewalls solo-NetBird desde s222: SSH, Dokploy, proxies VM/PG) · las apps públicas siguen vivas tras CF |
| UptimeRobot | (cuenta Edu) | Sin alertas externas si PROD cae. No es bloqueante porque hay redundancia con health checks Dokploy. |
3 · Procedimientos de rotación / regeneración
3.1 Regenerar GH_PAT workspace (caso s76)
Cuándo: cuando alguna funcionalidad del workspace que llama a GitHub API empieza a dar 401/403/404. Caso típico: cambio de membresía Org, token expirado, scope insuficiente.
Pasos:
- Ir a
https://github.com/settings/personal-access-tokens/new(cuentaEsquembri, Owner del Org). - Configurar:
- Token name:
GH_PAT workspace (CF Pages) - Resource owner:
CreaRackSL(Org, no User personal — crítico) - Expiration: 1 año
- Repository access: Only select repositories → marcar los 3:
CreaRack-Pro,CreaRackSL-workspace,claude-method - Repository permissions:
- Metadata: Read
- Contents: Read and write
- Actions: Read
- Issues: Read and write
- Pull requests: Read
- Token name:
- Si la Org requiere aprobación: aprobar en
https://github.com/organizations/CreaRackSL/settings/personal-access-tokens-requests(auto-aprueba si eres Owner). - Subir a CF Pages env vars:
pnpm wrangler pages secret put GH_PAT --project-name=crearacksl-workspace. Pegar el token cuando pida valor. - Disparar redeploy: push cualquier commit a main del workspace — el cron
cf-pages-deployde OPS lo despliega en ≤10 min. (El workflow “CF Pages Deploy” de Actions estádisabled_manually— NO usarlo.) - Validar widget CI Pipeline del dashboard salud — debe mostrar
5/5con color verde y “última: success”.
3.2 Regenerar WORKSPACE_REPO_TOKEN
Mismo procedimiento que 3.1 con scopes mínimos: solo Contents:Read + Metadata:Read sobre el repo CreaRackSL-workspace. Subir a gh secret set WORKSPACE_REPO_TOKEN --repo CreaRackSL/CreaRack-Pro y validar con gh workflow run audit-docs-drift.yml --repo CreaRackSL/CreaRack-Pro.
3.3 Re-añadir deploy key (caso s76)
Cuándo: cuando un cron de OPS falla con Repository not found o un workflow falla con ERROR: Repository not found / fatal: Could not read from remote repository. Causa típica: transferencia Org → deploy keys quedan enabled: false.
Pre-requisito: verificar que la Org tiene el toggle global activo:
gh api orgs/CreaRackSL | python -c "import sys,json; print('deploy_keys_enabled_for_repositories =', json.load(sys.stdin).get('deploy_keys_enabled_for_repositories'))"
Si devuelve False: gh api -X PATCH orgs/CreaRackSL -F deploy_keys_enabled_for_repositories=true.
Pasos para re-añadir la key (sin tocar la privkey que ya está en OPS /root/.ssh/github_*):
# 1. Listar keys actuales para obtener id y pubkey
gh api repos/CreaRackSL/<repo>/keys
# 2. Borrar la entry rota
gh api -X DELETE repos/CreaRackSL/<repo>/keys/<id>
# 3. Re-añadir con misma pubkey
gh api -X POST repos/CreaRackSL/<repo>/keys \
-f title="crearack-ops (read-only)" \
-f key="ssh-ed25519 AAAA... <comment>" \
-F read_only=true
Validación (vía NetBird): ssh root@100.96.245.233 "cd /opt/<repo> && git pull" debe devolver “Already up to date” sin warnings (host aliases: github-crearack · github-workspace · github-claude-method).
3.4 Re-autorizar Zoho (per-user)
Ver runbook dedicado: [[runbook—zoho-integration-end-to-end]] sección “Autorizar mi cuenta Zoho”.
3.5 Rotar API key Anthropic / Google AI / Resend / Holded
Patrón común:
- Crear nueva key en panel del proveedor (sin borrar la vieja todavía).
- Subir a TODOS los almacenes donde se usa (mirar tabla 1.4 — varios servicios viven en 3+ sitios distintos: CF Pages env vars + GitHub Actions secrets + Dokploy env vars PROD + STAGE).
- Disparar redeploys de cada plataforma (CF Pages: push a main → cron OPS · Dokploy: redeploy del servicio en panel).
- Validar end-to-end con un caso real (mandar email test, generar 1 respuesta IA, listar 1 invoice, etc.).
- Borrar la key vieja del panel del proveedor.
Footgun común: olvidar subir la key nueva a Dokploy STAGE o a uno de los entornos secundarios → funciona en uno y rompe en otro silenciosamente. Por eso el inventario por plataforma debe estar siempre completo.
3.6 Rotar Service Tokens CF Access
Fuente canónica: [[crearack-tech—guides—secret-rotation-playbook]] §9 — inventario de las 6 copias del secret a sincronizar (GH secrets ×2 repos · OPS · /opt/dr-backups/.cf-access STAGE · Dokploy PROD+STAGE · env vars User ×3) + registro de rotaciones. CF Zero Trust → Service Auth → Service Tokens → /rotate (mantiene el client-id). El token nuevo aparece UNA VEZ. Validar con curl explícito al endpoint protegido + redeploy del CreaRack-Pro. Recordar: la policy debe ser Service Auth, nunca Bypass (footgun s223).
4 · Auditoría rutinaria · script de verificación
Ejecutar mensualmente o tras incidente de plataforma. Cada comando debe devolver verde / lo esperado. (Última ejecución completa: 24-07-2026 ✅.)
# A) GitHub secrets de los 3 repos
gh secret list --repo CreaRackSL/CreaRackSL-workspace # esperado: 9 (ver §1.4)
gh secret list --repo CreaRackSL/CreaRack-Pro # esperado: 5 (ANTHROPIC, CF_ACCESS ×2, MCP_TOKEN, WORKSPACE_REPO_TOKEN)
gh secret list --repo CreaRackSL/claude-method # esperado: vacío
# B) Deploy keys vivas (esperado: 1 por repo, "crearack-ops (read-only)", enabled)
gh api repos/CreaRackSL/CreaRack-Pro/keys | python -c "import sys,json; [print(k['title'], '·', 'enabled' if k['enabled'] else 'DISABLED') for k in json.load(sys.stdin)]"
gh api repos/CreaRackSL/CreaRackSL-workspace/keys | python -c "import sys,json; [print(k['title'], '·', 'enabled' if k['enabled'] else 'DISABLED') for k in json.load(sys.stdin)]"
gh api repos/CreaRackSL/claude-method/keys | python -c "import sys,json; [print(k['title'], '·', 'enabled' if k['enabled'] else 'DISABLED') for k in json.load(sys.stdin)]"
# C) Org toggle deploy keys (esperado: True)
gh api orgs/CreaRackSL | python -c "import sys,json; d=json.load(sys.stdin); print('deploy_keys_enabled =', d['deploy_keys_enabled_for_repositories'])"
# D) Apps instaladas en Org (esperado: cloudflare-workers-and-pages + dokploy ×2)
gh api orgs/CreaRackSL/installations | python -c "import sys,json; [print(i['app_slug'], '·', i['repository_selection']) for i in json.load(sys.stdin)['installations']]"
# E) Crons scheduled todos verdes (workspace · los migrados a OPS no aparecen aquí, ver F)
gh run list --repo CreaRackSL/CreaRackSL-workspace --limit 30 --json conclusion,event,workflowName,createdAt | python -c "
import sys, json
runs = json.load(sys.stdin)
scheduled = [r for r in runs if r['event'] == 'schedule']
by_wf = {}
for r in scheduled: by_wf.setdefault(r['workflowName'], r)
for wf, r in by_wf.items():
flag = 'OK' if r['conclusion'] == 'success' else 'FAIL'
print(f\" [{flag}] {wf}: {r['conclusion']} at {r['createdAt']}\")
"
# F) OPS · crons y runners funcionando (vía NetBird; esperado: 7 crons de §1.2bis + logs frescos)
ssh root@100.96.245.233 "ls /etc/cron.d/ && tail -2 /opt/cron-heartbeat/cron-driver.log"
# G) STAGE · DR backups frescos (vía NetBird)
ssh root@100.96.254.204 "ls -lt /opt/dr-backups/ | head -5"
# H) PROD containers up (vía NetBird)
ssh root@100.96.156.31 "docker ps --format '{{.Names}}: {{.Status}}'"
# I) Smoke test endpoints públicos
curl -s -o /dev/null -w "PROD = %{http_code}\n" https://crearack.com/health
curl -s -o /dev/null -w "Workspace = %{http_code}\n" https://workspace.crearack.com # esperado 302 (CF Access)
curl -s -o /dev/null -w "Esferic Labs = %{http_code}\n" https://esfericlabs.com # esperado 200 (landing en vivo desde 10-07-2026)
Resultado esperado: todos los [OK] en E, crons presentes y heartbeat fresco en F, backups de hoy en G, contenedores Up X · healthy en H, HTTP esperados en I. Cualquier desviación = abrir incidente y volver a este doc para identificar la credencial afectada.
5 · Histórico · footguns conocidos y migraciones
| Fecha | Incidente | Causa raíz | Mitigación implementada |
|---|---|---|---|
| 2026-05-19 (s74) | Migración GitHub User → Org CreaRackSL | Transferencia consciente. Pro User cuenta renombrada a CreaRackSL-bridge. | Auditoría exhaustiva s76 + este doc. |
| 2026-05-19 (s74) | WORKSPACE_REPO_PAT inválido post-Org | PAT atado a User antiguo, scope perdido al transferir repos | Regenerado fine-grained s75 desde Esquembri (resource owner=Org). Memoria footguns_gh_cli_token_owner_removal. Hoy el secret se llama WORKSPACE_REPO_TOKEN (28-05). |
| 2026-05-19 (s74) | Branch protections perdidas en los 3 repos | Downgrade Pro User → Free Org temporal | Activado plan Team Org ($144/año, s75) + protections re-aplicadas. |
| 2026-05-20 09:59 UTC (s75) | Bibliotecario-Catalog scheduled fail | required_status_checks blockea bots con GITHUB_TOKEN default | Quitado required_status_checks del workspace (workspace tiene bots autónomos que pushean a main). CreaRack-Pro mantiene status checks (no tiene bots autónomos). Memoria footguns_branch_protection_blocks_bots. |
| 2026-05-20 (s76) | Widget CI Pipeline DIM · MCP wiki/github handlers rotos · cron STAGE bib-reindex falla git pull · workflow Bibliotecario-Reindex-ClaudeMethod falla git clone | Triple cascada: GH_PAT workspace ligado a User antiguo + 2 deploy keys enabled: false por toggle Org deploy_keys_enabled_for_repositories: false | Regenerado GH_PAT (resource owner=Org) + toggle Org activado + 2 deploy keys re-añadidas. Este documento creado como mapa unificado para futuras auditorías. |
| 2026-05-21 (s78) | Página /maintenance UI: TypeError: Failed to fetch + auth_status: NONE redirect a CF Access login | App DR Backup Service (path /api/maintenance/*) tumbaba SSO de la app principal CreaRackSL Workspace por specificidad de path. Su policy primaria era Service Token Bypass (modo service-auth-first) → users staff con OAuth válida quedaban fuera. | App DR Backup Service eliminada. Path queda bajo CreaRackSL Workspace. Policy nueva Service Tokens (crons) (acción Service Auth) creada a nivel cuenta y vinculada a la app principal — incluye Service Tokens Workspace API - Bibliotecario crons + MCP + Maintenance Weekly Agent. Cron DR backup nocturno + routine Maintenance Weekly siguen funcionando. 3 footguns nuevos documentados en memorias staff. |
| 2026-05-25 (s85) | — | Migración VPN | Tailscale → NetBird Cloud Free (tailnets borrados, Tailscale purgado de servidores). Peers y setup: memoria infra_servers + runbook--infra--hetzner-firewall-solo-netbird. |
| 2026-07-03 → 05 (s174-s201) | — | Migración crons STAGE → OPS | Servidor OPS (CX33) con 3 deploy keys nuevas crearack-ops (03-07) + revocación de las 4 keys viejas de STAGE (s201) + F3 limpieza de STAGE (solo queda DR). |
| 2026-07-10 (s216) | Auditoría workspace P1a | Token MCP compartido en ficheros locales ×3 | MCP_TOKENS rotados (3 personales + CI) · .mcp.json → ${ENV_VARS} · workflow rotate-mcp-tokens.yml. |
| 2026-07-14/15 (s222-s223) | Rotación CF Access + firewalls | Endurecimiento superficie externa F2 | Secret CF Access rotado (6 copias sincronizadas, playbook §9) · firewalls solo-NetBird · policy /api/mcp a Service Auth. |
| 2026-07-24 (s235) | Re-verificación completa de este mapa | Secret CLAUDE_METHOD_DEPLOY_KEY huérfano detectado (pubkey revocada en s201; workflow sin schedule desde 16-06, dispatch manual roto) | Opción a ejecutada (decisión Edu): secret borrado + workflow bib-reindex-claude-method.yml eliminado. El cron bib-reindex-ws de OPS cubre el reindex de claude-method. |
6 · Quién debe leer este documento
- Edu — owner principal. Lo mantiene actualizado, lo consulta antes de cualquier rotación y al cierre del refresh-30d del Bibliotecario.
- Dani — lo lee para entender qué credenciales puede tocar sin riesgo (la mayoría requieren acción Edu, pero algunas — Zoho per-user, redeploys — son auto-servicio).
- Txell — solo las secciones relacionadas con billing (1.4 columna “Owner billing”) y el cross-link con [[entity—ops—catalogo-servicios-externos]]. Si una credencial caduca y bloquea facturación (Holded, Resend), Txell sabrá a qué panel ir.
- Cualquier sustituto temporal de los 3 (Regla 24 igualdad de accesos del staff) — este doc es punto de entrada al sistema de credenciales del proyecto. Junto al onboarding wiki, debe permitir tomar el relevo sin acceso previo a la memoria del equipo.
7 · Mantenimiento de este documento
- Lifecycle:
refresh-30d. El Bibliotecario marca como pendiente de verificación cada 30 días. Edu valida sección por sección. - Cuándo actualizar:
- Cualquier rotación de credencial (anotar en sección 5 si el incidente fue significativo).
- Nueva integración con proveedor externo (añadir a tablas 1.4, 2 y procedimientos 3).
- Cambio de plan Org GitHub o Cloudflare que afecte permisos/toggles.
- Tras cualquier auditoría exhaustiva ejecutar comandos sección 4 y confirmar estado.
- Cross-links a mantener vivos: [[entity—ops—catalogo-servicios-externos]] · [[runbook—zoho-integration-end-to-end]] · [[crearack-tech—admin—email-routing-architecture]] · [[crearack-tech—guides—secret-rotation-playbook]].
Véase también
- [[entity—ops—catalogo-servicios-externos]]
- [[runbook—zoho-integration-end-to-end]]
- [[crearack-tech—admin—email-routing-architecture]]
- [[crearack-tech—guides—secret-rotation-playbook]]
- [[decision—20260516—auditoria-simplificacion-servicios-auxiliares]]