Skip to content

Integração com API do DUT — terceiro pilar da telemetria do TLSStress.Art

Leia no seu idioma: English · Português · Español

Status do escopo (pós-congelamento de escopo 2026-05-10) — Ver ARCHITECTURE.md para os 37 MÓDULOs canônicos + 7 Test Kinds + arquitetura de safety DOM/CPOS/PIE-PA. ADRs 0014, 0019-0025 cobrem adições pós-Freeze. Este documento descreve como o TLSStress.Art conversa com as APIs REST dos elementos de rede do laboratório — Cisco FTD (NGFW), Cisco Nexus 9000 (switch), Palo Alto, Fortinet — para enriquecer o Dashboard, o Grafana e o Test Run Report com dados que somente a API consegue fornecer.

É o terceiro pilar de telemetria deste produto, juntando-se ao SNMP (métricas numéricas) e ao syslog (correlação de eventos):

Fonte Ponto forte Limitação
SNMP Contadores padronizados (bytes de interface, CPU, memória) Genérico; objetos vendor-specific pouco modelados; sem config
Syslog Eventos em tempo real com contexto completo Apenas reativo; sem estado atual; sem inventário
API (este doc) Config viva, versão, políticas aplicadas, status de deploy, LLDP/CDP, estado de HA Vendor-specific; exige autenticação; precisa considerar rate-limit

As três camadas combinadas produzem o nível de completude forense que o Test Run Report exige.

O que a integração de API destrava

Capacidade Sem API Com API
Confirmar modelo + número de série do NGFW SNMP entPhysicalSerialNum (genérico, às vezes errado em virtual appliances) Cisco FTD /operational/sysinfo retorna modelo preciso + revisão de hardware
Confirmar que a política de decrypt está habilitada e quais regras se aplicam ❌ não visível externamente ✅ Cisco FTD /policy/sslpolicies lista cada regra, ação, interfaces aplicadas
Confirmar status de deploy antes de iniciar uma execução ✅ Cisco FTD /operational/deploy — recusa iniciar se houver mudanças pendentes na fila
Confirmar que a config NTP do device bate com a expectativa do laboratório ✅ Cisco FTD /devicesettings/default/ntp + Cisco Nexus sys/time
Auto-descoberta de topologia do laboratório via LLDP/CDP ✅ Cisco Nexus DME sys/lldp/inst + sys/cdp/inst
Detectar standby de HA + pular escritas ✅ Cisco FTD HA endpoint + detecção de 405
Capturar inventário de chassis + lista de módulos parcial ✅ Cisco Nexus sys/ch?rsp-subtree=full retorna fans, PSUs, line cards com S/Ns
Anexo com chain-of-custody criptográfica ✅ Cada resposta de API armazenada com SHA-256 em dut_api_snapshots

Arquitetura

                                    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)         │
     └──────────────────┘         └───────────────────────┘     └─────────────────┘

Resumo de referência por fabricante

Cisco FTD (gerenciado pelo 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 do token tipicamente 30 min
Refresh em resposta 401
Detalhe de HA Unidade standby retorna 405 em certas leituras
Método de update Apenas PUT — objeto completo obrigatório (sem PATCH)
Habilitar no device nada — a FDM API vem ligada por padrão

Endpoints que consumimos (somente leitura): - GET /operational/sysinfo → modelo, versão, hostname, uptime - GET /devicesettings/default/ntp → servidores NTP configurados + estado - GET /operational/interfaces → estado live de interfaces - GET /policy/sslpolicies → regras da política de decrypt SSL/TLS - GET /operational/deploy → pending/deploying/deployed - GET /policy/intrusionpolicies → política IPS aplicada - GET /devices/default/ha → estado do par HA

Referência: 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 do cookie ~10 min (re-login em 401/403)
Object Model DME — Distinguished Names como sys, sys/ch, sys/intf, sys/lldp/inst
Formato da resposta {"totalCount":"N","imdata":[{"className":{"attributes":{...}}}]}
Habilitar no device feature nxapi + nxapi https port 443
VRF binding nxapi use-vrf management (recomendado)

Endpoints que consumimos (somente leitura): - 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 do 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 → vizinhos LLDP - GET /api/node/mo/sys/cdp/inst.json?query-target=subtree&target-subtree-class=cdpAdjEp → vizinhos CDP - GET /api/node/mo/sys/vpc.json?rsp-subtree=full → estado do peer vPC (equivalente a HA)

Referência: 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). Sem TTL de token — credenciais enviadas a cada requisição
Habilitar no device Redfish está ativo por padrão no CIMC 4.0+; verifique em Admin → Communication Services
Caveat de HA Nenhum (CIMC é single-controller)
Método de update PATCH em /redfish/v1/Systems/{id} (não usamos; somos read-only)

