Manual técnico de operaciones — IA Gobernanza

Audiencia: especialistas en seguridad, DevSecOps, oficiales de cumplimiento con perfil técnico. Describe procedimientos operativos, contratos de API y semántica de cada control tal como está implementado. Donde un control es una hoja de ruta y no una capacidad actual, se indica explícitamente.

Versión 1.0 · Base URL: https://<su-dominio>/api · Todas las rutas del plano de control exigen sesión de operador (cookie gov_session, httpOnly, SameSite=Lax, 8 h). Rutas de datos usan API key (Authorization: Bearer gov_live_* o X-API-Key).


1. Arquitectura de referencia

[Apps del cliente] ──Bearer gov_live_*──▶ /api/v1/gateway/chat/completions ──▶ Conector (Ollama/vLLM local · Fireworks · DeepSeek · …)
        │                                  │ pre-auditoría (<50 ms) · ZK anonimización · post-auditoría ISO 42001
        │                                  └─▶ connector_transactions (hash/métricas) · incidents · webhooks HMAC v2
[SDK aiguard / Muro Perimetral] ──X-API-Key──▶ /api/v1/public/evaluate-stream (fail-closed PII)
[Operadores] ──cookie + MFA TOTP──▶ /api/{models,policies,killswitch,connectors,threats,keys,webhooks,audit,...}
Persistencia: MongoDB (tenant-scoped por company_id) · Vault efímero ZK: Redis (REDIS_URL) o MongoDB TTL

Principios implementados:

  • Multi-tenancy por actor: toda consulta filtra por company_id derivado de la sesión o de la API key; accesos por id a recursos ajenos devuelven 404.
  • Zero-Knowledge fail-closed: /v1/public/evaluate-stream rechaza PII en claro (422 PII_PLAINTEXT_REJECTED) y solo persiste hashes. El Gateway anonimiza PII hacia destinos externos con mapa cifrado efímero (TTL ≤ 300 s).
  • Kill Switch por consenso (anti-FP): Capa 1 regla dura · Capa 2 confianza (risk ≥ 55) · Capa 3 persistencia (≥ 3 eventos en 5 s). Las amenazas de usuario no disparan el KS por sí solas.
  • Auditoría tamper-evident: audit_events encadenada por SHA-256 (prev_hash → hash), verificable en GET /api/audit/verify-chain.

2. Identidad, MFA y RBAC

RutaMétodoRolNotas
/auth/loginPOST—{email,password}. bcrypt(12). Rate limit 5/min por IP+email. Si el usuario tiene MFA → {mfa_required:true, mfa_token} (JWT purpose=mfa, 5 min).
/auth/mfa/verifyPOST—{mfa_token, code} o {mfa_token, recovery_code} → cookie de sesión. 5 intentos/min por usuario.
/auth/mfa/setup · /enable · /disable · /recovery-codesPOSTsesiónTOTP RFC 6238 (otplib, ventana ±30 s). Secreto cifrado AES-256-GCM con MFA_ENC_KEY; recovery codes solo como SHA-256.
/auth/usersGET/POST/PUT/DELETEadminCrear/rotar rol/deshabilitar/mfa_reset:true. Último admin activo no puede degradarse.
/auth/change-passwordPOSTsesiónInvalida sesiones previas (session_version).

Enforcement MFA (`MFA_REQUIRED_ROLES=admin,operator`): un usuario de rol obligado sin MFA solo puede ejecutar GET; toda mutación devuelve 403 {code:'MFA_ENROLLMENT_REQUIRED'}. En producción el propio usuario no puede desactivar su MFA; otro admin (con MFA) lo reinicia vía PUT /auth/users/:id {mfa_reset:true}.

RBAC (`requiredRoleFor`): GET → viewer · killswitch/simulate/incidents/threats/webhooks test/connectors test → operator · resto → admin. Desactivar un Kill Switch exige admin + reason obligatorio + evento de auditoría + webhook firmado.

Rotación JWT: firma con JWT_SECRET; verificación acepta JWT_SECRET_PREVIOUS durante la ventana de rotación. Proveedor de secretos: SECRETS_PROVIDER=env|aws (AWS Secrets Manager soportado en código; no configurado en esta instalación).


