# Fase 3 + Fases 0.2/0.3: infra de PRODUÇÃO Monetarie, status final

Data: 2026-07-07 (sessão paralela de infra, worktree `monetarie-infra-prod`, branch `infra-prod`).
Escopo executado conforme `docs/handoff/2026-07-07-fase3-infra-prod-orientacao-sessao-paralela.md`.
A sessão principal pode iniciar as Fases 4/5/6 a partir deste relatório.

## Resumo

FASE 3 COMPLETA (Tasks 3.1 a 3.5) APLICADA E VALIDADA VIVA na VPC de produção
10.50 (`vpc-0da523dbdbac50b5d`, adotada por data source, estado Terraform novo e
isolado). Fase 0.3 (truststore) COMPLETA com verify 8/8. Fase 0.2 (matriz de
acessos) PREENCHIDA da origem 10.50: HSM prod e MQ prod CONECTAM; RSFN resolve
e conecta em arq/www; dict/icom 16522 pendentes de liberação RTM. O chamado da
Fase 0.1 foi dispensado pelo dono, que forneceu o endpoint do HSM
(`cloudhsm.priv.rtmcloud.net.br`) e os dados do MQ de produção diretamente.

## Estado Terraform

- Backend: S3 `monetarie-tfstate-990933657879`, key **`prod/greenfield/terraform.tfstate`**
  (isolado do HML `homolog/greenfield/`), lock DynamoDB `monetarie-tf-lock`.
- Init: `terraform init -reconfigure -backend-config=backend.prod.hcl`
- Plan/apply: `terraform plan -var-file=envs/prod.tfvars`
- Estado final: **`terraform plan` = No changes** (247 recursos aplicados).
- Gate de não regressão de HML provado em TODAS as ondas: plan de HML pós-refactor
  idêntico ao baseline (9 add / 12 change / 9 destroy de drift PRÉ-EXISTENTE;
  únicas deltas = renames de endereço via moved blocks). ATENÇÃO: o drift
  pré-existente de HML inclui replace de nats/openvpn/tigerbeetle (AMI nova) e
  task-defs; NÃO aplicar em HML sem tratar isso antes.
- Revisão adversarial pré-apply: workflow com 25 agentes (3 lentes + verificação
  por achado); achado crítico (rotas TGW ausentes na subnet pública do OpenVPN)
  corrigido ANTES do apply; demais confirmados corrigidos ou documentados abaixo.

## Recursos criados (IDs principais)

| Recurso | Valor |
|---|---|
| Aurora PostgreSQL | `monetarie-core-prod-50`, engine **17.9**, `available`, deletion_protection=true, endpoint `monetarie-core-prod-50.cluster-cb00agagqtcs.sa-east-1.rds.amazonaws.com` |
| Redis | `monetarie-gf-redis-node-prod-50` (`available`), `monetarie-gf-redis-node-prod-50.v2mdsw.0001.sae1.cache.amazonaws.com` |
| KMS | 6 CMKs (core/pix/spb/npc/sta/clst), aliases `alias/monetarie-<dominio>-prod` |
| Secrets | Contêineres `monetarie/prod/*` criados VAZIOS (senhas/valores fora do Terraform); MQ já populado (ver abaixo) |
| ECR | ADOTADO via data source (repos compartilhados, dono = estado HML) |
| ECS | Cluster `monetarie-greenfield-prod` + roles/log groups; **ZERO service/task-def de aplicação** (`create_ecs_services=false`; deploy é a Fase 6, por digest). ASG `monetarie-core-ecs-prod` com 1 EC2 aguardando a Fase 6. Task-def `db-bootstrap` existe (inerte; usada na Fase 4) |
| NATS | Cluster JetStream **3 nós** `monetarie-nats-{1,2,3}-prod` em 10.50.{1,2,3}.10 (1 por AZ, t4g.small, sem IP público) |
| TigerBeetle | Cluster **3 réplicas 0.17.3** `monetarie-tigerbeetle-{0,1,2}-prod` em 10.50.{1,2,3}.20 (1 por AZ, t4g.large, EBS gp3 30GB dedicado por nó com prevent_destroy, SEM --development) |
| NAT Gateway | `nat-0f0cbaab083db3502` (`available`, EIP 18.228.20.148), subnet pública 10.50.4.0/24 + IGW próprio; rota default da `monbank-rtm-prod-rt` -> NAT; tasks/EC2 SEM IP público |
| OpenVPN | `i-0efb3bf1fbabfb241` em 10.50.4.30 (subnet pública), EIP **15.229.92.89**, UDP 1194 ativo, perfis `Monetarie-PROD-OpenVPN-*.ovpn` em `/opt/monetarie/openvpn/` na instância |
| ALB interno | `monetarie-internal-prod-50` (`active`), 15 target groups `mon-*-50` (sem targets até a Fase 6) |
| DNS | Zona ÚNICA canônica `monetarie.internal` (`Z07255101LW0TK32G8LU2`, a mesma do HML) associada às DUAS VPCs (10.45 + 10.50): HML resolve `*-h`, produção resolve os nomes sem sufixo (`core-api.monetarie.internal` etc.), `nats.monetarie.internal` = multi-A com os 3 nós. A segunda zona criada por engano (Z0566…) foi eliminada em 2026-07-07. Zona `priv.rtmcloud.net.br` também associada à VPC prod |
| Resolver RSFN | Outbound em 10.50.1.53/10.50.2.53, forward `rsfn.net.br` para os 6 IRS oficiais |
| VPC endpoints | 10 nossos (`monetarie-*-vpce-prod`) + 3 da RTM adotados (`monbank-prod-{ssm,ssmmessages,ec2messages}-TEMP`; ver riscos) |

