CreaRack-SL

Manual de Seguridad y Backups — Esferic Labs / CreaRack (fuente única)

Runbookactiveverificado 2026-07-02#seguridad#backups#dr#runbook#infra#onboarding

Manual de Seguridad y Backups — Esferic Labs / CreaRack

Fuente única del modelo de accesos, secretos y copias de seguridad de todo el ecosistema (SaaS + workspace + perfiles Claude). Creado en la auditoría s185 (02-07-2026) consolidando lo que estaba disperso en memorias, guías DR y el catálogo de servicios. Los procedimientos paso a paso de recuperación NO se duplican aquí: viven en [[crearack-tech—guides—disaster-recovery]] (SaaS) y [[workspace—guias—disaster-recovery-workspace]] (workspace).

Nota Regla 9: este manual es el artefacto vivo de seguridad del proyecto — la Regla 9 del CLAUDE.md apunta aquí (+ core/licenses.py para licencias de dependencias) desde s185.


1 · Mapa de accesos y servicios

La fuente de verdad del inventario es el catálogo de la wiki: [[entity—ops—catalogo-servicios-externos]] (22 servicios con owner, criticidad y panel de billing). Resumen del modelo:

  • GitHub org CreaRackSL: 4 repos privados; los 3 miembros son Owner (equipo plano, Regla 4/24).
  • Hetzner: PROD (CCX, 116.203.31.166, crearack.com vía Dokploy) + STAGE (CX23, 178.104.131.173, crons de Biblioteca + mirror DR). Acceso SSH por clave Ed25519 + firewall por IP.
  • Cloudflare: Pages (workspace), Workers/D1 (MCP + Biblioteca), Access (auth del workspace), R2 (latente), 3 zonas DNS.
  • Zoho (email, 8 grupos — factu@/legal@ solo Txell), Resend (transaccional), UptimeRobot (vigilancia externa), Google AI Studio (Gemma, Regla 8), Holded (facturación, independiente).
  • VPN NetBird (Cloud Free) para llegar a los servidores compartidos — alta de cada miembro en claude-method/guides/NETBIRD_SETUP.md.

⚠️ Riesgo estructural conocido (s185): Edu es owner y pagador único de los 6 servicios críticos con su cuenta personal. Plan: traspasar billing a la SL y documentar la sucesión de accesos antes de la constitución de septiembre 2026.

2 · Modelo de secretos

Dónde viven (y dónde NO):

ÁmbitoDónde vive el secreto
SaaS producción (12 secrets)Panel Dokploy → Environment. Lista canónica = variables declaradas en compose.prod.yml (detalle en [[crearack-tech—guides—disaster-recovery]])
Workspace (CF)CF Pages → Environment variables (encrypted) + Workers secrets
Recuperación offlineemergency/SECRETS_VAULT.md rellenado y guardado FUERA de git (la copia del repo es solo plantilla)
Perfiles ClaudeEnv vars de usuario Windows (BIB_MCP_TOKEN, METHOD_DOCTOR_TOKEN)
Clave de firma del Local Agent (Ed25519)C:\Users\<usuario>\.crearack\keys\agent_signing_ed25519.pem en la máquina de build (hoy la de Edu) — fuera del repo y del servidor. Firma los paquetes de auto-update (app-X.Y.Z.zip) del Lanzador Estable; la pública va embebida en terminal/agent/main.py (PACKAGE_PUBKEYS_HEX). Perderla = no poder publicar updates → regenerar (scripts/agent/generate_signing_key.py) + release de bootstrap con la pública nueva + recompilar la flota. Rotación: el bootstrap acepta lista de claves públicas. Generarla: [[concept—general—como-funciona-el-mecanismo-de-auto-update-del-loca]].