3. Modelos gobernados y Kill Switch

  • POST /api/models {name, provider, type, risk_sector} crea ai_models_registered + killswitch_configs {mode:'alert', status:'inactive', trigger_threshold:80}.
  • PUT /api/killswitch/:modelId {status:'active'|'inactive', mode:'alert'|'block', reason}. mode:'block' marca el modelo blocked y toda evaluación/gateway devuelve bloqueo determinista. Desactivación: admin + reason.
  • Disparo automático: evaluateEvent / evaluateV1 / Gateway registran risk_events (TTL) y aplican decideAction(layers, circuitMode):
  • ACTION_KILLSWITCH_TRIGGER (L1∧L3, L2∧L3 o L1 aislada en motor de políticas), ACTION_REDACT_AND_SUBSTITUTE (L2), ACTION_LOG_AND_MONITOR, ACTION_ALLOW, HUMAN_ALERT_REQUIRED (circuit breaker: 100 % de la flota fallando, ≥ 2 modelos, congelación 30 s).
  • Cada decisión lleva decision_hash (SHA-256 sobre inputs exactos) para anti-repudio.
  • Webhooks: killswitch.activated, killswitch.deactivated.

Procedimiento de reactivación (runbook):

  1. Consultar GET /api/incidents y GET /api/threats para la causa (last_trigger_cause).
  2. Verificar que la causa está contenida (p. ej. API key del atacante revocada, conector corregido).
  3. PUT /api/killswitch/:id {status:'inactive', mode:'alert', reason:'<ticket + justificación>'} como admin con MFA.
  4. Confirmar recepción del webhook en el SIEM y verificar la cadena: GET /api/audit/verify-chain → chain_valid:true.

4. Políticas (motor determinista)

governance_policies {name, regulation, framework, applies_to[], policy_rules}. Reglas soportadas: max_bias, max_privacy_risk, max_risk_score, max_tokens_per_request, forbidden_categories[], requires_killswitch, max_toxicity, max_semantic_drift, pii_forbidden, prompt_injection_forbidden (+injection_threshold), system_prompt_leak_forbidden, max_pii_tokens_out, applies_to_stage. La política AI Threat Shield se crea automáticamente por tenant si no existe. Cache de políticas en Mongo con invalidación por versión (policies_version).


5. Conectores de IA (modelos propios) y Gateway

5.1 Modelo de datos

  • ai_connectors: {name, provider, base_url, network(public|private|loopback), egress{mode: direct|direct_private|proxy, proxy_id}, api_key_enc (AES-256-GCM, CONNECTOR_ENC_KEY), api_key_hint, default_model, model_id (→ ai_models_registered), sovereignty{kind, data_leaves_perimeter, processor_jurisdiction, model_origin, risk_level, regulatory_flags[]}, governance{...}, status, last_test}.
  • connector_egress_proxies: proxies inversos autorizados (proxy_url https, allowed_cidrs[], auth_token_enc). Requeridos para destinos privados salvo ALLOW_PRIVATE_EGRESS_DIRECT=true (despliegue on-prem/demo).
  • connector_transactions (TTL = governance.retention_days): {transaction_id, kind, latency_ms, upstream_ms, audit_ms, tokens{prompt,completion,total}, compliance_status, geopolitical_risk, data_left_perimeter, zk{anonymized,restored,unresolved,by_type}, rule, violations[], kill_switch_action, request_hash, decision_hash}. Nunca texto.

5.2 Reglas de gobernanza por conector (PUT /api/connectors/:id/governance)

CampoDefaultEfecto
pii_filter_lfpdppptrueEscaneo PII (PAN, CURP, RFC, CLABE, CPF, RUT, EMAIL, PHONE).
zk_anonymize_externaltrueAnonimización reversible hacia destinos externos (GovernanceZKEngine).
prompt_injection_detectiontrueThreat Shield determinista + normalización anti-evasión (base64, leetspeak, zero-width, NFKC).
kill_switch_threshold80Sensibilidad: solo riesgos ≥ umbral alimentan el consenso (Bajo 90 · Medio 80 · Alto 65).
block_on_geopolitical_riskaltoBloquea egreso de PII sin anonimizar hacia procesadores con ese riesgo o superior.
post_audit_enabled · post_audit_block_thresholdtrue · 75PostAuditEvaluator; riskScore > 75 o violación crítica → BLOCK_KILL_SWITCH.
kill_switch_on_output_leaktrueViolación crítica en la salida (fuga de secreto/system prompt, jailbreak exitoso) → KS inmediato del modelo vinculado.
forbidden_keywords[] · confidential_terms[][]Lista del admin; los términos confidenciales se persisten solo como SHA-256 (confidential_terms_hashes).
max_tokens_per_request · retention_days8192 · 90Límite (413) y retención de la bitácora de transacciones.