## Gates provados (evidência viva)

1. **Task 3.1**: plan prod adotando a VPC sem tocar HML; plans salvos no scratchpad
   da sessão; commits `2f5f6e2f`, `bcbd5eec`, `c4c29afe`, `11aac86d`.
2. **Task 3.2**: Aurora 17.9 `available` com deletion_protection; Redis `available`;
   endpoints resolvem.
3. **Task 3.3**: os 3 nós NATS Online; cluster `monetarie-prod` com rotas entre os
   3; stream de teste criada com **Replicas: 3** (réplicas nats-1/nats-2, leader
   nats-3), lida e removida.
4. **Task 3.4**: cliente TB conectou às 3 réplicas (`on_connect to=0/1/2`, quorum);
   conta sentinela criada (`CreateAccountStatus.created`) e lida de volta.
   **Pós-gate, por decisão do dono (zero resíduo em produção): cluster
   REFORMATADO limpo** (stop nos 3 nós, wipe dos `0_N.tigerbeetle`, format
   `--replica-count=3` réplica a réplica, start; os 3 serviços ativos e
   `lookup_accounts` do antigo id retornando `No accounts were found`).
   O ledger de produção nasce com ZERO registros.
5. **Task 3.5**: OpenVPN `openvpn-server@prod` ativo (UDP 1194);
   `core-api.monetarie.internal` resolve para o ALB; plan final limpo.
6. **SSM**: as 9 EC2 da 10.50 Online.

## Matriz de acessos da Fase 0.2 (origem 10.50.4.30, OpenVPN prod)

| Serviço | Alvo | Resultado |
|---|---|---|
| HSM prod | `cloudhsm.priv.rtmcloud.net.br:443` (10.173.1.247) | **CONNECT + TLS responde (HTTP 302)** |
| MQ SPB01 | `172.31.1.50:1414` | **CONNECT** |
| MQ MES01 | `172.31.1.50:12422` | **CONNECT** |
| MQ console web | `172.31.1.50:9443` | **CONNECT** |
| MQ porta HML | `172.31.1.50:1514` | fechado (esperado; portas prod são 1414/12422) |
| DNS RSFN | dict/icom/arq/www.rsfn.net.br | **todos resolvem** (200.218.66.144 / 200.218.67.204 / 200.218.66.142 / 200.218.66.12) |
| RSFN ARQ | `arq.pi.rsfn.net.br:1130` | **CONNECT** |
| RSFN www | `www.rsfn.net.br:443` | **CONNECT** |
| RSFN DICT | `dict.pi.rsfn.net.br:16422` | **CONNECT** |
| RSFN DICT-NP | `dict-np.pi.rsfn.net.br:16432` | **CONNECT** |
| RSFN ICOM | `icom.pi.rsfn.net.br:16422` | **CONNECT** |
| RSFN ICOM-SEC | `icom-sec.pi.rsfn.net.br:17422` | **CONNECT** |