Endpoints que acessamos (read-only): - GET /redfish/v1/Systems/<id> → modelo do servidor, versão BIOS, serial, asset tag - GET /redfish/v1/Chassis/<id> → estado de power do chassis, indicadores, sku - GET /redfish/v1/Chassis/<id>/Power → status de PSU, wattagem total, fontes - GET /redfish/v1/Chassis/<id>/Thermal → fans, temperatura inlet/outlet, breaches de threshold - GET /redfish/v1/Managers/<id> → versão de firmware do CIMC, saúde do serviço - GET /redfish/v1/Systems/<id>/Memory → inventário de DIMMs + saúde (por slot) - GET /redfish/v1/Systems/<id>/Processors → modelos de CPU + contagem de cores + saúde

Referência: https://www.dmtf.org/standards/redfish (padrão Redfish da DMTF, implementação Cisco CIMC).

Fortinet FortiGate (FortiOS REST v2) — fortinet-fortigate

Aspecto Valor
Base URL https://<fgt-mgmt>/api/v2/
Auth Token de API (Bearer). Token gerado por admin em System → Administrators → REST API Admin. Sem TTL — token é long-lived
Rotação de token Manual (operador regenera token na GUI; depois atualiza na nossa admin UI)
Caveat de HA Unidade ativa serve a API; standby retorna redirect — adapter segue o redirect transparentemente
Método de update PUT em /cmdb/<path>, mas somos read-only

Endpoints que acessamos (read-only): - GET /api/v2/monitor/system/status → hostname, versão, serial, uptime - GET /api/v2/monitor/system/interface → estado e contadores de interfaces - GET /api/v2/cmdb/system/ntp → servidores NTP configurados - GET /api/v2/cmdb/firewall/ssl-ssh-profile → perfis de inspeção SSL - GET /api/v2/cmdb/firewall/policy → tabela de policies de firewall (regras relevantes para decryption) - GET /api/v2/monitor/system/ha-status → estado do cluster HA, primário/secundário

Referência: https://docs.fortinet.com/document/forticonverter/fortios/restapi/

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

Backlog. Sem scaffold de adapter ainda. Quando implementado, auth será geração de API key via /api/?type=keygen&user=...&password=.... Endpoints de leitura seguem o padrão ?type=op&cmd=<show...>.

Modelo de dados

dut_api_devices (uma linha por device registrado)

Coluna Propósito
hostname Identificador único no laboratório
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 Conta de API
password_enc Ciphertext AES-256-GCM (BYTEA) — veja Encryption
tls_verify_mode strict (default) / self-signed (pin do primeiro cert) / insecure
pinned_cert_sha256 Definido na primeira conexão quando tls_verify_mode=self-signed
poll_interval_seconds Default 300 (5 min); mínimo 30
enabled Liga/desliga sem deletar a linha
last_poll_at / last_poll_status / last_poll_error Status live exibido na UI admin
notes Notas livres do operador

dut_api_snapshots (histórico append-only)

Toda chamada de API bem-sucedida (ou até falhada) escreve uma linha. Cada linha é o payload JSON completo com SHA-256 da forma canônica para chain-of-custody forense.

Coluna Propósito
device_id / device_hostname / vendor Desnormalizado para queries rápidas
endpoint_path Path vendor-specific (ex.: /api/fdm/v6/operational/sysinfo)
endpoint_label Label vendor-agnostic — system_info, ntp_config, lldp_neighbors, etc.
http_status Status da resposta da API
payload_json JSON completo do fabricante (coluna JSONB)
payload_sha256 digest hex, citado nos anexos do Test Run Report
collector_version Versão do TLSStress.Art que puxou o snapshot
test_run_execution_id NULL para polls de background; preenchido quando o snapshot foi vinculado a uma execução 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.

Isso permite ao Dashboard escrever queries como "me dê a config NTP mais recente de qualquer NGFW registrado, independente do fabricante" sem branching por fabricante.

Criptografia de credenciais

Credenciais do DUT são armazenadas criptografadas em AES-256-GCM na coluna BYTEA do Postgres. A chave de criptografia é a env var DUT_CRED_ENC_KEY, provisionada via Secret padrão do K8s.

Requisitos da chave: - 32 bytes - Fornecida como 64 hex chars OU codificação base64 - Gerar uma vez com node -e "console.log(require('crypto').randomBytes(32).toString('hex'))" - Armazenar em K8s Secret, montar como env var no pod do dashboard

Formato de criptografia: IV (12 bytes) || ciphertext || auth tag (16 bytes) concatenados como um único valor BYTEA. O helper decryptPassword() separa e verifica a tag GCM — corrupção ou chave errada lança erro.

Rotação de chave: re-criptografar cada linha sob a nova chave. Helper de migration para isso está planejado.

Fluxo do operador

Habilitar APIs nos devices

Cisco FTD — já vem ligada por padrão. Confirme com:

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 a chave de criptografia (uma única 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 um device

(O PR de follow-up entrega a UI admin. Por enquanto, devices são registrados via endpoint de API ou diretamente no banco.)

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"
  }'

