De SSH para REST: modernização orientada por segurança dos pipelines de dados EMR do Slack
(slack.engineering)- A plataforma de dados do Slack operava pipelines críticos de dados, como indexação diária de busca e tarefas analíticas, com mais de 700 Operators baseados em SSH, exigindo que todos os jobs fizessem acesso SSH direto a clusters AWS EMR de produção, criando uma ampla superfície de ataque
- Essa dependência de SSH não apenas representava um risco de segurança, mas também se tornou um obstáculo central para a modernização da infraestrutura, incluindo a migração para Spark on Kubernetes, EMR on EKS e a conclusão da iniciativa Whitecastle
- Como solução, foi usado o YARN Distributed Shell para permitir a execução até mesmo de comandos shell arbitrários dentro de contêineres YARN, e todas as submissões de jobs foram unificadas por meio do gateway REST interno do Slack, o Quarry
- Mais de 700 jobs foram migrados sem interrupção (zero downtime) em 8 regiões de dados, e a remoção de SSH foi concluída em 100% ao longo de três trimestres
- Como resultado, o Slack obteve redução da superfície de ataque, maior confiabilidade das tarefas e melhor visibilidade, além de estabelecer a base para concluir o Whitecastle e avançar para infraestruturas de próxima geração, como Spark on Kubernetes
Contexto: como surgiu a plataforma de dados baseada em SSH
- A plataforma de dados do Slack, construída por volta de 2017, adotou o modelo com SSH como o caminho mais direto para o Airflow executar jobs em clusters EMR
- Com
SSHOperator, conectava-se ao nó mestre do EMR e executavam-se comandos comospark-submit
- Com
- Depois disso, as equipes criaram seus próprios Operators personalizados baseados em SSH para diversos usos, não só Spark, mas também MapReduce, AWS CLI e scripts Python customizados
- Como resultado, o ambiente de produção acumulou mais de 700 jobs baseados em SSH
O custo real do modelo com SSH
-
Riscos potenciais de segurança
- O acesso SSH direto aos clusters de computação ampliava a superfície de ataque
- A distribuição e rotação de chaves em todos os workers de orquestração aumentavam a carga operacional
- Para auditoria detalhada, era necessário correlacionar logs de vários sistemas
- A gestão de permissões ficava mais complexa, com security groups dedicados e configurações customizadas
-
Problemas operacionais
- Os jobs não eram distribuídos e eram executados diretamente no nó mestre do EMR, gerando contenção de recursos
- Quando um Pod do Kubernetes reiniciava, a conexão SSH era interrompida e o job falhava
- Jobs de longa duração continuavam executando após a desconexão e viravam processos zumbis
- Quando a conexão caía, não era possível confirmar se o job teve sucesso ou falhou
-
Fatores que bloqueavam a modernização
- Era inviável avançar para Spark on Kubernetes e EMR on EKS (era preciso eliminar a dependência de SSH primeiro)
- O último cluster EMR da conta principal não podia ser movido para uma conta filha, impedindo a conclusão da iniciativa Whitecastle
- Whitecastle é a iniciativa do Slack de mover a infraestrutura AWS para contas filhas para reforçar segurança e isolamento de rede
- Não era possível implementar monitoramento e visibilidade adequados dos jobs
-
Caso representativo — equipe de Search Infrastructure
- Um pipeline que constrói diariamente índices de busca Solr com dados na casa dos terabytes, parte essencial do recurso de busca do Slack
- Por depender de submissão de jobs via SSH, ficava exposto a todos os problemas de confiabilidade citados acima
Conceito básico de submissão de jobs via REST
-
Limites inerentes do SSH
- Uma conexão SSH é uma conexão direta com estado; se ela cai por reinício de Pod ou outro motivo, o comando pode continuar rodando, falhar ou deixar processos órfãos
- Não há um meio confiável de reconectar e verificar o estado
-
Alternativa com REST
- Motores modernos de computação como YARN, Trino e Snowflake oferecem submissão de jobs por API HTTP
- POST da solicitação de job → retorna um ID de job
- GET do estado do job → permite verificar se está executando, concluído ou falhou
- DELETE do job → permite cancelamento adequado
- O ciclo de vida do job é gerenciado no lado do servidor, então mesmo se o cliente reiniciar, o job continua executando e seu estado segue consultável
- Motores modernos de computação como YARN, Trino e Snowflake oferecem submissão de jobs por API HTTP
-
O papel e os limites do YARN
- Para workloads Hadoop como MapReduce, Spark e Hive, o YARN é o gerenciador de recursos e também fornece uma API REST
- Porém, mais de 300 jobs baseados em CLI que executavam comandos arbitrários como
aws s3 syncehadoop distcpnão tinham uma API REST pronta para uso - A peça-chave para resolver isso foi o YARN Distributed Shell
O avanço decisivo: YARN Distributed Shell
- Para Spark, havia a API REST do Livy, e para Hive, o HiveServer2, então a migração era relativamente simples
- Já os jobs MapReduce e mais de 300 jobs baseados em CLI eram um grande desafio, pois não havia uma API REST pronta para uso
-
Requisitos
- Uma solução simples baseada em REST que se encaixasse naturalmente na arquitetura
- Reaproveitar os mecanismos existentes de autenticação e autorização sem precisar de uma camada de segurança customizada
- Usar um protocolo open source e não uma solução proprietária, aproveitando a API padrão do YARN
- Complexidade mínima, evitando construir e operar infraestrutura própria para execução de jobs customizados
-
Abordagens consideradas e descartadas
- Construir um serviço wrapper customizado para execução remota de comandos
- Usar frameworks de execução remota como Ansible e Salt
- Adicionar ao YARN um novo tipo de job do zero
- Todas foram consideradas inadequadas por introduzirem complexidade excessiva, segurança customizada e novas dependências
-
Descoberta do YARN Distributed Shell
- Com
org.apache.hadoop.yarn.applications.distributedshell.ApplicationMaster, tornou-se possível executar scripts shell arbitrários dentro de contêineres YARN - Como esse recurso já faz parte do YARN, usa a mesma API REST e não exige uma camada de segurança customizada
- Com
-
Como funciona
- 1. Fazer upload do script de comando para o S3 (por exemplo:
aws s3 sync /tmp/data/ s3://bucket/output/) - 2. Submeter ao YARN com a configuração do Distributed Shell
- Definir
application-typecomoMAPREDUCEe incluir noam-container-specvariáveis de ambiente comoDISTRIBUTEDSHELLSCRIPTLOCATION,DISTRIBUTEDSHELLSCRIPTLENeDISTRIBUTEDSHELLSCRIPTTIMESTAMP
- Definir
- 3. O YARN aloca um contêiner, baixa o script e o executa
- O YARN gerencia limites de recursos como memória e vCore, isolamento de contêineres, retries e tolerância a falhas, cancelamento apropriado e logging via UI do YARN
- 1. Fazer upload do script de comando para o S3 (por exemplo:
- Essa decisão permitiu executar dentro de contêineres YARN não só workloads Hadoop, mas também
aws s3 sync,hadoop distcpe scripts Python customizados
A solução: Quarry
- O Quarry é o gateway de submissão de jobs baseado em REST do Slack, criado para enviar jobs para múltiplos motores de computação, como EMR/YARN, Trino e Snowflake
- Ele já resolvia problemas de autenticação, confiabilidade e visibilidade, então se encaixava exatamente na eliminação do SSH
-
Funcionalidades do Quarry
- Autenticação: usa tokens entre serviços em vez de chaves SSH
- Submissão de jobs: envia jobs para YARN, Trino e Snowflake por APIs REST
- Rastreamento de estado: monitora o status dos jobs no lado do servidor
- Gestão do ciclo de vida: permite cancelamento e limpeza adequados com API REST
- Visibilidade: fornece logs estruturados, métricas e tracing para todas as submissões de jobs
-
Mudança de arquitetura
- Antes:
Airflow → SSH Connection → EMR Master Node → Execute Command - Depois:
Airflow → Quarry REST API → YARN ResourceManager → EMR Container - O Operator do Airflow passou a fazer requisições HTTP ao Quarry em vez de abrir conexões SSH; o Quarry submete ao YARN e faz polling do estado
- Mesmo se o Pod do Airflow reiniciar, o job continua, pois o Quarry preserva esse vínculo
- Antes:
-
Pontos fortes do Quarry
- Com suporte ao YARN Distributed Shell, ele se tornou um gateway genérico de submissão de jobs
- Jobs Spark, queries Hive e scripts shell passam todos pela mesma API REST
- Foram eliminadas as credenciais SSH e o acesso direto ao cluster, ficando apenas chamadas REST com autenticação e rastreamento de jobs no lado do servidor
A jornada de migração
- Havia mais de 700 jobs de produção em 8 regiões de dados independentes, com diferentes configurações de rede e exigências de soberania de dados, além de workloads que exigiam zero downtime, como indexação de busca; por isso, foi necessário um plano estruturado
-
Abordagem em fases
- Fase 1 – Prova de conceito (PoC): validar a abordagem com Quarry em jobs piloto, desenvolver o primeiro Quarry Operator e testá-lo em ambiente dev
- Fase 2 – Revisão de segurança: trabalhar com a equipe de segurança para planejar a remoção de credenciais e verificar se a abordagem baseada em REST atendia aos requisitos
- Fase 3 – Execução guiada por OKR: definir a migração como Key Result para dar visibilidade executiva; nessa fase foi alcançado o marco de 80% de migração
- Fase 4 – Migração em massa: várias equipes, como Search Infrastructure, Data Engineering & Analytics e ML Services, migraram em paralelo os workloads restantes em todas as regiões
- Fase 5 – Limpeza final: concluir DAGs pendentes, descontinuar todos os Operators legados baseados em SSH e chegar a 100%
-
Números da migração
- Mais de 700 jobs migrados em 7 tipos de Operator
- Implantação coordenada em 8 regiões de dados independentes
- 5 equipes migraram para os novos Operators
- Zero interrupção em serviços críticos do negócio
- Da fase piloto à eliminação total do SSH, tudo foi concluído em três trimestres
Desafios enfrentados durante a migração
-
Desafio 1 — falha no Virtual Memory Check
- Durante a migração de um DAG de exportação de dados, um job que funcionava com SSH falhou por erro de verificação de vmem
- Causa: com SSH, o job rodava diretamente no nó mestre e contornava a aplicação de recursos do YARN; com Quarry, o job passou a ser submetido corretamente ao YARN, então contêineres que excediam o limite de memória virtual eram rejeitados
- Solução: desabilitar o vmem check em todos os clusters, seguindo boas práticas da AWS —
"yarn.nodemanager.vmem-check-enabled": "false"- Isso está alinhado à recomendação da AWS de que a contabilidade de memória virtual no Linux não é confiável e que o limite de memória física é suficiente
- Lição: o SSH mascarava muitos problemas, então ao migrar para submissão correta no YARN, era preciso esperar o aparecimento de limites de recursos que antes ficavam invisíveis e testar bem em dev
-
Desafio 2 — isolamento de rede e conectividade com EKM
- Ao mover jobs de Search Infrastructure em dev de um cluster dev para um cluster analítico de staging, ocorreram timeouts de conexão com o EKM (Enterprise Key Management)
- Erro:
Unable to execute HTTP request: Connect to sts.amazonaws.com:443 failed: connect timed out - Causa: o cluster original tinha roteamento de rede até o endpoint de gerenciamento de chaves, mas o cluster analítico de staging, em um segmento de rede mais restrito, não possuía conectividade equivalente, revelando uma dependência da topologia de rede que não estava explícita na configuração do job
- Solução: mover os jobs de Search Infrastructure para um cluster dev ETL com roteamento para o serviço dev; manter em staging apenas os jobs que precisavam do catálogo Hive de produção; e ampliar o cluster dev ETL para absorver a carga adicional
- Lição: a topologia de rede é extremamente importante; antes de decidir em qual cluster cada job vai rodar, é preciso entender isolamento de rede e fronteiras entre contas
-
Desafio 3 — complexidade multi-região
- Por exigências de soberania de dados, havia clusters EMR operando em 8 regiões de dados independentes, então eliminar SSH significava, na prática, 8 migrações em paralelo
-
Fatores de complexidade
- Gestão de configuração: cada região exigia configurações próprias do Quarry, endpoints de cluster e regras de roteamento de rede
- Carga de testes: toda mudança de código precisava ser validada nas 8 regiões
- Implantação sequencial: não era possível implantar tudo ao mesmo tempo; o rollout precisava ser gradual por região
- Problemas específicos por região: diferenças em configuração de rede, regras de soberania de dados e versões de cluster
-
Como isso foi tratado
- Validar primeiro em uma única região piloto, em geral baseada nos EUA
- Documentar os requisitos de configuração por região
- Construir um Quarry Operator com consciência de região
- Fazer rollout gradual e incorporar aprendizados de cada região
- Acompanhar separadamente o progresso da migração em cada região
- Lição: infraestrutura multi-região não é apenas N vezes mais trabalho; ela é N vezes mais difícil por causa dos modos de falha específicos de cada região, então é preciso reservar tempo suficiente para coordenação entre regiões e debugging regional
Resultados
- Eliminação de 100% do SSH, com todos os jobs de produção passando a usar submissão via REST por meio do Quarry
-
Ganhos de segurança
- O acesso SSH foi removido de clusters EMR de produção em todas as 8 regiões de dados independentes, reduzindo drasticamente a superfície de ataque
- A distribuição de chaves SSH foi substituída por autenticação com tokens entre serviços, e o logging da API REST passou a fornecer trilha de auditoria adequada
- Todas as submissões de jobs passaram a ter logs estruturados via Quarry
- O último cluster EMR da conta principal da AWS foi movido para uma conta filha, concluindo a iniciativa Whitecastle
- A eliminação de security groups especiais e de uma gestão complexa de permissões simplificou o compliance
-
Melhorias operacionais
- A contenção de recursos no nó mestre foi eliminada, e todos os jobs não Hadoop passaram a executar em contêineres YARN distribuídos com alocação adequada de recursos
- Mesmo com reinício de Pods Kubernetes do cliente, os jobs continuavam ativos, trazendo grande melhora de confiabilidade, eliminando processos zumbis e permitindo encerramento correto via API REST
- A API do Quarry passou a fornecer estado de job, logs e métricas estruturados, permitindo rastrear todo o ciclo de vida do job, consultar logs dos contêineres YARN e depurar com as ferramentas apropriadas
-
Base para o futuro
- Com a dependência de SSH removida, tornou-se possível a migração para Spark on Kubernetes
- A arquitetura baseada em REST está alinhada com práticas cloud-native
- O Quarry Operator, mais simples e fácil de manter do que configurações SSH complexas, facilitou o onboarding das equipes
- Houve desacoplamento entre o Airflow e os detalhes da infraestrutura EMR
- A padronização de todas as submissões de jobs no Quarry tornou mudanças futuras mais simples
- Após dois anos de operação em produção, a validade da decisão arquitetural foi confirmada, com melhorias em segurança, estabilidade operacional e flexibilidade de infraestrutura
Lições aprendidas
-
O que funcionou bem
- Migração gradual: rollout sequencial Dev → GovDev/CommDev → Prod e migração por tipo de Operator, acumulando aprendizados a cada etapa
- Forte colaboração entre equipes: cooperação entre Search, Analytics, Data Engineering, ML, Marketing e outras áreas, com code reviews rápidos e comunicação por canal compartilhado
- Acompanhamento guiado por dados: criação de um dashboard para o progresso da migração em todas as regiões e uso de consultas ao banco do Airflow para identificar trabalhos restantes baseados em SSH
-
O que fariam diferente
- Mapear antes a topologia de rede: problemas de isolamento de rede, como a conectividade com EKM, só foram descobertos mais tarde; seria preciso documentar fronteiras de conta do Whitecastle e roteamento de rede antes da migração dos clusters
- Testar limites de recursos mais cedo: o problema do vmem check apareceu tardiamente; seria necessário incluir desde a fase piloto testes dos limites de recursos do YARN em comparação com SSH
- Comunicar antes as restrições dos Operators: quando o uso de novos
SSHOperatorfoi restringido na fase final, algumas equipes não sabiam; seria preciso reforçar a comunicação prévia com todos os usuários do Airflow
-
Boas práticas para migrações em larga escala
- Construa monitoramento antes de migrar: crie cedo dashboards que permitam ver sempre o trabalho restante e use consultas ao banco do Airflow
- Teste em vários ambientes: valide em Dev, CommDev e GovDev para detectar problemas específicos antes da produção, especialmente testes entre fronteiras de contas para identificar antecipadamente problemas de isolamento de rede
- Descontinue Operators gradualmente: retire CrunchExecOperator, S3SyncOperator e outros um de cada vez, tratando cada etapa como um mini projeto com seus próprios testes e validação; é mais lento, mas reduz muito o risco
Ainda não há comentários.