Skip to content

Integración con API del DUT — tercer pilar de la telemetría de TLSStress.Art

Lee en tu idioma: English · Português · Español

Estado del alcance (post-congelación de alcance 2026-05-10) — Ver ARCHITECTURE.md para los 37 MÓDULOs canónicos + 7 Test Kinds + arquitectura de safety DOM/CPOS/PIE-PA. ADRs 0014, 0019-0025 cubren adiciones post-Freeze. Este documento describe cómo TLSStress.Art conversa con las APIs REST de los elementos de red del laboratorio — Cisco FTD (NGFW), Cisco Nexus 9000 (switch), Palo Alto, Fortinet — para enriquecer el Dashboard, Grafana y el Test Run Report con datos que solo la API puede entregar.

Es el tercer pilar de telemetría en este producto, sumándose a SNMP (métricas numéricas) y syslog (correlación de eventos):

Fuente Fortaleza Limitación
SNMP Contadores estandarizados (bytes de interfaz, CPU, memoria) Genérico; objetos vendor-specific poco modelados; sin config
Syslog Eventos en tiempo real con contexto completo Solo reactivo; sin estado actual; sin inventario
API (este doc) Config viva, versión, políticas aplicadas, status de deploy, LLDP/CDP, estado de HA Vendor-specific; requiere autenticación; hay que considerar el rate-limit

Las tres capas combinadas producen el nivel de completitud forense que el Test Run Report exige.

Qué desbloquea la integración de API

Capacidad Sin API Con API
Confirmar modelo + número de serie del NGFW SNMP entPhysicalSerialNum (genérico, a veces incorrecto en virtual appliances) Cisco FTD /operational/sysinfo devuelve modelo preciso + revisión de hardware
Confirmar que la política de decrypt está habilitada y qué reglas aplican ❌ no visible desde fuera ✅ Cisco FTD /policy/sslpolicies lista cada regla, acción, interfaces aplicadas
Confirmar status de deploy antes de iniciar una corrida ✅ Cisco FTD /operational/deploy — rechaza iniciar si hay cambios pendientes en cola
Confirmar que la config NTP del device coincide con la expectativa del laboratorio ✅ Cisco FTD /devicesettings/default/ntp + Cisco Nexus sys/time
Auto-descubrir topología del laboratorio vía LLDP/CDP ✅ Cisco Nexus DME sys/lldp/inst + sys/cdp/inst
Detectar standby de HA + saltar escrituras ✅ Cisco FTD HA endpoint + detección de 405
Capturar inventario de chassis + lista de módulos parcial ✅ Cisco Nexus sys/ch?rsp-subtree=full devuelve fans, PSUs, line cards con S/Ns
Anexo con chain-of-custody criptográfica ✅ Cada respuesta de API almacenada con SHA-256 en dut_api_snapshots

Arquitectura

                                    OOBI mgmt network
                                          │
   ┌─────────────────┐                   │
   │ Cisco FTD       │ ◄────HTTPS Bearer ┤
   │ (FDM API v6)    │                   │
   └─────────────────┘                   │
                                         │
   ┌─────────────────┐                   │
   │ Cisco Nexus 9k  │ ◄────APIC-cookie ─┤
   │ (NX-API DME)    │                   │
   └─────────────────┘                   │
                                         │  Server-side fetch
   ┌─────────────────┐                   │  inside Dashboard pod
   │ Cisco UCS CIMC  │ ◄────Basic Auth ──┤  (poll every N min OR
   │ (Redfish)       │                   │   on-demand at run start)
   └─────────────────┘                   │
                                         │
   ┌─────────────────┐                   │
   │ Fortinet        │ ◄────Bearer ──────┤
   │ (FortiOS REST)  │                   │
   └─────────────────┘                   ▼
                                     ┌──────────────────────┐
   ┌─────────────────┐               │ DUT API Collector    │
   │ Palo Alto       │ ◄────XML ────▶│ (Next.js worker)     │
   │ (PAN-OS) v6.x  │               │                      │
   └─────────────────┘               │ Adapter pattern:     │
                                     │ - cisco-ftd.ts       │
                                     │ - cisco-nexus.ts     │
                                     │ - cisco-ucs-cimc.ts  │
                                     │ - fortinet-fortigate.ts│
                                     │ - (future) palo-alto │
                                     └──────────┬───────────┘
                                                │
                          ┌─────────────────────▼────────────────────┐
                          │ Postgres                                  │
                          │  dut_api_devices    (creds AES-256-GCM)   │
                          │  dut_api_snapshots  (JSONB + SHA-256)     │
                          └─────────────────────┬────────────────────┘
                                                │
                ┌───────────────────────────────┼─────────────────────────┐
                ▼                               ▼                         ▼
     ┌──────────────────┐         ┌───────────────────────┐     ┌─────────────────┐
     │ Grafana          │         │ Test Run Report       │     │ TLS Decrypt     │
     │ "DUT Live State" │         │ Phase 3 Annex B (Nexus)│    │ Probe (cross-   │
     │ dashboard        │         │ Phase 3 Annex C (NGFW) │    │ verifies decryp │
     │                  │         │ + per-snapshot SHA-256│     │ policy)         │
     └──────────────────┘         └───────────────────────┘     └─────────────────┘

