O livro está disponível em inglês. Este site apresenta o conteúdo em português para facilitar a compreensão. Versão em inglês em thebackendofluck.com open_in_new
Decisão de Arquitetura · 2026-04-12

Console Móvel do Operador

Um app móvel para SREs e equipes de compliance de iGaming — construído sobre Cloudflare Access, OpenBao SSH CA e YubiKey 5 NFC. Zero licenças do Teleport, zero novos serviços de caminho crítico, e trilha de auditoria GLI-33 / SIGAP / LGPD que chega ao Wazuh.

3
Camadas de auth
15min
TTL do cert SSH
R$ 0
Custo de licença
~10d
Até primeiro release

O Problema

Plantão às 03:00 a partir de um celular é a realidade de todo SRE de iGaming. O dashboard ajuda. Mas quando um PSP começa a devolver 502 no meio de um torneio, ou o geofence bloqueia um IP de navio de cruzeiro, o operador precisa de um shell de verdade — não de uma página de status. SSH de um notebook num posto de gasolina com a YubiKey dependurada no chaveiro não é um fluxo de trabalho: é uma vulnerabilidade.

Ao mesmo tempo, o regulador não tem paciência para romantismo operacional. SIGAP (Brasil), GLI-33, MGA Class 4, UKGC LCCP e LGPD fazem as mesmas três perguntas: quem autenticou, com qual fator, e o que fez? Um console móvel que não consiga responder isso num log forense é passivo regulatório, não ativo.

A resposta ingênua é comprar Teleport e seguir em frente. Essa resposta está errada na nossa escala (1–5 operadores, ≤ 3 hosts SSH) porque introduz uma nova dependência de caminho crítico, uma nova licença por usuário e duplica recursos que já rodam. A arquitetura desta página é o caminho que escolhemos.

O App em Cinco Telas