5.3 Anti-SSRF (analyzeBaseUrl)

Solo http(s); sin credenciales embebidas; resolución DNS en alta y en cada llamada (anti-rebinding); clases: public, private (RFC1918/fc00::/7), loopback, blocked (169.254/16 metadata, 0/8, 100.64/10 CGNAT, multicast, fe80::/10, fd00:ec2::). blocked nunca se permite. Público sin TLS → advertencia. Redirecciones no se siguen (redirect:'manual').

5.4 Gateway OpenAI-compatible

POST /api/v1/gateway/chat/completions (alias POST /api/v1/chat/completions) · GET /api/v1/gateway/models.

Selección de conector: header X-IAG-Connector: <id|nombre>, o model = "<nombre conector>", o model = "<conector>/<modelo upstream>"; con un único conector activo se usa por defecto y model pasa como upstream.

Secuencia:

  1. Auth Bearer (scope gateway:invoke o evaluate:stream), rate limit por key (X-RateLimit-*).
  2. Corto circuito: conector disabled → 403 CONNECTOR_DISABLED; KS active+block o modelo blocked → 403 KILL_SWITCH_ACTIVE.
  3. Pre-auditoría síncrona (sin I/O): tokens (413 MAX_TOKENS_EXCEEDED), Threat Shield (score ≥ 0.6 → 403 PROMPT_THREAT_BLOCKED con rule{id,name,framework,severity,matched_patterns}, kill_switch{triggered,consensus_action,layers}), PII, geopolítico (403 GEOPOLITICAL_PII_EGRESS), anonimización ZK (mapa → TokenCacheService.saveSessionMap(tx_gober_<uuid>), TTL 300 s).
  4. Forward al upstream (Authorization: Bearer <api_key descifrada>), timeout de cabeceras 120 s. stream_options.include_usage se añade cuando el proveedor lo soporta.
  5. Retención completa de JSON o SSE: límite de 2 MB y 120 s de lectura del cuerpo. No se entrega contenido mientras el proveedor genera la respuesta. SSE requiere finish_reason y [DONE]; cierre incompleto, JSON inválido, tamaño excesivo, timeout o canal no auditable → error, nunca APPROVED.
  6. Post-auditoría de las elecciones completas, texto de razonamiento/rechazo y llamadas textuales a herramientas. Términos prohibidos, PII residual o tokens inventados bloquean la salida. Los detectores siguen siendo deterministas, no universales. Sólo después se restauran tokens conocidos; borrado del mapa al terminar, incluso en error o cancelación.
  7. Entrega JSON o envoltura SSE posterior a auditoría, sin streaming de texto en tiempo real. Header X-IAG-Delivery-Mode: buffered-audited, metadata iag_governance.delivery_mode; un bloqueo devuelve HTTP 403 antes de entregar texto del proveedor. Un cliente SSE debe manejar errores JSON no-200.

Estados de compliance_status: APPROVED, BLOCKED_INJECTION, BLOCKED_OUTPUT, BLOCKED_GEOPOLITICAL, BLOCKED_KILL_SWITCH, BLOCKED_POLICY, UPSTREAM_ERROR, CLIENT_ABORTED.

5.5 GovernanceZKEngine y TokenCacheService

  • Tokens [CURP_n], [RFC_n], [FINANCIAL_n] (tarjeta con Luhn, CLABE), [PHONE_n], [EMAIL_n], [NAME_n] (honoríficos e introductores en español). Mismo valor → mismo token; índices ya presentes en el texto se reservan; cada valor cifrado AES-256-GCM con IV aleatorio y AAD = token (impide intercambiar entradas). Clave por tenant: HKDF(CONNECTOR_ENC_KEY, company_id); nunca se persiste.
  • Vault: REDIS_URL (driver oficial redis v4, reconexión con backoff, SET NX EX ≤300) con respaldo MongoDB TTL (zk_token_maps). Estado: GET /api/public/status → hardening.zk_token_cache.
  • Métrica objetivo: anonimizar+desanonimizar < 15 ms; pre-auditoría < 50 ms. Observado en pruebas internas: audit_ms ≈ 1–5 ms.

