Skip to content

TLSStress.Art — Desenho de Alto Nível do Sistema (HLD)

Público-alvo: arquitetos, operadores, revisores de segurança e investidores que precisam da visão do sistema inteiro em um único documento. Este HLD fica acima da visão geral de Arquitetura (tour de componentes) e dos Registros de Decisão de Arquitetura (racional por decisão). Onde este documento resume, aqueles documentos são autoritativos no detalhe.

Aprofundamentos companheiros: F2 — arquitetura do Cell-0 (Hetzner), postura de segurança ZTP-prem, ADR-0053 (hyperscale por cells).


1. Propósito & escopo

TLSStress.Art é um test-bed para medir performance de decriptografia TLS em Next-Generation Firewalls (NGFWs) atuando como Device Under Test (DUT). O alvo primário é HTTP/3 (QUIC sobre UDP/443) — todo NGFW moderno reivindica inspeção QUIC — com HTTP/2 (TCP/443) medido secundariamente para comparação.

O produto tem duas faces:

Face O que é Onde roda
Plano de controle SaaS Signup, billing, ledger de tokens (TSU), auto-provisionamento, enrollment central AWS (App Runner + RDS) · Cloudflare (borda/DNS) · cell-0 Hetzner (K3s)
Appliance on-prem (TBI) A bancada em si — agentes, personas, dashboard, observabilidade — instalada ao lado do NGFW do cliente Datacenter/lab do cliente (K3s/RKE2 ou Docker Desktop dev)

A bancada gera carga a partir de agentes (Playwright + k6) através do NGFW, que decripta/inspeciona/re-assina TLS, e segue até os webservers (as Personas). Comparando o tempo de handshake e o throughput com decriptografia ON vs BYPASS, o operador quantifica o custo de inspeção TLS do NGFW.


2. Contexto do sistema — atores

Ator Papel Ponto de contato
Cliente Compra um pacote no SaaS, recebe um tenant provisionado + um appliance on-prem (TBI) para download app.tlsstress.art (signup/pagamento), download do TBI (S3/F1)
Operador Roda a bancada contra um NGFW real. O Dashboard é a ÚNICA interface do operador — toda mudança de config passa pela UI (nunca kubectl edit / curl admin/ / exec) Dashboard on-prem (Next.js)
NGFW DUT O dispositivo sob medição. Gateway L3 padrão das VLANs de test-plane; executa a decriptografia TLS Firewall físico/virtual em trunks 802.1q
flowchart LR
    CUST(["Cliente"])
    OPER(["Operador"])

    subgraph SAAS["Plano de controle SaaS (sempre-online)"]
        APP["customer-app<br/>App Runner · Next.js<br/>signup · Stripe · mint TSU"]
        CELL["cell-0 (Hetzner K3s)<br/>Provisioning Orchestrator<br/>saga Temporal · RLS de tenant"]
        TBI[("Artefatos TBI<br/>S3 · img/qcow2/oci")]
    end

    subgraph PREM["Appliance on-prem (datacenter do cliente)"]
        DASH["Dashboard (Next.js)<br/>a ÚNICA UI do operador"]
        AGENTS["Agentes<br/>Playwright + k6"]
        PERS["Personas<br/>100 webservers (Caddy)"]
        OBS["Observabilidade<br/>Prometheus + Grafana"]
    end

    DUT{{"NGFW DUT<br/>decripta · inspeciona · re-assina TLS"}}

    CUST -->|"signup / pagamento"| APP
    APP -->|"applyTier (mint de quota)"| APP
    APP -->|"enqueueOnboarding (HMAC)"| CELL
    CUST -->|"download do appliance"| TBI
    TBI -.->|"dd para USB / KVM / boot"| PREM

    OPER -->|"login · configurar"| DASH
    DASH --> AGENTS
    DASH --> PERS
    DASH --> OBS
    AGENTS ==>|"leg TLS 1"| DUT
    DUT ==>|"leg TLS 2"| PERS
    AGENTS -.->|"eventos de spend TSU"| DASH
    DASH -.->|"reporte de uso (horário)"| APP

    classDef saas fill:#0F1A2E,stroke:#00D8FC,color:#FCFCFC,stroke-width:2px
    classDef prem fill:#f0fdf4,stroke:#16a34a,stroke-width:1px
    classDef dut  fill:#fef9c3,stroke:#b45309,stroke-width:2px
    class APP,CELL,TBI saas
    class DASH,AGENTS,PERS,OBS prem
    class DUT dut