Testar a conexão

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 um 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 em background

Uma vez habilitado, o worker de polling do dashboard itera pelos devices registrados no poll_interval_seconds configurado, executa todos os métodos collect* suportados e grava snapshots. A implementação do polling worker entra no PR-B (follow-up).

Vinculando snapshots a uma execução

Quando uma execução de Test Plan inicia, a engine dispara um snapshot imediato de cada device registrado com test_run_execution_id preenchido. Esse snapshot vira o "estado do DUT no início" da execução. No fim da execução, outro snapshot estabelece o "estado do DUT no fim". Ambos são referenciados no Test Run Report.

Modelo de segurança

O que a integração FAZ

  • Armazena credenciais do DUT criptografadas at rest (AES-256-GCM)
  • Usa HTTPS para cada chamada ao device
  • Suporta cert-pinning para devices self-signed
  • Loga cada snapshot em tabela append-only com SHA-256
  • Audit-log de cada registro de device / mudança de credencial

O que a integração NÃO faz

  • NÃO escreve no device por padrão — apenas métodos de adapter read-only. Métodos de escrita futuros (ex. configurar servidor NTP via API) serão fluxos explícitos com confirmação do operador e auditoria separada
  • NÃO faz cache de credenciais em texto plano além da duração de uma chamada de API
  • NÃO suporta fluxo OAuth client_credentials no FTD (só password grant) — se sua política de segurança exige client_credentials, abra uma issue

Threat model

Ameaça Mitigação
Vazamento do banco expõe credenciais AES-256-GCM com chave em K8s Secret — atacante precisa também obter DUT_CRED_ENC_KEY
MITM no caminho adapter↔device Verificação TLS (strict default); modo insecure exige opt-in explícito do operador e fica registrado em tls_verify_mode
Pod do dashboard comprometido abusa do acesso à API Adapter é read-only por padrão; métodos de escrita futuros exigirão re-auth admin nova
Replay de respostas antigas da API payload_sha256 + timestamp collected_at; mismatch detectável por quem tiver tanto o snapshot quanto um fetch contemporâneo do device
Erro de digitação do operador registra device errado Botão "Test connection" valida auth + reachability antes de salvar

Considerações de performance + rate-limit

Intervalo de poll padrão é 5 minutos por device. Observação empírica:

  • Cisco FTD: coletar todos os 7 endpoints de leitura leva ~3-8 segundos no total (token em cache, chamadas sequenciais)
  • Cisco Nexus 9000: coletar todos os 6 endpoints leva ~2-5 segundos (cookie em cache)
  • Nenhum dos fabricantes documenta números de rate-limit; ambos parecem aguentar 1 chamada/segundo confortavelmente em leituras

Se você estiver rodando múltiplos devices, o loop de poll do worker é sequencial por device (não paralelo) para ser educado. Tempo total de ciclo = soma das durações por device.

Trabalho futuro — operações de escrita

Uma vez estável a fundação de leitura, métodos de escrita se tornam possíveis:

  • Configurar servidor NTP no Cisco FTD: PUT /api/fdm/v6/devicesettings/default/ntp/{objId} (objeto completo) + POST /api/fdm/v6/operational/deploy para commit
  • Resetar contadores de interface no Cisco Nexus: POST MO com action clear
  • Alternar estado da política de decrypt para testes A/B durante uma execução
  • Aplicar política QoS específica do test-bed no Nexus pré-execução, reverter pós-execução

Cada escrita exigirá: 1. Re-auth admin no momento do request 2. Confirmação explícita do operador na UI ("prestes a mudar fonte NTP do NGFW — prosseguir?") 3. Entrada de audit log com snapshots before/after 4. Rollback automático se a leitura pós-escrita confirmar divergência da intenção

Fora do escopo deste PR; rastreado como PR-C no roadmap de integração de API.

What ships in this PR

Este PR é a fundação: - Tabelas do banco + schema Drizzle - Helpers de criptografia de credenciais AES-256-GCM - Interface de adapter + catálogo ENDPOINT_LABELS - Adapter Cisco FTD funcional com 7 endpoints de leitura - Adapter Cisco Nexus funcional com 6 endpoints de leitura (cobre descoberta LLDP/CDP) - Esta documentação

What ships in PR-B (follow-up): - UI admin para registrar devices - Polling worker (Kubernetes CronJob OU Next.js server interval) - Endpoints de API /api/admin/dut/devices/* + /api/admin/dut/snapshots/* - Dashboard Grafana "TLSStress.Art — DUT Live State" - Integração na execução do Test Plan (snapshot no início + fim da execução)

What ships in PR-C (futuro): - Adapters Palo Alto + Fortinet - Test Run Report Phase 3 Annex B/C ligado a esses snapshots - Operações de escrita (set NTP, toggle decrypt-policy) com fluxo de confirmação do operador

Relacionados

Referências