5.6 Integración de una aplicación cliente

export OPENAI_BASE_URL=https://<dominio>/api/v1/gateway
export OPENAI_API_KEY=gov_live_********
# Cualquier SDK OpenAI-compatible funciona: model = nombre del conector
curl $OPENAI_BASE_URL/chat/completions -H "Authorization: Bearer $OPENAI_API_KEY" -H 'Content-Type: application/json' \
  -d '{"model":"DeepSeek R1 Local","stream":true,"messages":[{"role":"user","content":"..."}]}'

Recomendado: enviar X-IAG-User-Ref: <id opaco del usuario final> para análisis de comportamiento (burst/probing/extracción) sin exponer identidad.

5.7 MOCK de pruebas (solo DEMO_MODE=true)

/api/mock-llm/v1/{models,chat/completions} — OpenAI-compatible, soporta stream. El prompt simula_fuga produce una salida maliciosa (token inventado + jailbreak) para ejercitar la post-auditoría. No existe en producción.

5.8 Vista previa de repositorios de agentes — SIMULADA (MOCK)

Este panel no tiene un escáner ni conexión a GitHub/GitLab. No audita repositorios reales ni acredita cumplimiento.

  • GET /api/agents/status (sesión): informa integration_status:not_connected, real_audit_available:false, audited_repositories:0 y si el usuario puede cargar ejemplos.
  • GET /api/agents/repos (sesión): array de muestras con data_source:demo, is_demo:true, verification_status:simulated; sin modo demo devuelve []. Los registros históricos sin procedencia no se muestran; no se eliminan.
  • POST /api/agents/seed (admin y controles MFA existentes, sólo DEMO_MODE=true): carga explícita de ejemplos idempotente, sin borrar registros. Fuera de demo está deshabilitado (404 tras superar autenticación/autorización).
  • Abrir o actualizar el panel no crea datos. Sus porcentajes y conflictos se etiquetan como ejemplos, sin commits ni sincronizaciones reales. Sin muestras no se calcula un índice de cumplimiento.

6. Gobernanza agéntica: propuestas y autoridad

  • GET /api/agent-policies devuelve la configuración efectiva y, separadamente, pending_change, pending_action, pending_id y revision. Una edición pendiente no retira la regla vigente del evaluador.
  • Con Cuatro Ojos, crear/editar/pausar/reactivar/eliminar requiere validar por otro gov_admin. POST /api/agent-policies/:id/validate y /reject-change reciben pending_id y credencial de reautenticación; el cliente debe enviar revision conocida para evitar una vista obsoleta. No se sustituye una propuesta pendiente por otra.
  • Desactivar Cuatro Ojos mediante PUT /api/governance/settings genera propuesta y conserva dual_control_enabled:true. Se resuelve con POST /api/governance/settings/validate o /reject-change, pending_id y reautenticación; validación requiere otro administrador.
  • Aprobar/rechazar /api/agent-approvals/:id/{approve,reject} exige el rol snapshot de la regla. gov_admin puede resolver ambas categorías; gov_approver no puede resolver una reservada a admin. El cargo humano descriptivo no se usa como permiso.
  • La resolución usa comparación atómica status:PENDING y expiración: un único ganador, perdedor 409 DECISION_CONFLICT. Actualizar la bandeja, no repetir una acción ciegamente. Poll: GET /api/v1/agent/decision/:id (singular), estados en mayúsculas y execution_token sólo al aprobar.
  • No existe endpoint de consumo/verificación de uso único del execution_token; la integración ejecutora debe respetar la autorización.
  • Kill-switch: un disparo no autoriza cambiar mode, auto_trigger o trigger_threshold. Para operator, omitir esos campos incluso si desea conservar su valor; su presencia devuelve 403. Sólo admin configura. alert no detiene tráfico y block sólo protege el camino integrado.
  • Evidencia pública: GET /api/public/capabilities y /trust#evidencia; registros documentales curados, no telemetría en vivo. Los campos sin prueba registrada mantienen last_verification:null.

