Como a arquitetura de microserviços pode influenciar na segurança e confiabilidade

A arquitetura de microserviços deixou de ser apenas uma tendência para se tornar um padrão em muitos sistemas de grande escala. Ao quebrar aplicações monolíticas em serviços independentes, ela traz ganhos de escalabilidade e velocidade de entrega. Para mim, a grande vantagem da arquitetura de microserviços é como ela facilita o design de uma arquitetura orientada a domínios (DDD) e isso tem diversos impactos positivos como a diminuição da dependência entre os times e da carga cognitiva que cada pessoa precisa absorver. Isso permite que cada equipe possa avançar mais rápido na experimentação e entrega de features. Mas há um aspecto que eu não costumava considerar que é como a arquitetura de microserviços pode facilitar algumas práticas de desenvolvimento de sistemas seguros e confiáveis.

A adoção de arquitetura de microserviços traz características estruturais que tornam mais fácil incluir aspectos de segurança pelo seu próprio design.

Isolamento

Cada microserviço é um contexto com fronteiras bem definidas, limites muito claros. Esta divisão do sistema em contextos menores é um facilitador para adoção de alguns princípios de construção de sistemas seguros e confiáveis.

Zero Trust Networking (ZTN)

“Never trust, always verify”.

Em abordagens mais antigas, os sistemas implementavam um modelo de segurança baseado no conceito “castle-and-moat”. Ou seja, tudo que está dentro da rede é, por default, confiável. Logo, se houver alguma falha que comprometa um componente desta rede, é fácil que o atacante/invasor alcance os demais componentes uma vez que dentro da rede tudo é confiável. Exemplo: uma vulnerabilidade do sistema catálogo pode ser usada para explorar a parte de pagamentos (movimentação lateral).

Na abordagem ZTN, não se assume que a rede interna é segura. As interações entre os componentes desta rede são sempre autenticadas e autorizadas. Logo, é necessário estabelecer fronteiras bem definidas entre estes componentes para permitir este controle granular. Logo, quanto maior a quantidade de componentes/funcionalidades estão dentro de uma mesma fronteira, maior será o alcance de um falha de segurança.

Com a arquitetura de microserviços, cada serviço é pequeno, com fronteiras bem definidas e com banco de dados próprio. Ou seja, permite isolar os componentes de uma forma bem granular. Além disso, a interação dos microserviços se dá por APIs ou mensageria o que torna fácil aplicar camadas de autenticação e autorização nesta comunicação.

Least privilege

O alinhamento do uso de microserviços com arquitetura orientada a domínios (DDD) facilita a aplicação do least privilege pois conseguimos um controle sobre a comunicação entre eles. A autenticação e autorização da abordagem ZTN permite configurações granulares que evitam a movimentação lateral de um possível atacante.

Além disso, a aplicação do princípio de least privilege no nível organizacional também é facilitada. Na arquitetura de microserviços, cada domínio tem um time responsável. Ou seja, somente times que realmente precisam, que são responsáveis por aquele domínio devem ter acesso aos componentes do mesmo.

Observabilidade e resiliência

Para um sistema ser confiável, é essencial que tenha observabilidade: logs, métricas, traces e etc que nos permita entender o estado da aplicação em tempo real.

Quando o sistema é grande, não há separação clara entre os componentes e logs/métricas/traces ficam misturados e dificultam a identificação da origem de um problema. Isso cria pontos cegos fazendo com que comportamentos indesejados passem despercebidos ou sejam identificados tarde demais. Se alguma vulnerabilidade é explorada em grandes sistemas, é mais difícil saber como isso foi feito, como foi a movimentação dentro do sistemas pois a comunicação entre os componentes são apenas chamadas internas de funções ou métodos. Isso atrapalha a análise pós-incidente (post-mortem).

Na arquitetura de microserviços, estes pontos são atenuados uma vez que os componentes são pequenos e com fronteiras bem definidas. Logo, logs/métricas/traces são mais precisos facilitando a identificação dos problemas. Esta segregação também permite que a análise pós-incidente seja mais fácil uma vez que a comunicação entre os componentes é rastreável.

Facilidade de manutenção e correções rápidas

Cada microserviço possui mecanismos de deploy independentes. Como as responsabilidades e área de atuação de cada microserviço são pequenas, quando a comparadas a outra arquiteturas, isso traz mais segurança para o time realizar deploys com mais frequência. É mais fácil monitorar a nova versão e, em caso que um erro seja introduzido, o impacto é limitado.

A observabilidade mais eficiente e a facilidade de deploy são vitais para identificar problemas rapidamente e aplicar correções de qualquer natureza, inclusive de segurança.

Compreensibilidade

Quanto mais difícil é entender um sistema, maior a chance de uma pessoa engenheira, acidentalmente, introduzir um bug, uma vulnerabilidade ou alguma coisa que comprometa a resiliência do mesmo. A pessoa engenheira pode ter um entendimento errado de um determinado comportamento da aplicação ou desconhecer algum aspecto que não foi documentado que entra em conflito com a modificação que está sendo feita.

Um sistema composto de pequenos módulos onde cada um tem propósitos claros e bem definidos é mais fácil de entender. Desta forma, o time tem mais confiança nas mudanças que faz, diminuindo o risco de que a nova versão tenha problemas. E esta confiança também impacta a atuação em emergências. Se é mais fácil de entender cada módulo e as interações entre eles, o MTTR (Mean time to repair) é reduzido pois as etapas de compreensão e atuação ganham velocidade.

Então é só adotar microserviços com com arquitetura DDD que temos “security by construction”?

Não. ☹️ Mas se você aproveita as características de microserviços, já consegue trazer características de segurança e confiabilidade para seu sistema. Não adianta dividirmos o sistema em microserviços se os mesmos não possuem autenticação forte entre si, proteções como rate limiting, quota management, burst control, input validation e etc.

É claro que a adoção de uma arquitetura de microserviços possui pontos negativos. Considerando principalmente confiabilidade e segurança, temos:

  • maior superfície de ataque uma vez que temos mais endpoints
  • aumento da complexidade operacional:
    • logs e métricas ficam distribuídos tornando mandatório a adoção de boas ferramentas para gerenciar isso.
    • é mais difícil garantir a compatibilidade entre as versões de cada microserviço pois cada um tem seu ciclo de vida próprio.
    • a adoção de uma ferramenta de gerenciamento de credenciais torna-se mandatória uma vez que cada microserviço tem suas credenciais que só podem ser acessadas por ele.
    • gestão de autenticação e aplicação de least privilege entre serviços é mais complexa.

Importante sempre ressaltar que “One size does not fit all”. Cada indústria, time, produto tem aspectos únicos que precisam ser considerados. Além disso, o momento do produto também influencia muito. As necessidades de segurança e confiabilidade para um produto que está sendo testado no mercado é completamente diferente de produto utilizado por milhões de pessoas espalhadas pelo mundo inteiro.

Independentemente destes fatores, analisar a adoção de microserviços e arquitetura DDD em relação a requisitos de segurança e confiabilidade é muito interessante e enriquecedor para nossa caixa de ferramentas no desenvolvimento de software.

Referência:

ADKINS, Heather; BEYER, Betsy; BLANKINSHIP, Paul; LEWANDOWSKI, Piotr; OPREA, Ana; STUBBLEFIELD, Adam. Building Secure & Reliable Systems. California: O’Reilly Media, 2020. Link

Deixe um comentário

Este site utiliza o Akismet para reduzir spam. Fica a saber como são processados os dados dos comentários.

Site no WordPress.com.

EM CIMA ↑