3. Visão de containers (C4-ish)

O próximo nível aproxima dos containers implantáveis e seus protocolos. O plano de controle fica on-prem (Dashboard ↔ agentes pela bridge OOBI) enquanto o plano de controle de billing/provisionamento vive na cloud (customer-app ↔ cell-0). O único canal on-prem→cloud é o reporte horário de uso TSU.

graph TB
  CUST(["Cliente<br/>navegador"])
  OPER(["Operador<br/>navegador"])

  subgraph CLOUD["Plano de controle SaaS na cloud"]
    direction TB
    APP["customer-app<br/>(App Runner, Next.js)"]
    RDS[("RDS · ledger UTXO<br/>mint @ checkout")]
    STRIPE{{"Stripe"}}
    PROV["Provisioning Orchestrator<br/>(cell-0, Go + Temporal)"]
    CELLDB[("Cell control DB<br/>tenants · slots (RLS)")]
  end

  subgraph ONPREM["Appliance on-prem"]
    direction TB
    DASH["Dashboard<br/>(Next.js · Drizzle)<br/>gate license authorize()"]
    PG[("Postgres 16<br/>runs · agents · audit_log<br/>notas UTXO · idempotency")]
    PWA["Agentes Playwright<br/>(1..80, HPA)"]
    K6A["Agentes k6<br/>(1..200, HPA)"]
    PERS["Personas (Caddy)<br/>100 / 20 países"]
    VYOS["MÓDULO ISP/BGP<br/>(VyOS + FRR)"]
    PROM["Prometheus + Grafana"]
    BOOT["bootstrap-controller<br/>(drain de spend TSU)"]
  end

  DUT{{"NGFW DUT"}}

  CUST -->|"HTTPS"| APP
  STRIPE -->|"checkout.session.completed"| APP
  APP -->|"applyTier mint"| RDS
  APP -->|"HMAC POST /trigger"| PROV
  PROV -->|"saga"| CELLDB

  OPER -->|"cookie HMAC / Basic"| DASH
  DASH -->|"SQL"| PG
  DASH <-->|"Bearer + Idempotency-Key"| PWA
  DASH <-->|"Bearer"| K6A
  DASH -->|"spend de nota de licença"| PG
  PWA ==>|"leg TLS 1 · h2/h3"| DUT
  K6A ==>|"leg TLS 1 · h2/h3"| DUT
  DUT ==>|"leg TLS 2 (re-assinado)"| VYOS --> PERS
  PROM -->|"scrape /api/metrics · SNMP"| DASH
  BOOT -.->|"POST horário /api/usage/report"| APP

  classDef cloud fill:#0F1A2E,stroke:#00D8FC,color:#FCFCFC,stroke-width:2px
  classDef prem  fill:#f0fdf4,stroke:#16a34a,stroke-width:1px
  classDef dut   fill:#fef9c3,stroke:#b45309,stroke-width:2px
  class APP,RDS,STRIPE,PROV,CELLDB cloud
  class DASH,PG,PWA,K6A,PERS,VYOS,PROM,BOOT prem
  class DUT dut

4. Componentes principais & responsabilidades

4.1 Appliance on-prem (a bancada)