**ERRATA (corrigida na mesma sessão):** a primeira rodada da matriz sondou os
hosts de produção nas portas de HOMOLOGAÇÃO (16522/16532/17522, herdadas dos
targets de HML) e concluiu erradamente que DICT/ICOM estavam bloqueados na RTM.
O cliente provou o contrário (sweep da EC2 10.50.1.128 com as portas de
produção) e a re-sondagem das NOSSAS duas origens confirmou: produção usa
**16422/16432/17422** e está TUDO ABERTO. Não há pendência de rede com a RTM.
As portas por ambiente agora são parametrizadas (`rsfn_service_ports`).
| Auth de canal MQ | APP.SVRCONN / spb_server | pendente (exige cliente MQ; validar na Fase 6 com o sidecar, como em HML) |

## Fase 0.3: truststore ICP-Brasil de produção

- `icp_brasil_ca_chain_prod.pem` com **9 CAs** montada a partir dos bundles
  oficiais AIA dos próprios certificados (ac-validspbv5.p7b da VALID;
  acserproacfssl.p7b e serprossl.p7b do SERPRO): Raízes Brasileiras v5/v10/v11/v12,
  AC SERPRO SSLv1, AC VALID v5, AC VALID SPB v5, AC SERPRO v4, AC SERPRO Final SSL.
- `openssl verify` **OK para os 8 certs**: 4 nossos (PIA P003, PIC P002, 2x SPB
  P001 com seriais 32E065D08DC8469A e 3422F6C3C91AE4BE) + 4 peers BACEN
  (PIA-P515, PIC-P514, SPB-P060, MES-P061).
- Commitada em `pix/backend/apps/shared/priv/certs/` e
  `spb/services/bacen_gateway/priv/certs/` (só CAs públicas; commit `a18c9da2`).
- Validade: SPB-P060 e MES-P061 vencem **2026-09-01** (monitorar renovação).

## Fase 0.1 (ex-chamado RTM) e spike HSM

- Chamado dispensado pelo dono. Endpoint do HSM de produção informado:
  `https://cloudhsm.priv.rtmcloud.net.br` (registro A já existia na zona da conta,
  apontando para 10.173.1.247; a VPC prod já roteava esse /32 via TGW).
- Rede PROVADA (CONNECT + TLS 302). **Falta o spike de assinatura**: exige as
  credenciais do HSM de produção (crypto_user/token e UIDs das chaves PIA P003 /
  PIC P002 / 2x SPB P001). Os contêineres `monetarie/prod/hsm/*` existem vazios.
  PENDENTE COM O DONO: credenciais do HSM prod e localizacao dos UIDs (locate-all).
  Bloqueante do go-live PIX (Fases 5/6), não da infra.

## Segredos gravados (Secrets Manager, CMK do SPB)

- `monetarie/prod/mq/spb/ssh_private_key`: chave ed25519 do usuário `herbeth`
  (fingerprint SHA256:2IH1rEZN3+mcOPC04e5qjdU+FJMgY+W9f6u6LmE0FMI, conferido com a
  pública fornecida pelo dono; zip e material temporário destruídos do disco).
- `monetarie/prod/mq/spb/ssh_key_passphrase`: passphrase da chave (validada
  abrindo a chave).
- `monetarie/prod/mq/spb/web_console`: URL/usuário/senha do console MQ 9443.
- `monetarie/prod/mq/spb/connection_info`: host/QM/canal/portas/usuários (não
  sensível, conveniência).
- `monetarie/prod/hsm/pix/{crypto_user,token}` e `.../spb/{crypto_user,token}`:
  app user `APP-MONETARIE-PRD` + token, gravados 2026-07-07 (mesmo app user p/ PIX
  e SPB, consistente com HML; token 28 chars, mesmo formato do de HML).
- `monetarie/prod/hsm/vco/{name,token}`: credencial VCO (administrador do console
  Ecos, para gerar/importar certificados). vHSM = 60042 (não é segredo).

## Fase 0.1 / spike HSM: resultado empírico (2026-07-07)

Credenciais recebidas do dono e gravadas no Secrets Manager. Spike rodado de dentro
da 10.50 (OpenVPN box, lendo os segredos pelo IAM da instância — token nunca em log
de SSM). Descoberta importante:

