Manual de Seguridad y Backups — Esferic Labs / CreaRack (fuente única)
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.mdapunta aquí (+core/licenses.pypara 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):
| Ámbito | Dó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 offline | emergency/SECRETS_VAULT.md rellenado y guardado FUERA de git (la copia del repo es solo plantilla) |
| Perfiles Claude | Env 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.mdpasa a ser un índice.
Reglas:
- 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).
- Env var nueva en Dokploy no llega al contenedor sin declararla en el compose (
- VAR=${VAR:-}). CREDENTIAL_ENCRYPTION_KEYdifiere a propósito entre STAGE y PROD — no “corregir”.- 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ónde | Frecuencia | Restore probado |
|---|---|---|---|
| PostgreSQL PROD (pg_dump) | Hetzner Object Storage crearack-backups/postgres/ + local 14d | Diario 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 offsite | Google Drive CreaRackSL/backups/workspace/ (30 copias) | Domingos 03:00 (rclone) | ❌ |
| Código + docs | GitHub + clones en cada PC | Continuo (git) | ✅ implícito |
| Perfiles Claude (memorias) | Repo claude-backups | Manual (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-alpinedesechable en STAGE → 0 errores de datos (solo 188 GRANTs benignos al roldani_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(repoclaude-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 scriptdeploy-staging-mirror.ps1incluye el bloqueauth_basicen 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-weeklyexpira ~13-05-2027 ·ATLAS_CHECK_PATsin 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):
- 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):
- Retirar de GitHub org · 2. Revocar su parte de
MCP_TOKENSen CF Pages · 3. Quitar email de CF Access · 4. Retirar clave SSH deauthorized_keys+ IP del firewall · 5. Desactivar cuenta Zoho / reasignar grupos · 6. RevocarMETHOD_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
Authorizationo de/api/saleprivate, no-storesalvo que declare su propia política (core/middleware/cache_default.py, CreaRack v1.166.3). - Regla de Cloudflare (ruleset
fc3bf23f…, reglafd371768…): todo lo que no sea/static/en crearack.com y www sin caché del borde./static/va con huella eimmutable. - Comprobar:
curl -sI "https://crearack.com/<ruta>?nc=$RANDOM"→cf-cache-statusDYNAMIC en lo dinámico, HIT en/static/. Detalle, verificación del 29-09 y vuelta atrás:context/INFRA.mdde CreaRack-Pro, sección “Caché de Cloudflare”.
7 · Deudas vivas de seguridad/backups (auditoría s185, con dueño)
| # | Deuda | Plan |
|---|---|---|
| 1 | ✅ CERRADA 02-07-2026: rotada + barrida de todos los docs (placeholder → bóveda) | |
| 2 | Bóveda de secretos sin implantar | Decidido s185: Bitwarden Teams (task #33, Edu en ello) |
| 3 | Media PROD sin offsite + snapshots Hetzner sin activar + Dokploy config en copia única | rclone sync /app/media al bucket + activar snapshots (~2 €/mes) + export cifrado de env vars |
| 4 | ✅ Simulacro #1 ejecutado 02-07-2026 (acta en §3). Rutina trimestral: #2 en octubre (incluir WAL/PITR) | |
| 5 | Billing en cuenta personal de Edu + sin procedimiento de sucesión | Antes de la constitución (septiembre) |
| 6 | Caducidades de tokens sin registro/aviso | Columna en el catálogo + recordatorio cron STAGE (el inventario de credenciales s185 aporta la lista base) |
| 7 | factu@/legal@ solo Txell | Forwarding/co-lectura a Edu |
| 8 | Backup 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]]