Volver a la wiki

Fase 3 · Autenticación local del Agent (Raíz 3 Auditoría Suprema)

Resumen

Agent 2.0.24 → 2.1.0 · Cierra los 12 hallazgos de severidad ALTA de la Raíz 3 de la Auditoría Suprema del dominio terminal. El Agent local genera un token secreto (opaco, 32B), lo persiste cifrado en el PC del cliente, lo deposita en el SaaS al conectar, y a partir de ahí solo acepta órdenes de quién presente ese token. Combinado con las Fases 1-2 (ya en PROD), cierra definitivamente la exposición a DNS-rebinding/CSRF.

El problema (Raíz 3)

Hasta 2.1.0, la API HTTP local del Agent (http://127.0.0.1:PORT/) atendía a cualquiera que llamara desde el PC del cliente:

La auditoría identificó esto como el bloque de seguridad más grave del Agent (12 hallazgos ALTA).

La solución (Fase 3)

La autenticación local del Agent sigue un modelo de three-phase rollout:

FaseCuándoQuiénQué
Fase 1✓ PRODSaaSGenera/custodia el token local de cada Agent (cifrado en BD)
Fase 2✓ PRODFrontend (navegador)Recibe el token del SaaS, lo inyecta en llamadas a la API local via Bearer + WS via postMessage
Fase 3✓ Esta PR (2.1.0, build pendiente)Agent .exeGenera el token, lo persiste localmente, lo deposita en el SaaS, lo exige en toda la API HTTP y el WS

Componentes (Fase 3)

  1. [[entity—agent—service—local-token]] — Generación, persistencia (DPAPI) y validación del token:

    • get_or_create_local_token(): genera token_urlsafe(32), lo almacena cifrado en %APPDATA%/CreaRackAgent/local_token.enc, lo cachea en memoria.
    • verify_local_token(candidate): compara en tiempo constante con hmac.compare_digest().
    • auth_required(auth_manager): retorna True solo si el Agent está vinculado a un SaaS.
    • extract_bearer(headers): parsea Authorization: Bearer <token>.
    • allowed_origins_for(auth_manager, port): retorna origins CORS permitidos (SaaS + UI local, o ["*"] pre-activación).
    • EXEMPT_PATHS: /info, /health, /check, /favicon.ico, /, /terminal/ui, /saas/configure|status|connect (bootstrap del frontend + activación inicial).
  2. [[entity—agent—service—connector-register-local-token]] — Integración del token con el SaaS:

    • connector._register_local_token(): POST /api/agent/register-local-token con el token.
    • Best-effort: reintenta en cada reconexión WS; si falla, el frontend sigue sin token (middleware local rechaza la solicitud).
  3. [[entity—agent—service—terminal-ws-auth]] — Validación en tiempo de conexión WS:

    • Primer mensaje obligatorio: {"action": "auth", "token": <token>}.
    • terminal.html lo recibe del SaaS vía postMessage SET_AUTH_TOKEN (Fase 2) y lo manda en open/reconexión.
    • Sin token válido → WebSocket cierra con código 4401.
  4. Middleware HTTP en main.py:

    • Instala security headers (CSP + X-Frame).
    • Gate Bearer: antes de cualquier endpoint (salvo EXEMPT_PATHS), valida el token.
    • CORS cerrado: allow_origins pasa de ["*"] al origin del SaaS + UI local.
    • Orden de middlewares (IMPORTANTE): gate + headers → CORS (capa más externa).

Seguridad detallada

Token local

Depósito en el SaaS

Gate Bearer en la API local

Si (method == OPTIONS) OR (path in EXEMPT_PATHS) OR (not auth_required()) OR (token válido):
  → llamada normal
Else:
  → 401 "Local auth token required"

CORS

WebSocket de consola

// client (terminal.html)
window.addEventListener('message', (event) => {
  if (event.data.type === 'SET_AUTH_TOKEN') {
    localAuthToken = event.data.token;
    sendWsAuth(ws);  // Envía {"action":"auth","token":...} en open
  }
});

// server (routes/terminal.py)
if auth_required():
    first = await ws.receive_text()  // Espera primer mensaje
    if first.action != "auth" or not verify_local_token(first.token):
        await ws.close(4401)
        return

Compatibilidad

Versión AgentSaaS Fase 1Frontend Fase 2Comportamiento
2.0.24 (old)✓✓Token opcional; no verificado (compat)
2.1.0 (nuevo)✓✓Token exigido cuando vinculado; WS exige auth
2.1.0✓✗ (viejo)Token depositado; frontend no lo inyecta → 401 en primeras llamadas

En la release final: compilar 2.1.0, hacer smoke tests (terminal, SSH, discovery, signage), publicar agent-v2.1.0, borrar release anterior.

Testing

6 tests en tests/agent/test_agent_local_auth.py:

Estado: ✓ Verdes en Docker; py_compile de los 5 módulos OK.

Véase también

Subir