- **`cloudhsm.priv.rtmcloud.net.br` (10.173.1.247) é o CONSOLE de administração do
  HSM**, não o gateway de assinatura. TLS válido (Let's Encrypt `*.priv.rtmcloud.net.br`).
  `:443` = web console `Login - Ecos Cloud Vhsm` (ASP.NET/Kestrel; `/` redireciona
  para `/Authentication/login`); `:6443` = API server do Kubernetes (`system:anonymous
  forbidden`, o "diagnóstico histórico" que o CLAUDE.md manda não usar). Todos os
  paths `/v1/kmip/...` dão 404. Nenhuma outra porta aberta (8443/9443/8080/... closed).
- **O gateway KMIP REST de assinatura (`/v1/kmip/{vhsm}/sign-rsa`), que a app usa,
  NÃO existe em produção ainda**: em HML é `monetarie-hsm-hml.priv.rtmcloud.net.br`
  (10.151.11.140/141, istio-envoy); o análogo de produção não está publicado na zona
  `priv.rtmcloud.net.br` (que só tem `cloudhsm`, `cloudhsm-hml`, `monetarie-hsm-hml`)
  nem está roteado na route table da 10.50 (só 10.173.1.247/32 vai via TGW).
- **Contrato da API confirmado no código** (`.../crypto/rtm_hsm/client.ex`): login
  `POST /v1/kmip/{vhsm}/get-session-credential` → sessão; assinatura `sign-rsa`
  RSAHASH (PKCS#1 v1.5/SHA-256); **não há operação de `locate`/listar chaves** no
  cliente (só `get-attributes` de um UID já conhecido). Logo os UIDs das nossas
  chaves (PIA P003, PIC P002, 2x SPB P001) têm que vir da RTM/console, não da API.

**RESOLVIDO (2026-07-07 noite): assinatura de produção PROVADA ponta a ponta.**
O gateway REST de produção é `monetarie-hsm-prd.priv.rtmcloud.net.br` (10.151.11.138/139,
istio, TLS Let's Encrypt válido) — informado pelo dono. Adicionadas as rotas
`10.151.11.0/24 → TGW` nas route tables da 10.50 (nível VPC); o RTM completou a rota no
TGW (`tgw-rtb-00c87955e8b181f3f`, via Direct Connect). Do host na 10.50:
- `/v1/health` = 200; `get-session-credential` com `APP-MONETARIE-PRD` = **200, sessão OK**;
- `locate-all` existe e retornou **12 chaves**; os labels identificam as nossas:
  `MONETARIE_P003_PRIV/PUB` (PIA P003, assinatura PIX), `MONETARIE_P002_PRIV/PUB`
  (PIC P002, mTLS), e 2 keypairs SPB P001 (thumbprints 4D58FF64… e B602EB3E…);
- **`sign-rsa` (RSAHASH) com a chave privada da PIA P003 → assinatura que VERIFICA
  (`openssl dgst -sha256 -verify` = `Verified OK`) contra o certificado público P003.**
  É a operação exata que a cabine faz na pibr.001.

UIDs das 4 keypairs gravados no Secrets Manager `monetarie/prod/hsm/{pix,spb}/*_uid`
(NÃO em repo, regra #10). O `RTM_HSM_BASE_URL` de produção já aponta para o endpoint
certo. Assinatura de produção destravada; resta só o deploy (Fase 6) e o eco BACEN.

## Fase 4 parcial: bootstrap de dados (feito sem HSM, 2026-07-07)

Por decisão do dono ("faça tudo o que for possível sem o HSM"). Feito o que não
depende da imagem da aplicação:

- **Todos os secrets de aplicação populados** no Secrets Manager `monetarie/prod/*`,
  com formato idêntico ao de HML (lido para calibrar, sem inventar): db/{6 svcs}/
  password (hex 24B) e /url (`ecto://role:pw@monetarie-core-prod-50...:5432/db`),
  auth/{6}/secret_key_base + guardian_secret (base64 64B), admin/{core,pix,spb,npc,
  sta}/initial_password (20 chars, complexidade garantida, troca no 1º login),
  secrets/master_key + auth/mon_core/webhook_key + auth/mon_npc/cloak_key (base64
  32B), auth/mon_pix/rsa_private_key (RSA PKCS#1 2048) + rsa_public_key, bacen/ispb
  (46026562) + sisbacen (00018). Valores gerados localmente e gravados via arquivo
  temporário com umask 077, nunca ecoados nem em repo (regra #10); temporários
  destruídos.
- **db_bootstrap rodado** (ECS RunTask Fargate): criou os 6 roles `mon_*` com as
  senhas geradas, os 6 bancos (`mon_core` + `mon_pix/spb/npc/sta/clst`) com owner
  correto, e os grants ao `monetarie_admin`. Exit 0.
- **Validado ao vivo**: cada role loga no seu próprio banco com a senha gerada
  (`OK mon_pix @ mon_pix` … para os 6), e `pg_database` confirma os 6 bancos com
  owner correto. Aurora 17.9, negócio zerado.

Falta da Fase 4 (depende da IMAGEM da aplicação promovida por digest + do perfil
`SEED_PROFILE=prod` que é código de produto, fora desta sessão): rodar as
migrations, os seeds só-de-sistema (COSIF, tabelas de referência, grupos/permissões,
diretório de instituições) e criar o admin inicial (`admin@monetarie.com`,
confirmado pelo dono). Os secrets e os bancos já estão prontos para isso.

## Pendências e riscos

1. RESOLVIDO (era erro NOSSO, não bloqueio RTM): a matriz inicial sondou portas
   de homolog em hosts de produção. Com as portas certas (16422/16432/17422),
   DICT/DICT-NP/ICOM/ICOM-SEC conectam das duas origens 10.50. Ver ERRATA na
   seção da matriz. Nada a pedir à RTM.
2. RESOLVIDO: HSM de produção validado ponta a ponta (endpoint
   `monetarie-hsm-prd`, rota TGW completada pelo RTM, auth OK, assinatura PIA P003
   `Verified OK`, UIDs no Secrets Manager). Ver seção "spike HSM". Resta para a Fase 6
   apenas escolher, entre os 2 keypairs SPB, o que casa com o `BACEN_CERT_PEM_FILE`
   de produção (correlacionar o thumbprint 4D58FF64/B602EB3E com o cert ativo do SPB).
3. **Endpoints SSM `monbank-prod-*-TEMP` são da RTM/Gabriel**: se forem removidos,
   as EC2 perdem SSM; nesse caso esvaziar `skip_interface_endpoints` em
   `envs/prod.tfvars` e aplicar (cria os nossos). A regra 443 no SG default
   (`sgr-059c1a9f4ddd75c70`) foi necessária porque os TEMP usam o SG default.
4. **Auth de canal MQ** (APP.SVRCONN/spb_server) pendente de cliente MQ (Fase 6,
   sidecar; mesmo caminho validado em HML).
5. **UIDs de HSM em env de task-def** (padrão herdado de HML): na Fase 6, avaliar
   mover para secrets.
6. **OpenVPN UDP 1194 aberto a 0.0.0.0/0** (padrão HML): restringir a IPs
   administrativos quando definidos (`openvpn_allowed_cidrs`).
7. **Dimensionamento registrado**: Aurora max 16 ACU (teto sem custo em idle) e
   Redis t4g.micro deliberados para o go-live; rever com tráfego real.
8. **bacen_env/sta_environment**: valores de produção definidos na Fase 6, depois
   de verificar no código o que as aplicações aceitam (zero inferência).
9. RESOLVIDO: a conta sentinela do gate foi eliminada; cluster TB reformatado
   limpo em 2026-07-07 ~23:40 UTC (ledger com zero registros, provado).
10. **Flags de negócio**: nenhuma task-def existe ainda; a Fase 6 nasce com ENVIO
    BACEN desabilitado até o eco assinado (gate 6.2), conforme o plano.

## Rollback

- A infra de produção é um estado isolado: `terraform destroy -var-file=envs/prod.tfvars`
  derruba tudo SEM tocar HML (exceções: Aurora com deletion_protection+prevent_destroy
  e EBS do TB com prevent_destroy exigem remoção consciente das proteções; os
  endpoints TEMP e a VPC/rotas RTM não são geridos por nós).
- HML permanece intocado (nenhum apply foi feito no estado homolog; o drift
  pré-existente segue lá, documentado nos plans do scratchpad da sessão).

## Custos novos (aproximados, por mês)

NAT Gateway ~US$70 + dados; 3x t4g.small (NATS) ~US$36; 3x t4g.large (TB)
~US$180; t4g.micro OpenVPN ~US$6; t4g.small ECS ~US$12; Aurora Serverless v2
por uso (min 0,5 ACU ~US$65); Redis micro ~US$11; ALB ~US$20; 10 VPC endpoints
~US$75; 2 EIPs. Total base na casa de US$450 a 500/mês antes de tráfego.