Resumen de referencia por fabricante

Cisco FTD (gestionado por FDM) — cisco-ftd

Aspecto Valor
Base URL https://<ftd-mgmt>/api/fdm/v6/
Auth OAuth2 password grant → Bearer token
Token endpoint POST /api/fdm/v6/fdm/token
TTL del token típicamente 30 min
Refresh en respuesta 401
Detalle de HA La unidad standby devuelve 405 en ciertas lecturas
Método de update Solo PUT — objeto completo obligatorio (sin PATCH)
Habilitar en el device nada — la FDM API viene activa por defecto

Endpoints que consumimos (solo lectura): - GET /operational/sysinfo → modelo, versión, hostname, uptime - GET /devicesettings/default/ntp → servidores NTP configurados + estado - GET /operational/interfaces → estado live de interfaces - GET /policy/sslpolicies → reglas de la política de decrypt SSL/TLS - GET /operational/deploy → pending/deploying/deployed - GET /policy/intrusionpolicies → política IPS aplicada - GET /devices/default/ha → estado del par HA

Referencia: https://developer.cisco.com/docs/ftd-api-reference/latest/

Cisco Nexus 9000 (NX-API REST DME) — cisco-nexus

Aspecto Valor
Base URL https://<nexus-mgmt>/api/
Auth POST /api/aaaLogin.jsonSet-Cookie: APIC-cookie
TTL de la cookie ~10 min (re-login en 401/403)
Object Model DME — Distinguished Names como sys, sys/ch, sys/intf, sys/lldp/inst
Forma de la respuesta {"totalCount":"N","imdata":[{"className":{"attributes":{...}}}]}
Habilitar en el device feature nxapi + nxapi https port 443
VRF binding nxapi use-vrf management (recomendado)

Endpoints que consumimos (solo lectura): - GET /api/node/mo/sys/ch.json?rsp-subtree=full → chassis + módulos + S/Ns - GET /api/node/mo/sys/time.json?rsp-subtree=full → config NTP + estado del clock - GET /api/node/mo/sys/intf.json?rsp-subtree=full → config de interfaces - GET /api/node/mo/sys/lldp/inst.json?query-target=subtree&target-subtree-class=lldpAdjEp → vecinos LLDP - GET /api/node/mo/sys/cdp/inst.json?query-target=subtree&target-subtree-class=cdpAdjEp → vecinos CDP - GET /api/node/mo/sys/vpc.json?rsp-subtree=full → estado del peer vPC (equivalente a HA)

Referencia: https://developer.cisco.com/docs/nx-os-n3k-n9k-api-ref/

Cisco UCS C-Series CIMC (Redfish) — cisco-ucs-cimc

Aspecto Valor
Base URL https://<cimc-mgmt>/redfish/v1/
Auth HTTP Basic (admin / password). Sin TTL de token — credenciales enviadas en cada solicitud
Habilitar en el device Redfish está activo por defecto en CIMC 4.0+; verificar en Admin → Communication Services
Caveat de HA Ninguno (CIMC es single-controller)
Método de update PATCH en /redfish/v1/Systems/{id} (no usado; somos read-only)