Componente Código Responsabilidade
Dashboard dashboard/ Next.js 15 App Router. A única UI do operador. Auth por cookie HMAC, audit_log de toda mutação, stream SSE ao vivo, /api/metrics Prometheus, o gate license authorize() (dashboard/src/lib/license/).
Agentes Playwright agent/ Workers Chromium headless. BrowserContext novo por ciclo, captura protocolo / tcp_sockets_open / web-vitals. Circuit breaker por alvo, idempotency keys. HPA min=1, max=80.
Agentes k6 k6-agent/ Wrapper Node.js do binário grafana/k6. Emite p50/p95/p99, error_rate, rps, data_received. readOnlyRootFilesystem, /tmp em memória. HPA min=1, max=200.
Personas personas/, webserver/ 100 webservers Caddy em 20 países (5 cada). H2 + H3, TLS 1.2 mín, session tickets desabilitados. Certs emitidos pelo persona-ca-issuer. Os endpoints do leg TLS 2.
MÓDULO ISP / BGP bgp-router-peer/, ospf-router-peer/, vpn-remote/ VyOS + FRR. Rota padrão do NGFW; roteia adiante para cada /24 de país. Também stress de control-plane (injeção de LSA BGP/OSPF).
Postgres 16 k8s/40-postgres.yaml runs, agents, k6_*, metrics_buckets, audit_log, idempotency, notas UTXO, envelopes de licença. CronJob diário de pg_dump.
Observabilidade observability/, grafana/ Prometheus + Grafana, SNMP exporter para NGFW/Nexus, node_exporter. Dashboards DUT (NGFW, Nexus, probe de decrypt-mode).
DUT API engine dashboard/src/lib/dut-api/ Adapters de vendor (Cisco FTD/Nexus/UCS-CIMC, FortiGate). Captura config + identidade sanitizadas, AES-GCM em repouso, hashes SHA-256 de snapshot embarcados no Test Run Report.
bootstrap-controller pkg/bootstrap-controller/ Drena arquivos de spend TSU e faz POST para o /api/usage/report da cloud, de hora em hora.

4.2 Plano de controle SaaS na cloud

Componente Código Responsabilidade
customer-app pkg/octopus/customer-app/ Next.js no AWS App Runner. Signup, checkout Stripe, minta a quota TSU no ledger UTXO do RDS no checkout (applyTier), e (fail-safe) enfileira o onboarding ao cell-0.
Provisioning Orchestrator pkg/octopus/provisioning-orchestrator/ Worker Go + Temporal no cell-0. Roda o OnboardingWorkflow — saga de 12 atividades com compensação LIFO. Ver F2 HLD.
Cell control DB internal/cell/migrations/ Database Postgres cell: tenants, slots, tenant_data com RLS Postgres para isolamento por tenant (ADR-0053).
Admin console pkg/octopus/admin-console/ Console interno de operador/billing (separado do Dashboard on-prem).
TBI builder build/tbi/, pkg/tbi-agent/ Constrói a imagem do appliance on-prem (mkosi → img/qcow2/oci). Embarca tbi-agent, k3s, gVisor, probes de hardware.

5. Os dois legs TLS

O produto inteiro existe para medir o custo da decriptografia entre dois legs TLS.

flowchart TB
    A["Pod de agente<br/>(Playwright / k6)<br/>VLAN 20 / 30 — TRUST/INSIDE"]
    DUT{{"NGFW DUT<br/>decripta · inspeciona · re-assina TLS"}}
    VYOS["MÓDULO ISP (VyOS + FRR)<br/>VLAN 2001 — UNTRUST/OUTSIDE<br/>rota padrão 200.130.0.2"]
    PERS["Pod Persona Caddy<br/>ex.: shop.us.persona.tlsstress.art<br/>= 198.32.10.10 · H2 + H3"]

    A ==>|"leg TLS 1<br/>agente confia na CA do NGFW"| DUT
    DUT ==>|"leg TLS 2<br/>NGFW confia no persona-ca-issuer"| VYOS
    VYOS -->|"uma saída por LAN de país"| PERS

    note1["Confiança leg 1: agentes carregam NODE_EXTRA_CA_CERTS /<br/>SSL_CERT_FILE = CA do NGFW (ConfigMap 10-ngfw-ca)"]
    note2["Confiança leg 2: NGFW confia no cert-manager<br/>persona-ca-issuer (platform/pki/)"]
    note1 -.-> DUT
    note2 -.-> VYOS

    classDef agent fill:#dbeafe,stroke:#2563eb,stroke-width:1px
    classDef dut   fill:#fef9c3,stroke:#b45309,stroke-width:2px
    classDef rtr   fill:#fff7ed,stroke:#c2410c,stroke-width:1px
    classDef pers  fill:#f0fdf4,stroke:#16a34a,stroke-width:1px
    classDef noted fill:#f5f5f7,stroke:#999,stroke-width:1px,color:#333
    class A agent
    class DUT dut
    class VYOS rtr
    class PERS pers
    class note1,note2 noted