6b. AI Threat Shield

Detectores deterministas (Capa 1) con pesos: ignore_instructions, reveal_system_prompt, role_override, dan_jailbreak, delimiter_injection, exfil_instruction, dump_data, encoded_payload, tool_abuse; análisis de comportamiento por user_ref (burst ≥ 30/min, tasa de violaciones, plantillas repetidas → MODEL_EXTRACTION_SUSPECTED, tokens PII en salida → DATA_EXFILTRATION_ATTEMPT); huella de system prompt por shingles hasheados (PUT /api/models/:id/system-prompt-fingerprint). Mapeo OWASP LLM Top 10 / MITRE ATLAS. Incidentes THREAT_DETECTED con dedup 10 min; webhook threat.detected con pistas OCSF (class_uid 2004).

Operación: GET /api/threats, PUT /api/threats/:id/ack, PUT /api/threats/:id/resolve {resolution, note}, POST /api/threats/simulate (operator, DEMO).


7. API pública, SDK y Muro Perimetral

  • POST /api/v1/public/sessions (scope sessions:create) → session_token por modelo/usuario.
  • POST /api/v1/public/evaluate-stream {session_token, text_payload, stage: INPUT|OUTPUT} (scope evaluate:stream). Tokens [TOKEN_<TIPO>_<HASH>] del SDK se aceptan como PII anonimizada; PII en claro → 422 fail-closed (ZK_FAIL_CLOSED=true).
  • GET /api/v1/public/healthcheck → heartbeat (Dead Man’s Switch: ausencia > 60 s → stale, incidente DMS con dedup 15 min).
  • SDK Python aiguard (/sdk): GovernanceClient, RedactionEngine, RedisTokenVault, mTLS opcional, threats.py. Muro Perimetral (/deploy/perimeter-wall): proxy K8s con redacción local y vault Redis. No publicado en PyPI; se entrega como código.

8. API keys y Webhooks

  • POST /api/keys {name, scopes[], expires_in_days, rate_limit_per_min} → la key en claro se muestra una sola vez; se persiste key_hash SHA-256 (en DEMO además plain, exclusivamente para evaluación). DELETE /api/keys/:id revoca de inmediato. Scopes: sessions:create, evaluate:stream, metrics:write, metrics:read, policies:read, policies:write, killswitch:read, killswitch:override, logs:read, keys:manage, gateway:invoke.
  • Webhooks HMAC v2: cabeceras X-IAG-Timestamp, X-IAG-Nonce, X-IAG-Signature: v2=HMAC-SHA256(timestamp.nonce.body); ventana ±5 min, anti-replay por nonce, reintentos 2/4/8/16/32 s. Eventos: killswitch.activated|deactivated, policy.violation, threat.detected. Verificación de ejemplo en /docs/WEBHOOKS.md.

9. Auditoría y evidencia

  • GET /api/audit?limit= (admin) — eventos con seq, prev_hash, hash, actor, IP, details saneados (claves sensibles redactadas).
  • GET /api/audit/verify-chain — recalcula la cadena; chain_valid:false implica alteración o pérdida.
  • Logs de evaluación: monitoring_logs (hash de entrada, scores, decisión, políticas violadas, latencia). Transacciones del Gateway: connector_transactions.

