CreaRack-SL

Decisión: SSH TOFU server-side con degradación (Auditoría Suprema A9/M3)

Contexto

Hallazgo de auditoría (Auditoría Suprema Etapa 3, network A9/sa1 + M3/sa2):

ScrapliManager conectaba con auth_strict_key=False, deshabilitando la verificación de identidad del host SSH. Esto permite un ataque de hombre en el medio (MITM): un atacante en la red podría suplantar un equipo y capturar credenciales.

Opciones evaluadas:

  1. TOFU rígido: registra clave en primera conexión, bloquea cualquier cambio (seguro, pero puede bloquear nuevos equipos)
  2. TOFU con degradación: registra clave, la exige después, pero degrada a no-check si es primera conexión y no se puede captar la clave (seguridad + usabilidad)
  3. Sin verificación (estado actual): vulnerabilidad presente

Decisión

TOFU con degradación, implementado por organización sin modelo Django.

Justificación

  1. Seguridad: la mayoría de conexiones son a equipos ya registrados → MITM protection activo
  2. Usabilidad: primera conexión a nuevo equipo nunca falla por falta de clave (mejor UX que bloqueo riguroso)
  3. Escalabilidad: sin modelo DB, sin migración → más rápido de desplegar, menos carga
  4. Multi-tenancy: almacén por org_id → dos tenants con RFC1918 iguales no interfieren

Trade-offs aceptados

  • Riesgo residual en primera conexión: un MITM activo al conectar por primera vez a un equipo nuevo podría capturar la clave. Mitigado por:

    • Arquitectura: la mayoría de deployments aislados por firewall (no acceso desde internet)
    • Operativo: el equipo debe estar reachable la primera vez; atacante debe estar en el camino exacto
    • Futuro: se puede tomar la clave del dispositivo vía API/SNMP anterior, o validar fuera de banda
  • Sin garantía de no regresión en conectividad: si scrapli/asyncssh rompen el interface, el fallback es auth_strict_key=False. Mitigado por tests.

Implementación

  • Archivo: network/services/ssh_host_keys.py
  • Almacén: MEDIA_ROOT/ssh_known_hosts/<org_id>/known_hosts (filesystem, sin DB)
  • Función pública: scrapli_strict_args(org_id, host, port) → dict de kwargs para ScrapliManager
  • Propagación: org_id desde request (scripts.py) o device (backups.py)
  • Tests: 6 tests en test_network_ssh_tofu.py

Precedente

Diseño refleja el TOFU del Agent (terminal/agent/network/host_keys.py, s124). La diferencia: Agent = por máquina local; servidor = por tenant (multi-org).

Revisión futura

  • Validación de clave fuera de banda (por API del dispositivo, SNMP, etc.)
  • Rotación de claves + notificación de cambios sospechosos
  • Dashboard de “claves por dispositivo por org”

Véase también

  • [[feature—security—ssh-tofu-server-side]]
  • [[entity—network—service—ssh-host-keys]]
  • [[entity—network—service—scrapli-manager]]
  • [[concept—network—ssh-host-verification]]
  • [[concept—security—mitm-prevention]]