Endpoints que consultamos (read-only): - GET /redfish/v1/Systems/<id> → modelo del servidor, versión BIOS, serial, asset tag - GET /redfish/v1/Chassis/<id> → estado de power del chassis, indicadores, sku - GET /redfish/v1/Chassis/<id>/Power → estado de PSU, vatiaje total, fuentes - GET /redfish/v1/Chassis/<id>/Thermal → ventiladores, temperatura inlet/outlet, breaches de threshold - GET /redfish/v1/Managers/<id> → versión de firmware del CIMC, salud del servicio - GET /redfish/v1/Systems/<id>/Memory → inventario de DIMMs + salud (por slot) - GET /redfish/v1/Systems/<id>/Processors → modelos de CPU + cantidad de cores + salud

Referencia: https://www.dmtf.org/standards/redfish (estándar Redfish de DMTF, implementación Cisco CIMC).

Fortinet FortiGate (FortiOS REST v2) — fortinet-fortigate

Aspecto Valor
Base URL https://<fgt-mgmt>/api/v2/
Auth Token de API (Bearer). Token generado por admin en System → Administrators → REST API Admin. Sin TTL — el token es long-lived
Rotación de token Manual (el operador regenera el token en la GUI; luego actualiza en nuestra admin UI)
Caveat de HA La unidad activa sirve la API; standby retorna redirect — el adapter sigue el redirect transparentemente
Método de update PUT en /cmdb/<path>, pero somos read-only

Endpoints que consultamos (read-only): - GET /api/v2/monitor/system/status → hostname, versión, serial, uptime - GET /api/v2/monitor/system/interface → estado y contadores de interfaces - GET /api/v2/cmdb/system/ntp → servidores NTP configurados - GET /api/v2/cmdb/firewall/ssl-ssh-profile → perfiles de inspección SSL - GET /api/v2/cmdb/firewall/policy → tabla de policies de firewall (reglas relevantes para decryption) - GET /api/v2/monitor/system/ha-status → estado del cluster HA, primario/secundario

Referencia: https://docs.fortinet.com/document/forticonverter/fortios/restapi/

Palo Alto (PAN-OS XML API) — planeado v6.x

Backlogged. Sin scaffold de adapter aún. Cuando se implemente, auth será generación de API key vía /api/?type=keygen&user=...&password=.... Los endpoints de lectura siguen el patrón ?type=op&cmd=<show...>.

Modelo de datos

dut_api_devices (una fila por device registrado)

Columna Propósito
hostname Identificador único en el laboratorio
vendor cisco-ftd / cisco-nexus / cisco-ucs-cimc / fortinet-fortigate / palo-alto-panos (planned)
device_role ngfw / switch / futuro
base_url https://10.0.0.1
username Cuenta de API
password_enc Ciphertext AES-256-GCM (BYTEA) — ver Encryption
tls_verify_mode strict (default) / self-signed (pin del primer cert) / insecure
pinned_cert_sha256 Establecido en la primera conexión cuando tls_verify_mode=self-signed
poll_interval_seconds Default 300 (5 min); mínimo 30
enabled Activar/desactivar sin borrar la fila
last_poll_at / last_poll_status / last_poll_error Status live mostrado en la UI admin
notes Notas libres del operador

dut_api_snapshots (historial append-only)

Cada llamada a la API exitosa (o incluso fallida) escribe una fila. Cada fila es el payload JSON completo con SHA-256 de la forma canónica para chain-of-custody forense.

Columna Propósito
device_id / device_hostname / vendor Desnormalizado para queries rápidas
endpoint_path Path vendor-specific (ej. /api/fdm/v6/operational/sysinfo)
endpoint_label Label vendor-agnostic — system_info, ntp_config, lldp_neighbors, etc.
http_status Status de la respuesta de la API
payload_json JSON completo del fabricante (columna JSONB)
payload_sha256 digest hex, citado en los anexos del Test Run Report
collector_version Versión de TLSStress.Art que tomó el snapshot
test_run_execution_id NULL para polls de background; establecido cuando el snapshot se ató a una corrida específica