Leg De → Para Âncora de confiança Notas
Leg 1 Agentes → NGFW Agentes confiam na CA do NGFW (k8s/dut/10-ngfw-ca.yaml, injetada via NODE_EXTRA_CA_CERTS / SSL_CERT_FILE) O NGFW intercepta e re-assina com sua própria CA. Os agentes precisam aceitá-la para medir o caminho inspecionado.
Leg 2 NGFW → Personas NGFW confia no persona-ca-issuer (PKI cert-manager, platform/pki/) Personas apresentam certs com IP SANs (IP público real) + DNS <persona>.<country>.persona.tlsstress.art.

O NGFW só vê o único edge link (VLAN 2001); o pod VyOS-ISP roteia adiante para cada /24 de país. O inventário de interfaces do NGFW é, portanto, 8 interfaces (3 INSIDE + 4 OUTSIDE + 1 MGMT), não uma por persona.


6. Planos de dados — eth0 / net1 / VLANs

Cada pod é dual-homed. O eth0 carrega controle + observabilidade e nunca sai do host (bridge OOBI); o net1 é uma macvlan que bypassa iptables/NetworkPolicy e carrega o tráfego de teste de fato para o trunk VLAN. Essa separação é o que permite à bancada dirigir tráfego em line-rate por um NGFW físico mantendo a orquestração em um canal de controle limpo.

flowchart TB
    subgraph POD["Cada pod de plano de dados"]
        ETH0(["eth0<br/>net padrão K8s"])
        NET1(["net1<br/>macvlan (Multus)"])
    end

    subgraph CTRL["Plano de controle + observabilidade (eth0)"]
        DASH["Dashboard :3000"]
        PG["Postgres :5432"]
        PROM["Prometheus :9090"]
    end

    subgraph DATA["Plano de dados (net1 → trunk 802.1q)"]
        V20["VLAN 20 · 172.16.0.0/16<br/>Agentes Playwright (TRUST)"]
        V30["VLAN 30 · 172.17.0.0/16<br/>Agentes k6 (TRUST)"]
        V99["VLAN 99 · 10.254.254.0/24<br/>OOBI / SNMP mgmt"]
        V40["VLAN 40 · DHCP<br/>Cloner ISP (SEM NGFW)"]
        VCO["VLANs 101-120<br/>Personas — 1 VLAN/país<br/>/24 público real"]
    end

    DUT{{"NGFW DUT"}}
    NET2["VyOS-ISP → LANs de país"]
    INET(["Internet pública"])

    ETH0 --> CTRL
    NET1 --> V20 --> DUT
    NET1 --> V30 --> DUT
    NET1 --> V99
    NET1 --> V40 --> INET
    DUT --> NET2 --> VCO

    classDef ctrl fill:#fce7f3,stroke:#db2777,stroke-width:1px
    classDef data fill:#dbeafe,stroke:#2563eb,stroke-width:1px
    classDef dut  fill:#fef9c3,stroke:#b45309,stroke-width:2px
    classDef ext  fill:#f5f5f7,stroke:#000,stroke-width:1px
    class DASH,PG,PROM ctrl
    class V20,V30,V99,V40,VCO data
    class DUT dut
    class INET,NET2 ext
Plano Interface Segmento(s) Propósito
Controle / mgmt eth0 net padrão K8s API do Dashboard, heartbeat, scrape Prometheus — nunca sai do host
Dados — Playwright net1 VLAN 20 172.16.0.0/16 Carga browser-driven através do NGFW
Dados — k6 net1 VLAN 30 172.17.0.0/16 Carga TLS/HTTP sintética através do NGFW
SNMP / OOBI net1 VLAN 99 10.254.254.0/24 (VXLAN VNI 254254) Polling SNMP + fabric de orquestração OOBI
Personas net1 VLANs 101-120 — uma VLAN por país, /24 público real Endpoints do leg TLS 2 (atrás do VyOS-ISP)
Cloner ISP net1 VLAN 40 (DHCP) Saída direta para a internet do cloner de sites — bypassa o NGFW

Schema v4.3 / ADR-0007 (Realismo de Internet Pública): personas carregam apenas country em personas.yaml; o id da VLAN, o prefixo /24 público e o gateway são derivados via lookup contra platform/network/public-ip-pool.yaml. Endereçamento RFC1918 de persona (10.1.x.0/27) foi o estado v4.2 stale e não deve ser usado.


7. O substrato de cell (ADR-0053)

