Saltar al contenido
# 🔐 Pseudonymizer — Seudonimización de Payloads ## 🤔 ¿Qué hago? ¿Cómo lo hago? ¿Y para qué lo hago? **¿Qué hago?** Seudonimizo automáticamente todos los payloads sensibles (messages, system, tool_results, etc.) **antes** de enviarlos a proveedores externos como Anthropic. Reemplazo valores confidenciales por UUIDs y almaceno el mapeo en Qdrant para auditoria y reversibilidad. **¿Cómo lo hago?** Cada vez que Klaus-proxy-global recibe una petición `/v1/messages`: 1. Se procesa el payload según la lógica normal (caché, RAG, etc.) 2. **Justo antes de forwardear a Anthropic**, aplico seudonimización 3. Todos los campos sensibles se reemplazan con `[PSEUDONYM:uuid]` 4. El mapeo original → pseudonym se almacena en Qdrant (`klaude_pseudonyms`) 5. El payload seudonimizado se envía a Anthropic 6. Se registra un evento de log para que aparezca en el dashboard **¿Para qué lo hago?** Proteger datos confidenciales del usuario cuando se trabaja con LLMs externos. Aunque confíes en Anthropic, la seudonimización añade una capa extra de aislamiento: Anthropic nunca ve los datos originales, solo los tokens seudonimizados. Cumple requisitos de: - **GDPR**: Anonimización de datos personales en tránsito - **Compliance**: Auditoría completa de qué datos se enviaron y cuándo - **Control**: Toggle on/off en runtime, sin depender de configuración estática --- ## 🏗️ Arquitectura ```mermaid flowchart LR User["👤 Usuario<br/>Claude Code<br/>Continue.dev"] Proxy["🔀 Klaus-proxy-global<br/>/v1/messages"] Cache["💾 Cache<br/>RAG Injection"] Pseudonym["🔐 Pseudonymizer<br/>messages, system<br/>tool_results"] Anthropic["☁️ Anthropic API<br/>api.anthropic.com"] Qdrant["🗄️ Qdrant<br/>klaude_pseudonyms"] User -->|request| Proxy Proxy -->|1. lookup| Cache Cache -->|2. found? RAG| Proxy Proxy -->|3. apply pseudonym| Pseudonym Pseudonym -->|store mapping| Qdrant Pseudonym -->|forward [PSEUDONYM:uuid]| Anthropic Anthropic -->|response| User style Pseudonym fill:#4c1d95,color:#e0e0e0,stroke:#a78bfa style Qdrant fill:#1e293b,color:#64748b ``` --- ## 📡 Endpoints ### `GET /pseudonymizer/status` Consultar estado del seudonimizador y estadísticas. **Sin autenticación.** **Respuesta:** ```json { "enabled": true, "collection": "klaude_pseudonyms", "mappings_stored": 247, "status": "Green" } ``` | Campo | Tipo | Descripción | | --- | --- | --- | | `enabled` | bool | ¿Seudonimizador activo? | | `collection` | string | Nombre de colección Qdrant | | `mappings_stored` | int | Número de mappings almacenados (UUID → original) | | `status` | string | Estado de colección Qdrant (`Green`, `Yellow`, `Red`, `unavailable`) | --- ### `POST /pseudonymizer/toggle` Activar/desactivar el seudonimizador en runtime. **Sin autenticación (pero considerar añadir x-api-key en futuro).** **Body:** ```json { "enabled": true } ``` **Respuesta:** ```json { "enabled": true, "message": "Pseudonymizer enabled" } ``` | Parámetro | Tipo | Default | Descripción | | --- | --- | --- | --- | | `enabled` | bool | — | `true` para activar, `false` para desactivar. Si omitido, alterna el estado actual | --- ### `DELETE /pseudonymizer/mappings` Limpiar todos los mappings almacenados en Qdrant. Útil después de testing o para reset. **Headers:** `x-api-key: <cualquier valor no vacío>` **Respuesta:** ```json { "flushed": true, "deleted_points": 247 } ``` --- ### `POST /pseudonymizer/config` Configurar dinámicamente qué valores seudonimizar. **Klaus-code-cli llama esto al iniciar.** **Sin autenticación.** **Body:** ```json { "literals": ["path/to/project", "username", "custom-sensitive-value"] } ``` **Respuesta:** ```json { "literals": 3, "paths": 2 } ``` | Parámetro | Tipo | Default | Descripción | | --- | --- | --- | --- | | `literals` | list[str] | `[]` | Lista de valores específicos a seudonimizar. **Reemplaza** la lista anterior (no merge). Vacío = solo patrones regex + env | **Nota:** Esta configuración es **por sesión**, se pierde al redeploy del container. Klaus-code-cli debe llamar esto cada vez que inicia. --- ### `GET /pseudonymizer/config` Obtener literales actualmente configurados (para auditoría). **Sin autenticación.** **Respuesta:** ```json { "literals": ["path/to/project", "username"], "paths": ["/home/user", "/root"] } ``` | Campo | Tipo | Descripción | | --- | --- | --- | | `literals` | list[str] | Valores configurados vía `POST /config` | | `paths` | list[str] | Prefijos de rutas (del entorno) | --- ## 🧩 Módulo: `proxy/pseudonymizer.py` Módulo standalone que gestiona la lógica de seudonimización. ### Funciones públicas | Función | Firma | Descripción | | --- | --- | --- | | `is_enabled()` | `() -> bool` | Consultar estado global | | `set_enabled(enabled: bool)` | `(bool) -> None` | Cambiar estado | | `apply(request_data)` | `(dict) -> (dict, list)` | Seudonimizar payload. Retorna (pseudonymized, events) | | `get_stats()` | `() -> dict` | Estadísticas de mappings activos | | `get_rules()` | `async () -> dict` | Obtener literales + rutas configuradas | | `set_rules(literals)` | `async (list[str]) -> dict` | Actualizar literales dinámicamente (Klaus-code-cli) | | `restore_response(text)` | `async (str) -> str` | Deseudonimizar respuesta de Anthropic | | `flush()` | `() -> dict` | Limpiar todos los mappings | ### Campos seudonimizados **Automáticamente**, se seudonimiza cualquier valor string en: - `messages` — array de objetos con `content` - `system` — string o list de system prompts - `tool_results` — respuestas de herramientas (tool_use context) - `instructions` — si está presente en el payload - **Recursivamente**: funciona en nested structures (lists, dicts) ### Formato de pseudonym ``` [PSEUDONYM:550e8400] ``` Donde `550e8400` son los primeros 8 caracteres de un UUID v4. El UUID completo se usa como clave en Qdrant. --- ## 🗄️ Colección Qdrant: `klaude_pseudonyms` | Campo payload | Tipo | Descripción | | --- | --- | --- | | `pseudonym_id` | string | UUID v4 completo | | `original_value` | string | Valor original (seudonimizado) | | `field_name` | string | Campo en el que estaba: `text`, `system`, etc. | | `length` | int | Longitud del valor original | | `created_at` | ISO8601 | Timestamp de seudonimización | **ID determinista:** `hash(pseudonym_id) % (2**63)` — permite búsquedas eficientes por ID. --- ## 🎛️ Dashboard Integration ### Toggle en navbar Botón `🔐 Seudonimizar` en la barra superior. Hacer clic activa/desactiva el seudonimizador. - ✅ Verde cuando está **ON** (activo) - ⚪ Gris cuando está **OFF** (inactivo) ### Panel de logs Nueva sección **"Pseudonymizer"** con: - **Estado actual**: `✅ Seudonimizador ACTIVO · 247 mappings almacenados` - **Eventos recientes**: lista de últimos campos seudonimizados - Formato: `🔐 system · 3 valores seudonimizados` - Actualiza en tiempo real vía SSE ### Botones de control - **🔐 Seudonimizar**: Abre el modal de control - **🗑️ Limpiar mappings**: Borra todos los mappings (requiere confirmación) - **Cerrar**: Cierra el modal --- ## ⏱️ Performance | Escenario | Tiempo | Notas | | --- | --- | --- | | Seudonimización desactivada | ~0 ms | Solo check de flag (`if not enabled: return`) | | Payload pequeño (1KB) | ~2-5 ms | Parsing + storage en Qdrant | | Payload mediano (50KB) | ~20-50 ms | Más campos a procesar | | Payload grande (500KB) | ~200-500 ms | Considera si activar selectivamente | **Recomendación:** Mantener siempre activado en producción. El overhead es mínimo comparado con latencia de Anthropic (~1-2s). --- ## 🔒 Seguridad - ✅ **Mappings en Qdrant**: Los valores originales se almacenan en BD, no en logs - ✅ **No en stdout/stderr**: Los logs del proxy nunca contienen valores seudonimizados - ✅ **UUID aleatorio**: Imposible invertir `[PSEUDONYM:uuid]` sin acceso a Qdrant - ✅ **Audit trail**: Cada seudonimización queda registrada con timestamp - ⚠️ **Requires Qdrant security**: Si Qdrant se compromete, los mappings están expuestos. Protégelo con firewall --- ## 🔗 Documentos relacionados - [cache.md](cache.md) — Caché semántica (anterior en pipeline) - [sources.md](sources.md) — Ingestión de fuentes externas - [knowledge_base.md](knowledge_base.md) — Knowledge Base de proyecto - [architecture.md](architecture.md) — Arquitectura general del proxy --- ## 💡 Ejemplos de uso ### Activar seudonimizador ```bash curl -X POST http://localhost:8080/pseudonymizer/toggle \ -H "Content-Type: application/json" \ -d '{"enabled": true}' ``` **Response:** ```json {"enabled": true, "message": "Pseudonymizer enabled"} ``` ### Consultar estado ```bash curl http://localhost:8080/pseudonymizer/status ``` **Response:** ```json { "enabled": true, "collection": "klaude_pseudonyms", "mappings_stored": 150, "status": "Green" } ``` ### Limpiar mappings ```bash curl -X DELETE http://localhost:8080/pseudonymizer/mappings \ -H "x-api-key: admin" ``` **Response:** ```json {"flushed": true, "deleted_points": 150} ``` --- ## 🚀 Roadmap futuro - [ ] **Selective pseudonymization**: Solo ciertos campos (e.g., no seudonimizar `model`) - [ ] **Encryption at rest**: Encriptar mappings en Qdrant con KMS - [ ] **TTL per mapping**: Auto-delete después de X días - [ ] **Audit export**: Endpoint para exportar audit trail completo - [ ] **Rate limiting**: Limitar seudonimizaciones por usuario - [ ] **Reversibility endpoint**: Endpoint privado para reversal (admin only)