From 582e425832fc6aacffeeab2c698b65e551a16292 Mon Sep 17 00:00:00 2001 From: ARCHITECT Date: Thu, 25 Dec 2025 09:42:57 +0000 Subject: [PATCH 1/2] fix(security): Correct secrets architecture for autonomous instances MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ARCHITECT is the constructor, DECK/CORP are autonomous instances. Each instance must operate independently at runtime. Architecture: - Infisical (ARCHITECT): Central management, source of truth - Vaultwarden (DECK :8085): Local secrets for autonomous operation - Vaultwarden (CORP :8081): Local secrets for autonomous operation - Sync: Infisical β†’ Vaultwarden propagation Key principle: Instances never depend on ARCHITECT at runtime. πŸ€– Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- 04_SEGURIDAD/secretos.md | 504 +++++++++++++++++++++------------------ 1 file changed, 278 insertions(+), 226 deletions(-) diff --git a/04_SEGURIDAD/secretos.md b/04_SEGURIDAD/secretos.md index 355b789..bf5f943 100644 --- a/04_SEGURIDAD/secretos.md +++ b/04_SEGURIDAD/secretos.md @@ -5,205 +5,266 @@ --- -## Estado Actual: Triple GestiΓ³n +## Arquitectura de Secretos -**PROBLEMA CRÍTICO:** Actualmente existen tres fuentes de secretos sin sincronizaciΓ³n. +### Principio Fundamental + +> **DECK y CORP son instancias autΓ³nomas. Deben operar independientemente de ARCHITECT.** + +ARCHITECT es el constructor/coordinador. DECK y CORP son instancias diseΓ±adas para trabajar solas. + +### Modelo de GestiΓ³n ``` β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ FUENTES DE SECRETOS β”‚ +β”‚ ARCHITECT β”‚ +β”‚ (Constructor) β”‚ β”‚ β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ Infisical β”‚ β”‚ creds_* β”‚ β”‚ .env β”‚ β”‚ -β”‚ β”‚ (central) β”‚ β”‚ (PostgreSQL)β”‚ β”‚ (archivos) β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β”‚ β”‚ β”‚ β”‚ β”‚ -β”‚ β–Ό β–Ό β–Ό β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ ❌ SIN SINCRONIZACIΓ“N - Riesgo de inconsistencia β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ +β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ +β”‚ β”‚ Infisical β”‚ ← GestiΓ³n centralizada β”‚ +β”‚ β”‚ :8082 β”‚ Single source of truth β”‚ +β”‚ β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ +β”‚ β”‚ β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ + β”‚ + sync/push β”‚ (en deploy o periΓ³dico) + β”‚ + β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” + β–Ό β–Ό +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ DECK β”‚ β”‚ CORP β”‚ +β”‚ (Instancia) β”‚ β”‚ (Instancia) β”‚ +β”‚ β”‚ β”‚ β”‚ +β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ +β”‚ β”‚ Vaultwarden β”‚ β”‚ β”‚ β”‚ Vaultwarden β”‚ β”‚ +β”‚ β”‚ :8085 β”‚ β”‚ β”‚ β”‚ :8081 β”‚ β”‚ +β”‚ β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ +β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ +β”‚ β–Ό β”‚ β”‚ β–Ό β”‚ +β”‚ CLARA, ALFRED β”‚ β”‚ MARGARET, JARED β”‚ +β”‚ leen de aquΓ­ β”‚ β”‚ MASON, FELDMAN β”‚ +β”‚ β”‚ β”‚ leen de aquΓ­ β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ +``` + +### Gestores por Servidor + +| Servidor | Gestor | Puerto | Rol | +|----------|--------|--------|-----| +| ARCHITECT | Infisical | 8082 | GestiΓ³n central, source of truth | +| DECK | Vaultwarden | 8085 | OperaciΓ³n autΓ³noma DECK | +| CORP | Vaultwarden | 8081 | OperaciΓ³n autΓ³noma CORP | + +--- + +## Flujo de Secretos + +### AdministraciΓ³n (en ARCHITECT) + +``` +Administrador + β”‚ + β–Ό +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ Infisical β”‚ ← Crear/modificar/rotar secretos aquΓ­ +β”‚ (central) β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ +``` + +### SincronizaciΓ³n (ARCHITECT β†’ Instancias) + +``` +Infisical (ARCHITECT) + β”‚ + β”‚ Script de sync / deploy + β”‚ + β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” + β–Ό β–Ό β–Ό +Vaultwarden Vaultwarden (otras instancias + DECK CORP futuras) +``` + +### OperaciΓ³n (en cada instancia) + +``` +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ DECK β”‚ +β”‚ β”‚ +β”‚ CLARA ──────► Vaultwarden ◄─────── ALFRED +β”‚ :8085 β”‚ +β”‚ β”‚ +β”‚ βœ… No depende de ARCHITECT β”‚ +β”‚ βœ… Opera si ARCHITECT estΓ‘ caΓ­do β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` --- -## Fuente 1: Infisical +## Estado Actual: Problema -**URL:** http://localhost:8082 (ARCHITECT) -**Estado:** Operativo +**Triple gestiΓ³n sin sincronizaciΓ³n:** -### ConfiguraciΓ³n +| Fuente | UbicaciΓ³n | Estado | +|--------|-----------|--------| +| Infisical | ARCHITECT :8082 | Parcialmente usado | +| creds_* | PostgreSQL ARCHITECT | Activo | +| .env | /opt/*/.env en cada servidor | Activo, **permisos 644** | -```bash -# Acceso a Infisical -infisical login -infisical secrets --env=prod -``` - -### Ventajas -- Centralizado -- Versionado -- Auditable -- SDK para mΓΊltiples lenguajes - -### Uso Actual -- Parcial - no todos los servicios lo usan +**Problemas:** +- Secretos duplicados en mΓΊltiples lugares +- Sin sincronizaciΓ³n entre fuentes +- .env legibles por todos (644) +- Vaultwarden de DECK/CORP no integrados --- -## Fuente 2: Tablas creds_* (PostgreSQL) - -**Base de datos:** architect -**Estado:** Activo - -### Tablas - -| Tabla | Contenido | -|-------|-----------| -| creds_ia | APIs de IA (OpenAI, Anthropic, etc.) | -| creds_runpod | API keys de RunPod | -| creds_r2 | Credenciales Cloudflare R2 | -| creds_gitea | Tokens Gitea | -| creds_mail | Credenciales SMTP | -| creds_apis | APIs externas varias | - -### Schema TΓ­pico - -```sql -CREATE TABLE creds_ia ( - id SERIAL PRIMARY KEY, - servicio VARCHAR(50) NOT NULL, - api_key TEXT NOT NULL, - descripcion TEXT, - activo BOOLEAN DEFAULT true, - created_at TIMESTAMP DEFAULT NOW(), - updated_at TIMESTAMP DEFAULT NOW() -); -``` - -### Acceso - -```sql --- Consultar credenciales -sudo -u postgres psql -d architect -c "SELECT servicio, descripcion FROM creds_ia;" -``` - ---- - -## Fuente 3: Archivos .env - -**Ubicaciones:** -- /opt/clara/.env -- /opt/alfred/.env -- /opt/margaret/.env -- /opt/mason/.env -- /opt/feldman/.env - -### ALERTA CRÍTICA - -``` -Permisos actuales: 644 (legibles por todos) -Permisos correctos: 600 (solo propietario) -``` - -### Contenido TΓ­pico - -```bash -# Ejemplo .env -DB_HOST=localhost -DB_PORT=5432 -DB_NAME=corp -DB_USER=margaret -DB_PASSWORD=secreto_aqui # ⚠️ Expuesto si 644 - -R2_ACCESS_KEY=access_key_aqui -R2_SECRET_KEY=secret_key_aqui # ⚠️ Expuesto si 644 -``` - ---- - -## DecisiΓ³n D-001: MigraciΓ³n a Infisical +## DecisiΓ³n D-001: Arquitectura de Secretos ### Objetivo -Infisical como **ΓΊnica fuente de verdad** para todos los secretos. -### Plan de MigraciΓ³n +1. **Infisical** (ARCHITECT): Única fuente de verdad para administraciΓ³n +2. **Vaultwarden** (DECK/CORP): Gestores locales para operaciΓ³n autΓ³noma +3. **Sync**: Mecanismo de propagaciΓ³n Infisical β†’ Vaultwarden + +### DivisiΓ³n de Responsabilidades + +| Tipo de Secreto | GestiΓ³n en | OperaciΓ³n en | +|-----------------|------------|--------------| +| API keys externas (OpenAI, etc.) | Infisical | Vaultwarden local | +| R2 credentials | Infisical | Vaultwarden local | +| Gitea tokens | Infisical | Vaultwarden local | +| DB password DECK | Infisical | Vaultwarden DECK | +| DB password CORP | Infisical | Vaultwarden CORP | +| Tokens internos DECK | Infisical | Vaultwarden DECK | +| Tokens internos CORP | Infisical | Vaultwarden CORP | + +### Flujo de Trabajo ``` -Fase 1: Inventario -β”œβ”€β”€ Catalogar todos los secretos en creds_* -β”œβ”€β”€ Catalogar todos los secretos en .env -└── Identificar duplicados/inconsistencias - -Fase 2: CentralizaciΓ³n -β”œβ”€β”€ Migrar todos los secretos a Infisical -β”œβ”€β”€ Organizar por proyecto/ambiente -└── Establecer polΓ­ticas de acceso - -Fase 3: ActualizaciΓ³n de Servicios -β”œβ”€β”€ CLARA: Usar Infisical SDK -β”œβ”€β”€ MARGARET: Usar Infisical SDK -β”œβ”€β”€ MASON: Usar Infisical SDK -β”œβ”€β”€ FELDMAN: Usar Infisical SDK -└── ALFRED/JARED: Usar Infisical SDK - -Fase 4: DeprecaciΓ³n -β”œβ”€β”€ Eliminar archivos .env -β”œβ”€β”€ Marcar creds_* como "solo referencia" -└── Documentar proceso de rotaciΓ³n -``` - -### ImplementaciΓ³n con SDK - -```python -from infisical_client import InfisicalClient - -client = InfisicalClient( - host="http://localhost:8082", - token=INFISICAL_TOKEN -) - -# Obtener secreto -db_password = client.get_secret( - secret_name="DB_PASSWORD", - project_id="tzzr", - environment="production" -) +1. Admin modifica secreto en Infisical (ARCHITECT) + β”‚ + β–Ό +2. Script de sync detecta cambio + β”‚ + β–Ό +3. Propaga a Vaultwarden de DECK y/o CORP + β”‚ + β–Ό +4. Servicios locales usan Vaultwarden local + β”‚ + β–Ό +5. ARCHITECT puede caer β†’ DECK/CORP siguen operando ``` --- -## RotaciΓ³n de Secretos +## Plan de MigraciΓ³n -### PolΓ­tica Propuesta - -| Tipo | Frecuencia | Responsable | -|------|------------|-------------| -| API Keys externas | 90 dΓ­as | Orchestrator | -| ContraseΓ±as DB | 180 dΓ­as | DBA | -| SSH Keys | 365 dΓ­as | SysAdmin | -| Tokens Gitea | 180 dΓ­as | DevOps | - -### Proceso de RotaciΓ³n +### Fase 1: Inventario ``` -1. Generar nuevo secreto -2. Actualizar en Infisical -3. Desplegar servicios afectados -4. Verificar funcionamiento -5. Revocar secreto anterior -6. Documentar en changelog +β”œβ”€β”€ Catalogar todos los secretos en creds_* +β”œβ”€β”€ Catalogar todos los secretos en .env +β”œβ”€β”€ Identificar duplicados/inconsistencias +└── Mapear quΓ© secretos necesita cada instancia +``` + +### Fase 2: CentralizaciΓ³n en Infisical + +``` +β”œβ”€β”€ Migrar todos los secretos a Infisical +β”œβ”€β”€ Organizar por instancia (DECK, CORP) +β”œβ”€β”€ Establecer polΓ­ticas de acceso +└── Documentar cada secreto +``` + +### Fase 3: Configurar Vaultwarden en Instancias + +``` +β”œβ”€β”€ DECK: Configurar Vaultwarden :8085 +β”‚ β”œβ”€β”€ Crear organizaciΓ³n "DECK" +β”‚ β”œβ”€β”€ Importar secretos de DECK desde Infisical +β”‚ └── Configurar acceso para servicios +β”‚ +└── CORP: Configurar Vaultwarden :8081 + β”œβ”€β”€ Crear organizaciΓ³n "CORP" + β”œβ”€β”€ Importar secretos de CORP desde Infisical + └── Configurar acceso para servicios +``` + +### Fase 4: Implementar Sync + +``` +β”œβ”€β”€ Crear script de sincronizaciΓ³n +β”‚ └── infisical export β†’ vaultwarden import +β”œβ”€β”€ Configurar trigger (manual, cron, o webhook) +└── Probar sync en ambas direcciones +``` + +### Fase 5: Actualizar Servicios + +``` +β”œβ”€β”€ CLARA: Leer de Vaultwarden DECK +β”œβ”€β”€ ALFRED: Leer de Vaultwarden DECK +β”œβ”€β”€ MARGARET: Leer de Vaultwarden CORP +β”œβ”€β”€ JARED: Leer de Vaultwarden CORP +β”œβ”€β”€ MASON: Leer de Vaultwarden CORP +└── FELDMAN: Leer de Vaultwarden CORP +``` + +### Fase 6: DeprecaciΓ³n + +``` +β”œβ”€β”€ Eliminar archivos .env +β”œβ”€β”€ Marcar creds_* como "solo referencia histΓ³rica" +└── Documentar proceso completo +``` + +--- + +## ImplementaciΓ³n + +### Lectura desde Vaultwarden (Python) + +```python +import requests + +VAULTWARDEN_URL = "http://localhost:8085" # DECK +# VAULTWARDEN_URL = "http://localhost:8081" # CORP + +def get_secret(name: str) -> str: + """Obtiene secreto de Vaultwarden local.""" + # Implementar segΓΊn API de Vaultwarden/Bitwarden + pass +``` + +### Script de Sync (Infisical β†’ Vaultwarden) + +```bash +#!/bin/bash +# /opt/scripts/sync_secrets.sh + +# Exportar desde Infisical +infisical export --env=deck --format=json > /tmp/deck_secrets.json +infisical export --env=corp --format=json > /tmp/corp_secrets.json + +# Importar a Vaultwarden DECK +ssh deck 'bw import --format json /tmp/deck_secrets.json' + +# Importar a Vaultwarden CORP +ssh corp 'bw import --format json /tmp/corp_secrets.json' + +# Cleanup +rm /tmp/*_secrets.json ``` --- ## MitigaciΓ³n Inmediata -### Paso 1: Permisos .env +### Paso 1: Permisos .env (URGENTE) ```bash -# Ejecutar en todos los servidores - # DECK ssh -i ~/.ssh/tzzr root@72.62.1.113 'chmod 600 /opt/clara/.env /opt/alfred/.env' @@ -211,82 +272,73 @@ ssh -i ~/.ssh/tzzr root@72.62.1.113 'chmod 600 /opt/clara/.env /opt/alfred/.env' ssh -i ~/.ssh/tzzr root@92.112.181.188 'chmod 600 /opt/margaret/.env /opt/mason/.env /opt/feldman/.env' ``` -### Paso 2: AuditorΓ­a +### Paso 2: Verificar Vaultwarden ```bash -# Verificar permisos -ls -la /opt/*/.env +# DECK +curl -s http://72.62.1.113:8085/api/health -# Buscar secretos expuestos -grep -r "password\|secret\|key" /opt/*/ 2>/dev/null +# CORP +curl -s http://92.112.181.188:8081/api/health ``` --- -## Inventario de Secretos +## RotaciΓ³n de Secretos -### APIs de IA +### PolΓ­tica -| Servicio | UbicaciΓ³n Actual | Notas | -|----------|------------------|-------| -| OpenAI | creds_ia | GPT-4 | -| Anthropic | creds_ia | Claude | -| Replicate | creds_ia | Modelos varios | -| RunPod | creds_runpod | GRACE, PENNY, FACTORY | +| Tipo | Frecuencia | Responsable | +|------|------------|-------------| +| API Keys externas | 90 dΓ­as | Admin vΓ­a Infisical | +| ContraseΓ±as DB | 180 dΓ­as | Admin vΓ­a Infisical | +| SSH Keys | 365 dΓ­as | Admin vΓ­a Infisical | +| Tokens Gitea | 180 dΓ­as | Admin vΓ­a Infisical | -### Infraestructura +### Proceso -| Servicio | UbicaciΓ³n Actual | Notas | -|----------|------------------|-------| -| PostgreSQL | .env + creds_* | MΓΊltiples usuarios | -| R2/Cloudflare | .env + creds_r2 | Access + Secret key | -| Gitea | .env + creds_gitea | Read + Write tokens | -| SMTP | creds_mail | Mailcow | - -### Servicios Externos - -| Servicio | UbicaciΓ³n Actual | Notas | -|----------|------------------|-------| -| Stripe | creds_apis | (si aplica) | -| Twilio | creds_apis | (si aplica) | -| AWS | creds_apis | (si aplica) | - ---- - -## VerificaciΓ³n de Seguridad - -### Checklist Diario - -- [ ] Permisos .env son 600 -- [ ] No hay secretos en logs -- [ ] No hay secretos en commits git -- [ ] Infisical accesible - -### Comandos de VerificaciΓ³n - -```bash -# Verificar permisos -find /opt -name ".env" -exec ls -la {} \; - -# Buscar secretos en git history -git log -p | grep -i "password\|secret\|key\|token" - -# Verificar Infisical -curl -s http://localhost:8082/api/v1/health +``` +1. Rotar en Infisical (ARCHITECT) +2. Ejecutar sync a Vaultwarden (DECK/CORP) +3. Verificar servicios operando +4. Documentar rotaciΓ³n ``` --- -## Buenas PrΓ‘cticas +## VerificaciΓ³n -### DO (Hacer) -- Usar Infisical para todos los secretos nuevos -- Rotar secretos segΓΊn polΓ­tica -- Auditar accesos regularmente -- Cifrar secretos en reposo +### Checklist -### DON'T (No Hacer) -- Hardcodear secretos en cΓ³digo -- Commitear .env a repositorios -- Compartir secretos por chat/email -- Usar el mismo secreto en mΓΊltiples servicios +- [ ] Infisical operativo en ARCHITECT +- [ ] Vaultwarden operativo en DECK (:8085) +- [ ] Vaultwarden operativo en CORP (:8081) +- [ ] Sync configurado y probado +- [ ] Servicios leen de Vaultwarden local +- [ ] .env eliminados o con permisos 600 +- [ ] DECK opera si ARCHITECT cae +- [ ] CORP opera si ARCHITECT cae + +### Test de AutonomΓ­a + +```bash +# 1. Detener ARCHITECT (simulado) +# 2. Verificar DECK sigue operando +curl http://72.62.1.113:5051/health # CLARA + +# 3. Verificar CORP sigue operando +curl http://92.112.181.188:5051/health # MARGARET +``` + +--- + +## Resumen + +| Componente | Rol | +|------------|-----| +| **Infisical (ARCHITECT)** | GestiΓ³n centralizada, source of truth | +| **Vaultwarden (DECK)** | OperaciΓ³n autΓ³noma instancia personal | +| **Vaultwarden (CORP)** | OperaciΓ³n autΓ³noma instancia empresarial | +| **Sync** | PropagaciΓ³n de cambios | + +**Principio clave:** Las instancias (DECK, CORP) nunca dependen de ARCHITECT en runtime. From 0ee01d07a3f3e1e757d65154daacecbfbe2bab68 Mon Sep 17 00:00:00 2001 From: ARCHITECT Date: Thu, 25 Dec 2025 10:40:19 +0000 Subject: [PATCH 2/2] fix(arch): Enforce instance autonomy principle across docs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Updates to ensure DECK/CORP are documented as autonomous instances: - overview.md: Clarify ARCHITECT is for build/deploy only, not runtime - filosofia.md: Mark shared services (GRACE, etc.) as optional - backup-recovery.md: Each instance does its own local backup to its own R2 bucket Key principle: Instances never depend on ARCHITECT at runtime. πŸ€– Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- 00_VISION/filosofia.md | 17 ++- 01_ARQUITECTURA/overview.md | 19 ++- 05_OPERACIONES/backup-recovery.md | 205 +++++++++++++++++++----------- 3 files changed, 165 insertions(+), 76 deletions(-) diff --git a/00_VISION/filosofia.md b/00_VISION/filosofia.md index bfc90c7..7b82648 100644 --- a/00_VISION/filosofia.md +++ b/00_VISION/filosofia.md @@ -101,5 +101,18 @@ VALORES β†’ OBJETIVOS β†’ IMÁGENES IA β†’ CURACIΓ“N HUMANA β†’ LO QUE SOBREVIVE Cada instancia: - Tiene su propio bucket de almacenamiento - Puede renombrar sus agentes -- Opera de forma descentralizada -- Se conecta a servicios compartidos (GRACE, THE FACTORY, CIRCLE) +- **Opera de forma autΓ³noma** (no depende de ARCHITECT en runtime) +- Tiene su propio gestor de secretos (Vaultwarden) +- Hace sus propios backups a R2 + +### Servicios Compartidos (Opcionales) + +Las instancias **pueden** conectarse a servicios GPU compartidos: + +| Servicio | FunciΓ³n | Requerido | +|----------|---------|-----------| +| GRACE | ExtracciΓ³n IA | Opcional | +| THE FACTORY | GeneraciΓ³n | Opcional | +| CIRCLE | ColaboraciΓ³n | Opcional | + +> **Nota:** Si los servicios compartidos no estΓ‘n disponibles, la instancia sigue operando. Solo las funciones de IA estarΓ‘n limitadas. diff --git a/01_ARQUITECTURA/overview.md b/01_ARQUITECTURA/overview.md index e918db3..f716db9 100644 --- a/01_ARQUITECTURA/overview.md +++ b/01_ARQUITECTURA/overview.md @@ -5,24 +5,37 @@ --- +## Principio Fundamental + +> **ARCHITECT es el constructor. DECK y CORP son instancias autΓ³nomas.** + +- **ARCHITECT**: Construye, despliega, coordina. NO es dependencia runtime. +- **DECK/CORP**: Operan independientemente. Funcionan si ARCHITECT estΓ‘ caΓ­do. + +--- + ## Diagrama General ``` β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ CAPA DE COORDINACIΓ“N β”‚ +β”‚ CAPA DE CONSTRUCCIΓ“N (solo deploy/dev) β”‚ β”‚ β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ β”‚ ARCHITECT (69.62.126.110) β”‚ β”‚ β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ β”‚ β”‚ β”‚PostgreSQLβ”‚ β”‚ Gitea β”‚ β”‚Orchestratorβ”‚ β”‚ Infisical β”‚ β”‚ β”‚ -β”‚ β”‚ β”‚ central β”‚ β”‚ 25 repos β”‚ β”‚ v5 β”‚ β”‚ Secrets β”‚ β”‚ β”‚ +β”‚ β”‚ β”‚ contexto β”‚ β”‚ 25 repos β”‚ β”‚ v5 β”‚ β”‚ (master) β”‚ β”‚ β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ +β”‚ β”‚ +β”‚ Rol: ConstrucciΓ³n, deployment, gestiΓ³n central de secretos β”‚ +β”‚ NO es dependencia runtime de las instancias β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β”‚ + deploy β”‚ β”‚ β”‚ deploy β–Ό β–Ό β–Ό β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ CAPA DE SERVIDORES β”‚ +β”‚ CAPA DE INSTANCIAS (autΓ³nomas) β”‚ β”‚ β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ β”‚ DECK β”‚ β”‚ CORP β”‚ β”‚ HST β”‚ β”‚ diff --git a/05_OPERACIONES/backup-recovery.md b/05_OPERACIONES/backup-recovery.md index d21bddc..57f96e8 100644 --- a/05_OPERACIONES/backup-recovery.md +++ b/05_OPERACIONES/backup-recovery.md @@ -5,6 +5,15 @@ --- +## Principio Fundamental + +> **Cada instancia es responsable de su propio backup.** + +DECK y CORP son instancias autΓ³nomas. No dependen de ARCHITECT para hacer backups. +Cada servidor ejecuta su script de backup localmente y sube directamente a R2. + +--- + ## Estado Actual ### Backups Existentes @@ -20,94 +29,144 @@ --- -## Plan de Backup Propuesto +## Arquitectura de Backups -### PostgreSQL - Backup Diario - -```bash -#!/bin/bash -# /opt/scripts/backup_postgres.sh - -set -e - -DATE=$(date +%F) -BACKUP_DIR="/tmp/pg_backup" - -# Cargar credenciales R2 -source /home/orchestrator/orchestrator/.env -export AWS_ACCESS_KEY_ID="$R2_ACCESS_KEY" -export AWS_SECRET_ACCESS_KEY="$R2_SECRET_KEY" - -R2_ENDPOINT="https://7dedae6030f5554d99d37e98a5232996.r2.cloudflarestorage.com" - -mkdir -p $BACKUP_DIR - -# Backup ARCHITECT -echo "Backing up ARCHITECT..." -sudo -u postgres pg_dump architect | gzip > $BACKUP_DIR/architect_$DATE.sql.gz -aws s3 cp $BACKUP_DIR/architect_$DATE.sql.gz s3://architect/backups/postgres/ \ - --endpoint-url $R2_ENDPOINT - -# Cleanup local -rm -rf $BACKUP_DIR - -echo "Backup completado: $DATE" ``` - -### Cron Configuration - -```bash -# /etc/cron.d/tzzr-backup -# Backup diario a las 3:00 AM -0 3 * * * orchestrator /opt/scripts/backup_postgres.sh >> /var/log/tzzr-backup.log 2>&1 +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ ARCHITECT β”‚ β”‚ DECK β”‚ β”‚ CORP β”‚ +β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ +β”‚ backup.sh ───┼────►│ backup.sh ───┼────►│ backup.sh ───┼────► R2 +β”‚ (local) β”‚ β”‚ (local) β”‚ β”‚ (local) β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ + β”‚ β”‚ + β–Ό β–Ό + Sin dependencia Sin dependencia + de ARCHITECT de ARCHITECT ``` --- -## Backup por Servidor +## Backup por Servidor (LOCAL) ### ARCHITECT (69.62.126.110) +**UbicaciΓ³n script:** `/opt/scripts/backup_postgres.sh` + ```bash -# Base de datos: architect -sudo -u postgres pg_dump architect | gzip > architect_$(date +%F).sql.gz +#!/bin/bash +# Ejecutar EN ARCHITECT - backup local + +set -e +DATE=$(date +%F) + +# Credenciales R2 (desde Vaultwarden local o .env) +source /opt/architect/.env +export AWS_ACCESS_KEY_ID="$R2_ACCESS_KEY" +export AWS_SECRET_ACCESS_KEY="$R2_SECRET_KEY" +R2_ENDPOINT="https://7dedae6030f5554d99d37e98a5232996.r2.cloudflarestorage.com" + +# Backup local +sudo -u postgres pg_dump architect | gzip > /tmp/architect_$DATE.sql.gz # Subir a R2 -aws s3 cp architect_$(date +%F).sql.gz s3://architect/backups/postgres/ \ +aws s3 cp /tmp/architect_$DATE.sql.gz s3://architect/backups/postgres/ \ --endpoint-url $R2_ENDPOINT + +rm /tmp/architect_$DATE.sql.gz +echo "ARCHITECT backup completado: $DATE" ``` ### DECK (72.62.1.113) -```bash -# Base de datos: tzzr -ssh deck 'sudo -u postgres pg_dump tzzr | gzip' > deck_tzzr_$(date +%F).sql.gz +**UbicaciΓ³n script:** `/opt/scripts/backup_postgres.sh` -# Subir a R2 -aws s3 cp deck_tzzr_$(date +%F).sql.gz s3://architect/backups/deck/ \ +```bash +#!/bin/bash +# Ejecutar EN DECK - backup local (NO depende de ARCHITECT) + +set -e +DATE=$(date +%F) + +# Credenciales R2 (desde Vaultwarden DECK) +source /opt/deck/.env +export AWS_ACCESS_KEY_ID="$R2_ACCESS_KEY" +export AWS_SECRET_ACCESS_KEY="$R2_SECRET_KEY" +R2_ENDPOINT="https://7dedae6030f5554d99d37e98a5232996.r2.cloudflarestorage.com" + +# Backup local +sudo -u postgres pg_dump tzzr | gzip > /tmp/deck_tzzr_$DATE.sql.gz + +# Subir a R2 (bucket propio de DECK) +aws s3 cp /tmp/deck_tzzr_$DATE.sql.gz s3://deck/backups/postgres/ \ --endpoint-url $R2_ENDPOINT + +rm /tmp/deck_tzzr_$DATE.sql.gz +echo "DECK backup completado: $DATE" ``` ### CORP (92.112.181.188) -```bash -# Base de datos: corp -ssh corp 'sudo -u postgres pg_dump corp | gzip' > corp_$(date +%F).sql.gz +**UbicaciΓ³n script:** `/opt/scripts/backup_postgres.sh` -# Subir a R2 -aws s3 cp corp_$(date +%F).sql.gz s3://architect/backups/corp/ \ +```bash +#!/bin/bash +# Ejecutar EN CORP - backup local (NO depende de ARCHITECT) + +set -e +DATE=$(date +%F) + +# Credenciales R2 (desde Vaultwarden CORP) +source /opt/corp/.env +export AWS_ACCESS_KEY_ID="$R2_ACCESS_KEY" +export AWS_SECRET_ACCESS_KEY="$R2_SECRET_KEY" +R2_ENDPOINT="https://7dedae6030f5554d99d37e98a5232996.r2.cloudflarestorage.com" + +# Backup local +sudo -u postgres pg_dump corp | gzip > /tmp/corp_$DATE.sql.gz + +# Subir a R2 (bucket propio de CORP) +aws s3 cp /tmp/corp_$DATE.sql.gz s3://corp/backups/postgres/ \ --endpoint-url $R2_ENDPOINT + +rm /tmp/corp_$DATE.sql.gz +echo "CORP backup completado: $DATE" ``` ### HST (72.62.2.84) -```bash -# Base de datos: hst_images -ssh hst 'sudo -u postgres pg_dump hst_images | gzip' > hst_$(date +%F).sql.gz +**UbicaciΓ³n script:** `/opt/scripts/backup_postgres.sh` -# Subir a R2 -aws s3 cp hst_$(date +%F).sql.gz s3://architect/backups/hst/ \ +```bash +#!/bin/bash +# Ejecutar EN HST - backup local + +set -e +DATE=$(date +%F) + +source /opt/hst/.env +export AWS_ACCESS_KEY_ID="$R2_ACCESS_KEY" +export AWS_SECRET_ACCESS_KEY="$R2_SECRET_KEY" +R2_ENDPOINT="https://7dedae6030f5554d99d37e98a5232996.r2.cloudflarestorage.com" + +sudo -u postgres pg_dump hst_images | gzip > /tmp/hst_$DATE.sql.gz + +aws s3 cp /tmp/hst_$DATE.sql.gz s3://hst/backups/postgres/ \ --endpoint-url $R2_ENDPOINT + +rm /tmp/hst_$DATE.sql.gz +echo "HST backup completado: $DATE" +``` + +--- + +## Cron en Cada Servidor + +Cada instancia configura su propio cron: + +```bash +# /etc/cron.d/tzzr-backup (en cada servidor) +# Backup diario a las 3:00 AM +0 3 * * * root /opt/scripts/backup_postgres.sh >> /var/log/backup.log 2>&1 ``` --- @@ -157,26 +216,30 @@ docker exec gitea rm /tmp/gitea-dump-$DATE.zip ## Estructura de Backups en R2 +Cada instancia usa su propio bucket: + ``` s3://architect/backups/ β”œβ”€β”€ postgres/ -β”‚ β”œβ”€β”€ architect_2024-12-24.sql.gz -β”‚ β”œβ”€β”€ architect_2024-12-23.sql.gz -β”‚ └── ... -β”œβ”€β”€ deck/ -β”‚ β”œβ”€β”€ deck_tzzr_2024-12-24.sql.gz -β”‚ └── ... -β”œβ”€β”€ corp/ -β”‚ β”œβ”€β”€ corp_2024-12-24.sql.gz -β”‚ └── ... -β”œβ”€β”€ hst/ -β”‚ β”œβ”€β”€ hst_2024-12-24.sql.gz -β”‚ └── ... +β”‚ └── architect_2024-12-24.sql.gz └── gitea/ - β”œβ”€β”€ gitea-dump-2024-12-24_0300.zip - └── ... + └── gitea-dump-2024-12-24_0300.zip + +s3://deck/backups/ +└── postgres/ + └── deck_tzzr_2024-12-24.sql.gz + +s3://corp/backups/ +└── postgres/ + └── corp_2024-12-24.sql.gz + +s3://hst/backups/ +└── postgres/ + └── hst_2024-12-24.sql.gz ``` +> **Nota:** Cada instancia es dueΓ±a de sus backups. No hay dependencia cruzada. + --- ## RetenciΓ³n de Backups