Valores vendor-agnostic de endpoint_label: system_info, ntp_config, interfaces, lldp_neighbors, cdp_neighbors, decrypt_policy, deploy_status, ips_policy, qos_state, mac_table, routing_table, ha_status, license_state, config_running.

Esto permite al Dashboard escribir queries como "dame la config NTP más reciente de cualquier NGFW registrado, sin importar el fabricante" sin branching por fabricante.

Cifrado de credenciales

Las credenciales del DUT se almacenan cifradas en AES-256-GCM en la columna BYTEA de Postgres. La clave de cifrado es la env var DUT_CRED_ENC_KEY, provista vía Secret estándar de K8s.

Requisitos de la clave: - 32 bytes - Provista como 64 hex chars O codificación base64 - Generar una vez con node -e "console.log(require('crypto').randomBytes(32).toString('hex'))" - Almacenar en K8s Secret, montar como env var en el pod del dashboard

Formato de cifrado: IV (12 bytes) || ciphertext || auth tag (16 bytes) concatenados como un solo valor BYTEA. El helper decryptPassword() separa y verifica el tag GCM — corrupción o clave equivocada lanza error.

Rotación de clave: re-cifrar cada fila bajo la nueva clave. Helper de migration para esto está planificado.

Flujo del operador

Habilitar APIs en los devices

Cisco FTD — ya viene activa por defecto. Confirma con:

show api-server-info

Cisco Nexus 9000:

configure terminal
feature nxapi
nxapi https port 443
nxapi use-vrf management
end
write memory
show nxapi

Configurar la clave de cifrado (una sola vez)

# Generate
KEY=$(node -e "console.log(require('crypto').randomBytes(32).toString('hex'))")

# Provision via K8s Secret
kubectl create secret generic tlsstress-dut-cred \
  --from-literal=DUT_CRED_ENC_KEY="$KEY" \
  -n web-agents

# Reference in the dashboard Deployment env block:
#   env:
#     - name: DUT_CRED_ENC_KEY
#       valueFrom:
#         secretKeyRef:
#           name: tlsstress-dut-cred
#           key: DUT_CRED_ENC_KEY

Registrar un device

(El PR de follow-up entrega la UI admin. Por ahora, los devices se registran vía endpoint de API o directamente en la base de datos.)

curl -X POST "https://dashboard/api/admin/dut/devices" \
  -H "Authorization: Bearer $ADMIN_TOKEN" \
  -H "content-type: application/json" \
  -d '{
    "hostname": "ftd-1.lab.example.com",
    "vendor": "cisco-ftd",
    "deviceRole": "ngfw",
    "baseUrl": "https://10.10.10.1",
    "username": "admin",
    "password": "<plaintext — will be encrypted server-side>",
    "tlsVerifyMode": "self-signed",
    "pollIntervalSeconds": 300,
    "notes": "Cisco FTD 7.4 on FPR1010 — primary in HA pair"
  }'

Probar la conexión

curl -X POST "https://dashboard/api/admin/dut/devices/<id>/test" \
  -H "Authorization: Bearer $ADMIN_TOKEN"
# expect: {"ok": true, "detail": "auth OK; CPU monitor reachable in 142ms", "latencyMs": 142}

Disparar un snapshot manualmente

curl -X POST "https://dashboard/api/admin/dut/devices/<id>/snapshot" \
  -H "Authorization: Bearer $ADMIN_TOKEN"
# returns the IDs of the snapshot rows just written

Polling en background

Una vez habilitado, el worker de polling del dashboard itera sobre los devices registrados al poll_interval_seconds configurado, ejecuta todos los métodos collect* soportados y graba snapshots. La implementación del polling worker llega en el PR-B (follow-up).

Vincular snapshots a una corrida

Cuando una corrida de Test Plan inicia, el engine dispara un snapshot inmediato de cada device registrado con test_run_execution_id establecido. Ese snapshot se vuelve el "estado del DUT al inicio" de la corrida. Al terminar la corrida, otro snapshot establece el "estado del DUT al final". Ambos se referencian en el Test Run Report.

Modelo de seguridad