Bóveda del equipo (decisión s185): Bitwarden Teams — en implantación por Edu (task #33). Cuando esté operativa, será la fuente única de los valores; SECRETS_VAULT.md pasa a ser un índice.

Reglas:

  1. Nunca en git, wiki, WORKLOG ni Supercontexto — ni “temporalmente”. Si un secreto toca un fichero versionado, se considera comprometido: rotar, no solo borrar (el historial de git lo conserva).
  2. Env var nueva en Dokploy no llega al contenedor sin declararla en el compose (- VAR=${VAR:-}).
  3. CREDENTIAL_ENCRYPTION_KEY difiere a propósito entre STAGE y PROD — no “corregir”.
  4. Los secretos de dispositivos de clientes (SNMP/SSH) van cifrados at-rest en la BD y nunca llegan al navegador (patrón R3 de la Auditoría Suprema).

3 · Mapa de backups (el QUÉ, DÓNDE y CADA CUÁNTO)

QuéDóndeFrecuenciaRestore probado
PostgreSQL PROD (pg_dump)Hetzner Object Storage crearack-backups/postgres/ + local 14dDiario 03:00✅ 02-07-2026 (simulacro #1)
PostgreSQL PROD (WAL/PITR)Object Storage wal_archives/ (pérdida máx ~15 min)Cada 15 min❌ pendiente (simulacro #2)
D1 workspace (6 tablas)Hetzner STAGE /opt/dr-backups/ (30d)Diario 00:00✅ 02-07-2026 (integridad + conteos, simulacro #1)
D1 workspace offsiteGoogle Drive CreaRackSL/backups/workspace/ (30 copias)Domingos 03:00 (rclone)❌
Código + docsGitHub + clones en cada PCContinuo (git)✅ implícito
Perfiles Claude (memorias)Repo claude-backupsManual (claude-backup.ps1 -PushGit al cierre)❌ sin simulacro
Clave de firma del Agente (Ed25519, 119 B)~/.crearack/keys/ de Edu + backup cifrado hecho (07-07-2026)Al rotar la clave✅ respaldada
Media PROD (654 MB)⚠️ SOLO volumen Docker local — SIN offsite——
Config/secrets Dokploy⚠️ Copia única (BD interna de Dokploy)——
Snapshots Hetzner (servidor entero)⚠️ Pendiente de activar——
VictoriaMetrics (180d métricas)Solo volumen local (regenerable — aceptado)—N/A

Simulacros de restore realizados (acta)

  • #1 · 02-07-2026 (tarea #172, agente supervisado, 3 min 45 s): dump PG de las 03:00 (667 KB, sha256 verificado end-to-end) restaurado en un contenedor postgres:18-alpine desechable en STAGE → 0 errores de datos (solo 188 GRANTs benignos al rol dani_readonly, inexistente en un restore aislado — esperado) → conteos idénticos a PROD en las 5 tablas de control (5 orgs · 79 racks · 113 devices · 181 perfiles · 8 users). D1: backup-2026-07-02.json (13,6 MB) parsea íntegro con las 6 tablas de negocio (126 tasks · 627 activity_log · resto con datos). Limpieza verificada (contenedor y temporales destruidos; queda un volumen anónimo dangling ~40 MB inocuo en STAGE, decisión deliberada de no purgar volúmenes).
  • Próximo (#2): octubre 2026 — incluir el ensayo de WAL/PITR (no cubierto en el #1) y valorar el restore desde la copia offsite de Google Drive.

4 · Restauración — dónde está cada procedimiento

  • SaaS caído / servidor perdido → [[crearack-tech—guides—disaster-recovery]] (45-60 min, paso a paso, incluye PITR).
  • Workspace caído → [[workspace—guias—disaster-recovery-workspace]] (incluye la guía rápida sin tecnicismos y el mirror de emergencia en STAGE, puerto 8090 — cerrado por defecto en el firewall).
  • Perfil Claude perdido → claude-backup.ps1 -Restore -FromGit (repo claude-backups).
  • Biblioteca/grafo → regenerable con bib_full_reindex (horas, no días; los backups no la incluyen a propósito).

5 · Rotación y caducidades

  • Mirror DR (basic auth nginx en STAGE): htpasswd -b /etc/nginx/.htpasswd admindomo '<nueva>' + nginx -t && systemctl reload nginx. Rotada el 02-07-2026. El script deploy-staging-mirror.ps1 incluye el bloque auth_basic en su plantilla desde s185 (antes un redeploy lo borraba).
  • Tokens MCP → runbook [[runbook—infra—rotate-mcp-token]].
  • Tokens Zoho → re-auth OAuth por cuenta (ojo footgun: cerrar sesión Zoho entre cada ?as=).
  • PATs GitHub con fecha: routine-maintenance-weekly expira ~13-05-2027 · ATLAS_CHECK_PAT sin fecha documentada.
  • ⚠️ Deuda (s185): no existe registro central de caducidades ni aviso previo — añadir columna “caduca” al catálogo + recordatorio en el cron de STAGE.

6 · Altas y bajas de acceso (checklist)

Alta de un miembro (complementa la instalación técnica de [[workspace—onboarding—setup-equipo-nuevo]], que es la fuente única del setup):

  1. GitHub org CreaRackSL (Owner) · 2. VPN NetBird (setup key + grupo) · 3. BIB_MCP_TOKEN (MCP workspace) · 4. METHOD_DOCTOR_TOKEN (rollup de paridad) · 5. Clave SSH Ed25519 en los servidores + IP en el firewall Hetzner (decidir si por defecto o solo bajo demanda) · 6. Cuenta Zoho + grupos de email · 7. CF Access (email en la policy) · 8. Local Agent instalado (si va a tocar producto).

Baja de un miembro (⚠️ hasta s185 NO existía por escrito):

  1. Retirar de GitHub org · 2. Revocar su parte de MCP_TOKENS en CF Pages · 3. Quitar email de CF Access · 4. Retirar clave SSH de authorized_keys + IP del firewall · 5. Desactivar cuenta Zoho / reasignar grupos · 6. Revocar METHOD_DOCTOR_TOKEN · 7. Rotar los secretos compartidos que conociera (mirror DR, service tokens).

Pendientes concretos de septiembre 2026 (Dani y Txell al 100%): verificar sus claves SSH/firewall a PROD (docs contradictorias, s185) · Agent instalado en el equipo de Txell · alta NetBird verificada. (METHOD_DOCTOR_TOKEN ✅ ya provisionado en los 3 perfiles — verificado s187, 02-07-2026: el rollup muestra edu/dani/txell en verde.)

6b · Caché de Cloudflare: lo dinámico se marca, lo estático se hashea (tarea #319, 29-09-2026)

Cloudflare guarda por EXTENSIÓN (.svg .png .pdf .csv .xlsx…) cualquier respuesta sin Cache-Control, y la zona crearack.com está en caché “agresiva”. Una respuesta que dependa de la sesión y acabe en una de esas extensiones podría servirse a otro usuario (pasó con los SVG del enlace público de cartelería el 16-09).

  • Invariante: toda respuesta con sesión, cookie de sesión, cabecera Authorization o de /api/ sale private, no-store salvo que declare su propia política (core/middleware/cache_default.py, CreaRack v1.166.3).
  • Regla de Cloudflare (ruleset fc3bf23f…, regla fd371768…): todo lo que no sea /static/ en crearack.com y www sin caché del borde. /static/ va con huella e immutable.
  • Comprobar: curl -sI "https://crearack.com/<ruta>?nc=$RANDOM" → cf-cache-status DYNAMIC en lo dinámico, HIT en /static/. Detalle, verificación del 29-09 y vuelta atrás: context/INFRA.md de CreaRack-Pro, sección “Caché de Cloudflare”.

7 · Deudas vivas de seguridad/backups (auditoría s185, con dueño)

#DeudaPlan
1Contraseña del mirror DR expuesta en 12 ficheros versionados✅ CERRADA 02-07-2026: rotada + barrida de todos los docs (placeholder → bóveda)
2Bóveda de secretos sin implantarDecidido s185: Bitwarden Teams (task #33, Edu en ello)
3Media PROD sin offsite + snapshots Hetzner sin activar + Dokploy config en copia únicarclone sync /app/media al bucket + activar snapshots (~2 €/mes) + export cifrado de env vars
4Ningún restore ensayado✅ Simulacro #1 ejecutado 02-07-2026 (acta en §3). Rutina trimestral: #2 en octubre (incluir WAL/PITR)
5Billing en cuenta personal de Edu + sin procedimiento de sucesiónAntes de la constitución (septiembre)
6Caducidades de tokens sin registro/avisoColumna en el catálogo + recordatorio cron STAGE (el inventario de credenciales s185 aporta la lista base)
7factu@/legal@ solo TxellForwarding/co-lectura a Edu
8Backup de perfiles Claude manual (depende de acordarse)Automatizar (tarea programada o cron)

Véase también

  • [[crearack-tech—guides—disaster-recovery]]
  • [[workspace—guias—disaster-recovery-workspace]]
  • [[entity—ops—catalogo-servicios-externos]]
  • [[workspace—onboarding—setup-equipo-nuevo]]
  • [[runbook—infra—rotate-mcp-token]]
  • [[workspace—guias—como-trabajamos]]