O lado SaaS é construído cell-based desde o Wave-0 para escalar de dezenas a centenas de milhares de clientes sem migração pause-the-world.

Conceito Definição
Cell Unidade de isolamento de até 10 000 clientes com seu próprio stack OCTOPUS. Crash de uma cell nunca afeta outras. cell_id = <region>-<n> (ex.: hel1-0).
Sharding key deployment_id (ULID / dpl_*) — a unidade de tráfego, que é o que satura.
Plano de controle Serviços globais de todas as cells: Admin Console, Provisioning Orchestrator, token marketplace, PKI root, audit chain.
Plano de dados Tráfego de cliente por-cell, cell-isolado (rendezvous CONNECT.Art + signaling STUN-coord).

Wave-1 (live hoje) é uma única cell — hel1-0 em um VPS Hetzner — mas todo schema já é cell-ready (coluna cell_id em toda primary key), então waves posteriores são incrementais, nunca um rewrite. O isolamento por tenant usa RLS Postgres em schema compartilhado (escala a 10k tenants/cell sem 10k schemas): a tabela tenant_data tem ENABLE/FORCE ROW LEVEL SECURITY com policy USING (deployment_id = current_setting('octopus.tenant')). O plano de controle roda privilegiado; o plano de dados conecta com o role tenant_dataplane (NOSUPERUSER NOBYPASSRLS), então leituras cross-tenant retornam zero linhas.

Um slot (connect-art / stun-coord) é uma entrada de admissão, não um recurso de runtime escasso: os serviços de plano de dados leem slots para admitir/rejeitar um deployment_id. Ver F2 HLD §4.6 e ADR-0053.

flowchart LR
    subgraph CP["Plano de controle (global)"]
        ADMIN["Admin Console"]
        ORCH["Provisioning Orchestrator"]
        PKI["PKI root / audit chain"]
    end
    subgraph CELL["Cell hel1-0 (Wave-1)"]
        direction TB
        CA["CONNECT.Art"]
        SC["STUN-coord"]
        DB[("tenants · slots · tenant_data<br/>(RLS, schema compartilhado)")]
    end
    ORCH -->|"AllocateCell · ProvisionTenant · ReserveSlot"| DB
    CA -->|"lê slots → admite"| DB
    SC -->|"lê slots → admite"| DB
    ADMIN -.-> ORCH

    classDef cp   fill:#0F1A2E,stroke:#00D8FC,color:#FCFCFC,stroke-width:2px
    classDef cell fill:#f0fdf4,stroke:#16a34a,stroke-width:1px
    class ADMIN,ORCH,PKI cp
    class CA,SC,DB cell

8. A economia de tokens (TSU)

O billing é medido em TSU (TLSStress Units). O fluxo é deliberadamente dividido para que o saldo autoritativo viva na cloud enquanto o spend se origina on-prem.