Lo que la integración SÍ HACE

  • Almacena credenciales del DUT cifradas at rest (AES-256-GCM)
  • Usa HTTPS para cada llamada al device
  • Soporta cert-pinning para devices self-signed
  • Loguea cada snapshot en una tabla append-only con SHA-256
  • Audit-log de cada registro de device / cambio de credencial

Lo que la integración NO HACE

  • NO escribe en el device por defecto — solo métodos de adapter read-only. Métodos de escritura futuros (ej. configurar servidor NTP vía API) serán flujos explícitos con confirmación del operador y auditoría separada
  • NO hace cache de credenciales en texto plano más allá de la duración de una llamada de API
  • NO soporta flujo OAuth client_credentials en FTD (solo password grant) — si tu política de seguridad exige client_credentials, abre un issue

Threat model

Amenaza Mitigación
Filtración de la base expone credenciales AES-256-GCM con clave en K8s Secret — el atacante también debe obtener DUT_CRED_ENC_KEY
MITM en la ruta adapter↔device Verificación TLS (strict default); modo insecure requiere opt-in explícito del operador y queda registrado en tls_verify_mode
Pod del dashboard comprometido abusa del acceso a la API Adapter es read-only por defecto; métodos de escritura futuros requerirán re-auth admin nueva
Replay de respuestas viejas de la API payload_sha256 + timestamp collected_at; mismatch detectable por quien tenga tanto el snapshot como un fetch contemporáneo del device
Error de tipeo del operador registra device equivocado Botón "Test connection" valida auth + reachability antes de guardar

Consideraciones de performance + rate-limit

Intervalo de poll por defecto es 5 minutos por device. Observación empírica:

  • Cisco FTD: recoger los 7 endpoints de lectura toma ~3-8 segundos en total (token en cache, llamadas secuenciales)
  • Cisco Nexus 9000: recoger los 6 endpoints toma ~2-5 segundos (cookie en cache)
  • Ningún fabricante documenta números de rate-limit; ambos parecen aguantar 1 llamada/segundo cómodamente en lecturas

Si corres múltiples devices, el loop de poll del worker es secuencial por device (no paralelo) para ser educado. Tiempo total de ciclo = suma de las duraciones por device.

Trabajo futuro — operaciones de escritura

Una vez que la fundación de lectura sea estable, los métodos de escritura se vuelven posibles:

  • Configurar servidor NTP en Cisco FTD: PUT /api/fdm/v6/devicesettings/default/ntp/{objId} (objeto completo) + POST /api/fdm/v6/operational/deploy para commit
  • Resetear contadores de interfaz en Cisco Nexus: POST MO con action clear
  • Alternar estado de la política de decrypt para tests A/B durante una corrida
  • Aplicar política QoS específica del test-bed en Nexus pre-corrida, revertir post-corrida

Cada escritura requerirá: 1. Re-auth admin al momento del request 2. Confirmación explícita del operador en la UI ("a punto de cambiar fuente NTP del NGFW — proseguir?") 3. Entrada de audit log con snapshots before/after 4. Rollback automático si la lectura post-escritura confirma divergencia respecto a la intención

Fuera de scope para este PR; rastreado como PR-C en el roadmap de integración de API.

What ships in this PR

Este PR es la fundación: - Tablas de la base + schema Drizzle - Helpers de cifrado de credenciales AES-256-GCM - Interface de adapter + catálogo ENDPOINT_LABELS - Adapter Cisco FTD funcional con 7 endpoints de lectura - Adapter Cisco Nexus funcional con 6 endpoints de lectura (cubre descubrimiento LLDP/CDP) - Esta documentación

What ships in PR-B (follow-up): - UI admin para registrar devices - Polling worker (Kubernetes CronJob O Next.js server interval) - Endpoints de API /api/admin/dut/devices/* + /api/admin/dut/snapshots/* - Dashboard Grafana "TLSStress.Art — DUT Live State" - Integración en la ejecución del Test Plan (snapshot al inicio + final de la corrida)

What ships in PR-C (futuro): - Adapters Palo Alto + Fortinet - Test Run Report Phase 3 Annex B/C cableado a estos snapshots - Operaciones de escritura (set NTP, toggle decrypt-policy) con flujo de confirmación del operador

Relacionados

Referencias