Migrar o messagebroker compartilhado para Amazon MQ (RabbitMQ)

TLDR: Provisionar um messagebroker compartilhado no Amazon MQ para RabbitMQ (cluster HA, na VPC AWS compartilhada), expô-lo por outputs de remote state para que cada projeto crie o seu próprio vhost/user, e manter o broker antigo no ar até os consumidores validarem.

Contexto

O messagebroker compartilhado rodava num droplet da DigitalOcean, provisionado por user_data + Caddy, com DNS no Cloudflare e firewall do provedor. É infraestrutura compartilhada: cada projeto tem um vhost/user (hoje só marketing/n8n, vhost marketing-automation--staging).

O cluster Kubernetes compartilhado e a camada de dado do marketing (Aurora Postgres, ElastiCache Valkey) já estão na AWS, na VPC compartilhada (10.0.0.0/16, conta shared--production, subnets privadas compartilhadas org-wide via RAM). O messagebroker era a última peça compartilhada fora da AWS.

O Amazon MQ para RabbitMQ é RabbitMQ gerenciado — consistente com a direção de serviço gerenciado já tomada em Aurora e ElastiCache.

Decisões

Decisão Escolha Motivo
Gerenciado vs. self-hosted Amazon MQ, não RabbitMQ no EKS consistência com Aurora/ElastiCache; o provider kubernetes do módulo de messagebroker segue um stub
Modo de deploy CLUSTER_MULTI_AZ (HA) é produção; HA evita indisponibilidade em falha ou manutenção de nó. O droplet único não tinha HA nenhuma
Topologia um broker centralizado, multi-vhost overhead por vhost é desprezível; escala-se por tamanho de instância, não por broker separado
Tudo por Terraform sem local-exec vhost/user pelo provider cyrilgdn/rabbitmq onde declarados
Nomenclatura messagebroker em todo lugar só as strings impostas pela AWS ficam como são (mq:*, aws_mq_broker)

O perigo principal: contrato de endereço

Os outputs consumidos hoje assumem IP privado + AMQP 5672 em texto puro e uma API de management em HTTP. O Amazon MQ expõe hostname com TLS: AMQPS na 5671 e management em HTTPS 443. Adaptar isso é o risco central da migração.

Objetivos

  • Broker no Amazon MQ (cluster HA) nas subnets privadas da VPC compartilhada, alcançável privadamente pelos workloads do EKS.
  • Broker centralizado/multi-vhost, com o vhost, user e permissões do marketing recriados nele.
  • Preservar o contrato de output de remote state ao máximo, adaptando para hostname + TLS.
  • Cortar o consumidor n8n do marketing para o broker novo.

Fora de escopo

  • Recursos específicos de aplicação não vivem aqui. O vhost, o user e as permissões do n8n/marketing pertencem ao projeto marketing (marketing/automation/.infra), que já os cria via provider rabbitmq. Este stack compartilhado provisiona somente broker + user admin + security group + outputs.
  • Migrar mensagem enfileirada. O n8n reconstrói o estado da fila; só vhost/user/permissão são recriados.
  • Workflows restaurados do n8n que referenciam o hostname antigo — é correção de dado de workflow, em outro lugar.
  • Destruir o droplet: fica no ar até o cutover ser validado, e a remoção é spec própria.

Mudanças

Estrutura

Segue o padrão de provider dividido já usado no stack de Kubernetes:

src/shared/messagebroker/ ├── digitalocean/terraform/ # stack do droplet, movido para cá sem alteração └── aws/terraform/ # NOVO — Amazon MQ para RabbitMQ

Os targets de make ganham um switch PROVIDER (default aws, PROVIDER=do para o droplet).

Novo: src/shared/messagebroker/aws/terraform/

  • Provider: AWS assumindo a TerraformRole da conta shared, mesmo padrão dos outros stacks AWS. Chave de state shared/messagebroker-aws/terraform.tfstate.
  • aws_mq_broker: engine_type = "RabbitMQ", deployment_mode = "CLUSTER_MULTI_AZ", host_instance_type parametrizado, publicly_accessible = false, subnet_ids vindos do remote state da rede, security group novo, e o user admin com senha do ward.
  • Security group: na VPC compartilhada, ingress 5671 (AMQPS) e 443 (management) a partir do CIDR da VPC, egress liberado.
  • Outputs: mesmos nomes do stack do droplet, remapeados — messagebroker_amqp_host (hostname do endpoint AMQPS), messagebroker_amqp_port = 5671, messagebroker_management_host, messagebroker_management_port = 443, messagebroker_admin_password (sensitive), mais messagebroker_amqp_endpoint e messagebroker_amqps_tls = true. messagebroker_public_ip / _private_ip deixam de existir — não há IP.

Consumidor: marketing/automation/.infra/terraform

  • Provider rabbitmq apontado para o endpoint de management do Amazon MQ em HTTPS.
  • RABBITMQ_HOST = messagebroker_amqp_host, RABBITMQ_PORT = 5671, e RABBITMQ_TLS = "true" — o n8n precisa conectar por AMQPS.

Pré-requisitos de permissão

A TerraformRole da conta shared tinha EC2/RAM/EKS/ECR/IAM/Logs mas não mq:*. É preciso adicionar a statement mq:* à TerraformPolicy e reaplicar o bootstrap da conta antes de criar o broker. O Amazon MQ também precisa de ec2:*SecurityGroup* e ec2:*NetworkInterface*.

A senha do admin fica no ward (TF_VAR_shared_messagebroker_admin_password) e precisa atender às restrições do Amazon MQ (mínimo 12 caracteres, sem vírgula).

Como verificar

  • aws mq describe-broker mostra o broker RUNNING, em CLUSTER_MULTI_AZ, nas subnets privadas.
  • De dentro de um pod do EKS: openssl s_client -connect <amqp-host>:5671 conecta (alcance privado + TLS).
  • O vhost do marketing, seu user e permissões existem no broker novo.
  • kubectl -n marketing-automation--staging logs deploy/n8n-worker sem ENOTFOUND nem connection-refused.
  • Um workflow no n8n publica e consome via RabbitMQ ponta a ponta.
  • Os outputs de remote state resolvem e o stack do marketing planeja/aplica limpo contra eles.

Documentação

  • CLAUDE.md — messagebroker no Amazon MQ, split {digitalocean,aws} e o switch PROVIDER.
  • Skill commons:infra — seção de outputs de remote state: AMQPS 5671 + management 443, hostname e não IP, RABBITMQ_TLS=true obrigatório.
  • Aprendizado: restrições do Amazon MQ para RabbitMQ em cluster — onde as suposições desta spec de fato quebraram (tipo de instância, contagem de subnet).