sequenceDiagram
    autonumber
    participant C as Cliente
    participant APP as customer-app (AWS)
    participant RDS as ledger UTXO RDS
    participant DASH as Dashboard on-prem
    participant GATE as gate license authorize()
    participant PG as Postgres on-prem (notas UTXO)
    participant BOOT as bootstrap-controller
    participant USAGE as /api/usage/report (cloud)

    C->>APP: checkout (Stripe)
    APP->>RDS: applyTier — MINT de quota (autoritativo)
    Note over DASH,GATE: toda execução de test plan passa pelo gate
    DASH->>GATE: authorize(testPlanId, estimatedTokens, features)
    GATE->>PG: spendNotes() — queima seriais de nota UTXO
    GATE->>PG: sealedAppend() — registro de auditoria WORM
    GATE-->>DASH: recibo {sealedHash, burnedSerials, balanceAfter}
    DASH->>DASH: run executa — agentes emitem Tick(TSU) por run finalizado
    BOOT->>BOOT: drena /var/lib/tlsstress/spend/*.jsonl (horário)
    BOOT->>USAGE: POST eventos de uso (client_seq estável → dedup)

Propriedades-chave (fiéis a pkg/metering/README.md, dashboard/src/lib/license/):

  • Mint autoritativo no checkout — o customer-app minta a quota no ledger UTXO do RDS (tokens são notas tamper-evident, não um saldo mutável; Patent #19, sem coluna balance, sem race de update).
  • Spend on-prem — cada módulo emite um Tick(TSU) por unidade de trabalho finalizada em /var/lib/tlsstress/spend/<module>.jsonl. Um meter quebrado não pode derrubar o módulo (faz fallback para stderr).
  • Gate de licença como chokepointauthorize() em dashboard/src/lib/license/gate.ts é o único chokepoint pelo qual todo test run passa: gasta notas UTXO, faz append no audit hash-chain selado e retorna um recibo assinado. Wave-1 é always-allow (envelope de desenvolvedor); o enforcement (verificação de assinatura, gating de features, caps de concorrência, expiry+grace) liga sob a mesma assinatura no v5.3+.
  • Reconciliação horária — o bootstrap-controller drena os arquivos de spend e faz POST para o /api/usage/report da cloud; a idempotência é trabalho do controller (client_seq estável por evento → cloud rejeita duplicata no retry).

9. Postura de segurança (alto nível)

A postura completa de Zero-Trust-on-Premises (ZTP-prem) de 12 camadas — que defende a bancada contra um operador insider com kubectl + root dentro da própria org do cliente — está em SECURITY_ZTP_PREM.md. Esta seção é a baseline operacional que se aplica independentemente do estado de layer-flip do ZTP-prem.

Camada Controle
Containers Non-root, capabilities Linux dropadas, seccomp RuntimeDefault, root filesystem read-only onde possível.
Rede NetworkPolicy de egress default-deny; RFC1918 + link-local bloqueados da frota de agentes. Personas atrás do VyOS-ISP; movimento lateral OOBI bloqueado (só a VIP do Infra Stack 10.254.254.100 pode iniciar para IPs OOBI de MÓDULO).
Auth Cookie HttpOnly assinado por HMAC no Dashboard (compare em tempo constante, rate limit por IP); Authorization: Basic legado para callers programáticos. O trigger da cloud é HMAC-SHA256 com verify em tempo constante.
Supply chain gitleaks + trivy por PR, CodeQL semanal; imagens assinadas Cosign-keyless via GitHub OIDC; SBOM SPDX anexado por release tag.
Gate de pre-flight Catálogo de 5 checks antes de cada run (conflito de subnet, alcance NGFW + decrypt mode, frescor da PKI de persona, skew NTP, auth da DUT API). Bypass é logado no audit_log + impresso na capa do report.
Dados em repouso Credenciais da DUT API cifradas com AES-GCM; snapshots sanitizados com hash SHA-256 no Test Run Report (Anexo B/C/D).
Isolamento de tenant (cloud) RLS Postgres com o role tenant_dataplane (NOBYPASSRLS); leitura cross-tenant = 0 linhas (provado live).
Auditabilidade audit_log registra toda mutação de config (ator, IP de origem, JSON before/after); audit hash-chain selado do ZTP-prem (WORM) registra toda decisão de licença/admission/egress.

10. Topologia de deployment (ADR-0011)

A topologia é configurada via platform/topology.yaml em três eixos independentes, então um lab single-node e um fabric multi-node de prod compartilham uma única base de código.

Eixo Valores Controla
deployment_nodes single · dual · tri · multi Número de hosts UCS + distribuição de roles
l2_fabric nexus · none Switch L2 externo (ou sua ausência)
dut_type cisco-ftd · cisco-secure-router Vendor do DUT — gateia scripts de apply/verify

Single-node sem switch externo é first-class (l2_fabric: none): NICs do UCS cabeadas direto no NGFW, tuning Nexus pulado, mas a atestação BPDU de Linux-bridge continua rodando. O plano OOBI (eth0) é mandatório em todo host em todo modo. Overlays Kustomize (overlays/dual-node|tri-node|multi-node/) pinam cada tier de workload ao seu host dedicado via patches de nodeSelector.


11. Referências cruzadas

Tópico Documento
Tour de componentes, diagramas de sequência, topologia DUT docs/ARCHITECTURE.md
Aprofundamento F2 auto-provisionamento + cell-0 docs/F2_HETZNER_CELL0_ARCHITECTURE.md
Segurança ZTP-prem de 12 camadas docs/SECURITY_ZTP_PREM.md
Racional de hyperscale por cells ADR-0053
Índice de registros de decisão ADR/README.md
Convenções & regras do projeto CLAUDE.md