9b. Plataforma: gate de visitantes y Super Admin

  • Gate (middleware.js): toda ruta pública (landing, /trust, /status, /manual, /docs) exige una cookie válida: visitor_pin (PIN), gov_session (operador) o super_session. Excluidos /api/*, /gate, /superadmin, /legal/*, /?view=dashboard (sólo formulario de login). VISITOR_GATE_ENABLED=false lo desactiva. Es un control de exposición de información comercial, no una frontera de seguridad del plano de control (que sigue protegido por sesión + RBAC + MFA).
  • PINs: visitor_pins guarda SHA-256(pin | JWT_SECRET); vigencia y usos máximos; rate limit 10 verificaciones/min por IP; cada intento queda en gate_events (TTL 90 d).
  • **Super Admin (/superadmin, /api/superadmin/*): cuenta de plataforma (`platform_admins`, bcrypt, seed desde `SUPERADMIN_PHONE`/`SUPERADMIN_PASSWORD`; se recomienda cambiarla desde la UI: ≥ 12 caracteres). Funciones: alta de empresas (+ admin inicial), edición de plan/contrato/contactos, activar/suspender servicio** (motivo obligatorio; cierra sesiones del tenant vía session_version), inactivación automática al vencer contract_end (auto_suspend_on_expiry), métricas por tenant, generador y revocación de PINs, bitácora de accesos. Efecto de suspensión: login → 403 SERVICE_SUSPENDED, API keys → 403, Gateway → 403, rutas del plano de control → 403.

10. Runbooks de anomalías

SeñalDiagnósticoAcción
KILL_SWITCH_ACTIVE masivo en gatewayConsenso disparado o activación manualRevisar last_trigger_cause, GET /api/threats, transacciones del conector; reactivar con reason.
POST_AUDIT_BLOCK recurrente en un conectorModelo manipulado/comprometido o lista de prohibidos demasiado ampliaRevisar violations; si RESIDUAL_LEAK_* o SYSTEM_PROMPT_* tratar como compromiso del modelo: rotar system prompt, revisar fine-tuning/proveedor.
GEOPOLITICAL_PII_EGRESSPolítica de transferencia bloqueó PIIConfirmar zk_anonymize_external:true o mover carga a conector local; documentar decisión legal.
UPSTREAM_ERROR sostenidoEndpoint caído, TLS, API key caducada, proxy de egresoPOST /api/connectors/:id/test; revisar last_test.error; rotar api_key vía PUT.
PII_PLAINTEXT_REJECTEDCliente envía PII sin redactarDesplegar SDK/Muro; revisar X-ZK-Redacted (si venía true → bypass de redacción: ajustar patrones).
HUMAN_ALERT_REQUIREDCircuit breaker: toda la flota falla a la vezPosible falso positivo global o incidente mayor; decisión humana; el modo vuelve a AUTO tras 30 s.
Heartbeat stale / incidente DMSCliente sin latido > 60 sVerificar disponibilidad del cliente y conectividad saliente hacia /api/v1/public/healthcheck.
Webhook failingReceptor 4xx/5xx o firma rechazadaValidar secreto compartido y reloj (ventana ±5 min); revisar nonce store del receptor.
chain_valid:falseAlteración/pérdida en audit_eventsIncidente de seguridad: preservar la colección, comparar con respaldo, investigar accesos a la BD.
SERVICE_SUSPENDED / contract_expiredSuper Admin suspendió el tenant o venció contract_endRegularizar contrato; Super Admin → Activar o extender contract_end.
MFA_ENROLLMENT_REQUIRED en automatizacionesCuenta de servicio con rol admin/operator sin MFAUsar API keys para integraciones (no sesiones); las sesiones humanas requieren MFA.

11. Configuración y despliegue (variables relevantes)

MONGO_URL, DB_NAME, JWT_SECRET (+JWT_SECRET_PREVIOUS), MFA_ENC_KEY, MFA_REQUIRED_ROLES, CONNECTOR_ENC_KEY, ALLOW_PRIVATE_EGRESS_DIRECT, REDIS_URL, ZK_MAP_TTL_SEC, ZK_FAIL_CLOSED, SECRETS_PROVIDER/AWS_SECRETS_ID, DEMO_MODE (false en producción: desactiva cuentas demo, /seed, /demo-credentials, mock LLM y la auto-desactivación de MFA).

Checklist de salida a producción: DEMO_MODE=false · claves hex-64 dedicadas · ALLOW_PRIVATE_EGRESS_DIRECT=false salvo on-prem · Redis con TLS para el vault ZK · respaldos de MongoDB verificados · receptor de webhooks validado · revisión legal de Términos/Privacidad · pentest externo (pendiente en la hoja de ruta).


12. Límites conocidos (transparencia)

  • Detección PII/amenazas es determinista (regex + heurísticas); no hay clasificador ML en producción (hoja de ruta).
  • La evaluación de riesgo geopolítico es orientativa; no constituye asesoría legal.
  • No existen certificaciones SOC 2 / ISO 27001 / ISO 42001 de la plataforma; el diseño está alineado a esos marcos.
  • Redis y AWS Secrets Manager están soportados en código pero no aprovisionados en esta instalación.