CreaRack-SL

Auditoría Suprema 2 · Tanda 1 (monitoring + racks): gates de permiso en Observatory, CNS y radar de integridad

Cuándo

31-08-2026 · commit 29f793c (PR #477, v1.91.0). Segundo PR de la Tanda 1 de la Auditoría Suprema 2 — el primero (v1.90.0, mismo día) cerró 4 ALTA equivalentes en el dominio core. Esta entrega cubre monitoring y racks.

Síntomas visibles

Tres endpoints/grupos de endpoints comprobaban solo que el usuario pertenecía a la organización (get_current_org), nunca su nivel de permiso dentro de ella:

  1. Observatory (monitoring/api/observatory.py) — 7 endpoints sin require_perm: el layout del panel, las notas rápidas y los ajustes de gráficas son preferencias de toda la organización (no personales), y se leían/sobrescribían sin comprobar el scope observatory. Un usuario con observatory: none podía tocarlas igual que un admin.
  2. API CNS (monitoring/api/insight_execution.py, insights.py, insight_conversations.py, tutor.py) — ningún require_perm. El vector más grave: un usuario readonly (que sí tiene cns:view) podía ejecutar en los equipos los comandos SSH que la IA propone, vía POST /apply, sin tener cns:edit.
  3. Radar de integridad (racks/api/integrity.py, endpoint overview) — servía inventario de red (IP, hostname, vendor, número de serie, MAC) exigiendo solo pertenencia a la org, sin comprobar network:view — a diferencia de su endpoint hermano cable-report, que sí lo exige.

Causa raíz

Mismo patrón sistémico ya visto en el core (v1.90.0, mismo día) y en la Auditoría Suprema original sobre network y racks: el endpoint valida la organización pero no el nivel de permiso (ModulePermission) del usuario dentro de ella. No es un fallo puntual — es una clase de vulnerabilidad que reaparece dominio a dominio conforme se van auditando, porque require_perm no es un middleware automático: hay que declararlo explícitamente en cada endpoint Ninja.

Fix aplicado

Commit 29f793c13679323ee24c1e267d5b426c7f8ca1bc (PR #477):

  • require_perm(request, "observatory", "view"|"edit") en los 7 endpoints de Observatory — view en lecturas, edit en escrituras — antes de require_org.
  • require_perm(request, "cns", "edit") en apply/dry_run/rollback/acknowledge/revise/tutor-clear; "view" en list/stats/detail/conversations/tutor. Los endpoints de ingesta del Agente (receive_insight, report_recovery, receive_execution_result, explain) quedan fuera del gate a propósito: se autentican por el JWT del Agente, no por sesión de usuario. purge ya era superuser-only antes del fix.
  • require_perm(request, "racks", "view") y require_perm(request, "network", "view") en integrity.overview — igual que su endpoint hermano cable-report.
  • 13 tests nuevos: tests/monitoring/test_cns_observatory_authz.py (100 líneas) y tests/racks/test_integrity_authz.py (42 líneas) — cubren que un readonly no ejecuta insights ni sobrescribe el observatory, que cns:none/network:none/observatory:none reciben 403, y que los caminos legítimos (view) siguen devolviendo 200.

Lecciones

El mismo patrón — “gate por organización, nunca por nivel” — ha aparecido ya en core, network (Suprema 1, SA1-SA5), racks (Suprema 1) y ahora monitoring. Cada auditoría nueva lo vuelve a encontrar en un dominio distinto porque no hay ningún control estructural que obligue a declarar require_perm en un endpoint Ninja — depende de que la auditoría manual llegue a ese archivo.

Preventivos futuros

  • Continuar la Tanda 1 de la Auditoría Suprema 2 sobre los dominios que falten.
  • Valorar un check de CI (lint/test estructural) que detecte endpoints Ninja mutantes sin require_perm, para no depender solo de rondas de auditoría sucesivas.

Véase también

  • [[entity—core—service—require-perm]]
  • [[entity—core—service—has-permission]]
  • [[crearack—conceptos—usuarios-y-permisos]]
  • [[incident—20260602—auditoria-suprema-mini-tanda-seguridad]]
  • [[incident—20260602—auditoria-suprema-racks]]
  • [[feature—monitoring—auditoria-suprema-sa6-observatory-realtime]]
  • [[feature—monitoring—auditoria-suprema-sa3-cns-insights-ia]]