Construído com Expo (React Native) — o mesmo código TypeScript roda em iOS e Android. Telas capturadas no iPhone 17 (simulador iOS 26). Cada aba consome dados ao vivo de /api/v2/dash/* em new.acmetocasino.com atrás do Cloudflare Access; ações SSH passam pelo fluxo de CA SSH do OpenBao descrito abaixo. Os hostnames na aba Terminal foram redigidos.

Aba de visão geral SRE — saúde do ambiente, incidentes abertos, infraestrutura, serviços
Visão Geral — resumo SRE focado no ambiente; o badge conta P0/P1 abertos.
Aba de incidentes — filtros por severidade e badges de SLA estourado
Incidentes — feed ao vivo de /incidents/list com filtros e contagem de SLA.
Aba de infra — anéis de CPU/memória/disco, pool do banco, Redis, Kafka, grade de serviços
Infra — CPU real via delta de /proc/stat, barra do pool do banco, Redis e Kafka.
Aba de compliance — auditorias de viés de IA, registro de autoexclusão, LGPD
Compliance — auditorias de viés de IA, autoexclusão e fila de DSR LGPD.
Aba de terminal — detalhes da conexão SSH via Cloudflare Access e comandos recentes
Terminal — estado do túnel Cloudflare Access, comandos SSH copiáveis, certificado OpenBao de 15min.

Matriz de Decisão: Cloudflare Access vs Teleport

Dez critérios ponderados, pontuados de 1 (ruim) a 5 (excelente), contra os cinco caminhos viáveis: Teleport (spec original), Cloudflare Access + OpenBao SSH CA (vencedor), OpenBao + VPN, Tailscale, e "web móvel responsivo apenas".

Critério Peso Teleport CF + OpenBao OpenBao + VPN Tailscale Só web móvel
Postura de segurança (FIDO2 + mTLS + curta duração)555433
Complexidade operacional (serviços a manter)424445
Aderência regulatória (GLI-33, MGA, SIGAP)554434
Encaixe no time (1–5 operadores)425555
Lock-in de fornecedor323535
Custo (licença + infra + esforço)425545
UX móvel (terminal, push, biometria)454343
Tempo até o primeiro release425445
Alinha com capítulos 20, 20b, 24h235523
Exposição a SPOF / lock-out423534
Total ponderado140176167131159

A opção B vence no total e em todos os critérios de "serviços a manter" e "tempo até release" — os que realmente importam em time pequeno.

Arquitetura

Tudo no diagrama a seguir já está (a) rodando hoje, ou (b) é uma pequena adição a algo que já existe. Nenhum novo serviço de control-plane é introduzido.

phone_iphone
Camada 1

Cliente Móvel · iOS 16+ / Android 13+

smartphoneReact Native + Expo

Terminal XTerm.js embarcado em WebView endurecida.

securitySecure Enclave / StrongBox

Passkey atrelada ao device; chaves privadas nunca saem do elemento seguro.

contactlessYubiKey 5 NFC

Autenticador roaming FIDO2 via toque NFC para step-up resistente a phishing.

cloud
Camada 2

Cloudflare Edge · porteira Zero Trust

shieldWAF → Cloudflare Access

Motor de política à frente de cada origem. Deny-by-default.

verified_userIdentidade & postura
  • → OIDC via Google Workspace SSO
  • → Política de chave hardware FIDO2 (YubiKey obrigatório)
  • → Postura de device (versão do SO + cert mTLS)
apiRota de API

api.example.com → Cloudflare Worker → origem PROD

vpn_lockRota de SSH

ssh.example.com → Cloudflare Tunnel → LAN

dns
Camada 3

LAN Local · VLAN de Ops

key_verticalOpenBao
  • • SSH CA (certs curtos de 15min)
  • • Role PKI mobile
  • • Selado em HSM em repouso
memoryYubiHSM 2

PKCS#11 · assinatura raiz · seal wrap

terminalsshd no host de ops

TrustedUserCAKeys valida certs assinados pelo OpenBao. Bastião de prod na VLAN de Ops.

monitor_heartWazuh SIEM

auth.log + sessão sshd + auditd · Cloudflare Logpush (eventos Access).

Fluxo de Auth em 3 Camadas

O spec original listava cinco camadas. Três bastam para cobrir OWASP MASVS-AUTH-1/2 e GLI-33, e cada camada defende de um modelo de ameaça distinto.

fingerprint

1 · Passkey

Passkey destravada por biometria, atrelada ao Secure Enclave / StrongBox via expo-passkeys. Protege contra celular roubado + bloqueio fraco. Nunca sai do TEE.

key

2 · YubiKey + CF Access

O Cloudflare Access impõe política de chave de hardware FIDO2. Toque NFC da YubiKey 5 NFC gera a assertion; Google Workspace SSO traz a identidade. Resultado: JWT CF_Authorization de 8h.

verified_user

3 · Certificado OpenBao

Para operações privilegiadas (SSH, drain, aprovar saque) o JWT é trocado no OpenBao por um certificado SSH de 15 minutos assinado pelo SSH CA. Cada sshd confia só nesse CA — sem authorized_keys por usuário.

Token da API Cloudflare — Escopos Exatos

Crie um único token de API, usado tanto pelo Worker do backend móvel quanto pelo pipeline de deploy. Cinco permissões, nada além:

EscopoPor quê
Account.Access: Apps and Policies — EditCriar / atualizar aplicações Access para os hostnames api e ssh.
Account.Cloudflare Tunnel — EditCriar e rotacionar credenciais do tunnel para o cloudflared no host de ops.
Zone.DNS — EditGerenciar os CNAMEs que apontam para o hostname do tunnel.
Zone.Zone — ReadBuscar o zone id em tempo de deploy.
Account.Workers Scripts — EditFazer deploy do Worker gateway da API móvel.
Nunca conceda escrita global de conta. O token acima não consegue deletar zonas, não altera billing, e não toca em R2 nem D1. Se vazar, o raio da explosão fica confinado ao stack móvel.

Implementação em 5 Trechos

Cinco snippets que sustentam o design. Todos os tokens, IDs e hostnames são placeholders: substitua pelos seus antes de rodar.

Bootstrap do OpenBao SSH CA

# No host OpenBao — habilita o secrets engine SSH e gera a chave de assinatura export VAULT_ADDR="https://openbao.internal:8200" export VAULT_TOKEN="<OPENBAO_ROOT_TOKEN>" bao secrets enable -path=ssh-client ssh bao write ssh-client/config/ca generate_signing_key=true # Role: certs de 15 min, usuário root@ops, key_type ed25519 bao write ssh-client/roles/mobile-admin \ algorithm_signer=default \ allow_user_certificates=true \ allowed_users="root,ops" \ default_user="ops" \ ttl="15m" max_ttl="15m" \ key_type=ca key_bits=0 \ allowed_extensions="permit-pty,permit-agent-forwarding" # Publica a chave pública do CA — copiar para cada host com sshd bao read -field=public_key ssh-client/config/ca > /etc/ssh/ca.pub

Configuração do sshd nos alvos

# /etc/ssh/sshd_config.d/10-openbao-ca.conf TrustedUserCAKeys /etc/ssh/ca.pub AuthorizedPrincipalsFile /etc/ssh/auth_principals/%u PasswordAuthentication no PubkeyAuthentication yes # /etc/ssh/auth_principals/ops # (um principal por linha — casa com "valid_principals" do cert) mobile-admin

Aplicação Cloudflare Access (Terraform)

resource "cloudflare_access_application" "ssh" { account_id = "<CF_ACCOUNT_ID>" name = "ops-ssh" domain = "ssh.acmetocasino.com" type = "ssh" session_duration = "8h" } resource "cloudflare_access_policy" "ssh_hwk" { account_id = "<CF_ACCOUNT_ID>" application_id = cloudflare_access_application.ssh.id name = "hwk-only" decision = "allow" precedence = 1 include { email_domain = ["example.com"] } require { auth_method = "hwk" # hardware key device_posture = ["posture-os-version"] } }

cloudflared no host de ops

# /etc/cloudflared/config.yml tunnel: <TUNNEL_UUID> credentials-file: /etc/cloudflared/<TUNNEL_UUID>.json ingress: - hostname: ssh.acmetocasino.com service: ssh://127.0.0.1:22 - hostname: api.acmetocasino.com service: http://127.0.0.1:8000 - service: http_status:404 # Unidade systemd roda com usuário cloudflared; só no host da LAN.

Cliente móvel — troca JWT por cert SSH

// src/lib/openbao.ts — assina uma pubkey ed25519 local, TTL 15min import { getItem } from "expo-secure-store"; export async function requestShortLivedCert(jwt: string, publicKey: string) { const res = await fetch("https://openbao.acmetocasino.com/v1/ssh-client/sign/mobile-admin", { method: "POST", headers: { "X-Vault-Token": jwt, // JWT do CF Access, intermediado pelo Worker "Content-Type": "application/json", }, body: JSON.stringify({ public_key: publicKey, valid_principals: "mobile-admin", ttl: "15m", }), }); if (!res.ok) throw new Error(`sign failed: ${res.status}`); const { data } = await res.json(); return data.signed_key as string; // Certificado OpenSSH, TTL 15min }

Mapa de Compliance

O que cada regulador pede, e qual peça do stack responde por isso.

RegimeControleQuem responde
SIGAP (Brasil)Autenticação de acesso privilegiado e registro de sessãoLog FIDO2 do CF Access + sessão sshd no Wazuh
GLI-33Operador nomeado, fator de hardware, trilha de auditoriaIdentidade Google SSO + YubiKey + Wazuh
LGPDQuem acessou PII, quando, com qual finalidadeCF Logpush → Wazuh + auditoria de aplicação em /api/v2/*
MGA Classe 4Custódia de chaves e credenciais de curta duraçãoOpenBao SSH CA (TTL 15min) selado por YubiHSM 2
UKGC LCCPSegregação de funções, privilégio mínimoPolíticas do CF Access por aplicação + roles do OpenBao
OWASP MASVSAUTH-1/2, NETWORK-1/2, STORAGE-1Passkey + mTLS + cert pinning + MMKV encriptado

Comparativo de Custo

Conta de padaria anualizada para um time de 5 operadores. "Confirmar com o fornecedor" vale para qualquer número de terceiros abaixo — são a ordem de grandeza correta, não cotações atualizadas.

LinhaCF + OpenBaoTeleport (Team)
Licenças de control-planeR$ 0 — CF Zero Trust gratuito ≤ 50 assentosPor usuário ao mês (confirmar com fornecedor)
Serviços self-hostedOpenBao já rodandoAuth + Proxy + agents + Device Trust
YubiKey 5 NFC × 5~R$ 1.500 uma vez~R$ 1.500 uma vez
App móvel (Expo EAS)US$ 99/mês plano teamUS$ 99/mês plano team
Esforço de engenharia (setup)10–14 homem-dias15–20 homem-dias + upgrades contínuos
Custo de migração se abandonadoBaixo — OpenBao e CF usam padrões abertosAlto — RBAC + gravações vivem no Teleport

Resumo do Stack

keyHardware

YubiKey 5 NFC · YubiHSM 2 · iPhone Secure Enclave / Android StrongBox

lockIdentidade / segredos

Cloudflare Access · Google Workspace SSO · OpenBao (SSH CA + PKI) · cloudflared

phone_iphoneApp móvel

React Native · Expo SDK 51 · TypeScript · Zustand · TanStack Query · XTerm.js · MMKV

shieldAuditoria / SIEM

Wazuh SIEM · Cloudflare Logpush · log de sessão sshd · auditd

cloudEdge

Cloudflare Workers (API móvel) · Cloudflare Tunnel · Cloudflare WAF

notifications_activePush & alertas

Expo Push → FCM + APNs · bypass de alerta crítico em canais de incidente