BT

Disseminando conhecimento e inovação em desenvolvimento de software corporativo.

Contribuir

Tópicos

Escolha a região

Início Artigos Aumentando a segurança com um Service Mesh: explorando o Istio

Aumentando a segurança com um Service Mesh: explorando o Istio

Pontos Principais

  • O Istio ajudou a tornar o conceito de "service mesh" mais concreto e acessível, e com o recente lançamento da versão 1.0, podemos esperar um aumento no interesse por esta ferramenta;
  • O Istio tenta resolver alguns desafios difíceis ao executar aplicações em uma plataforma na nuvem: rede de aplicativos, confiabilidade e observabilidade;
  • Outro problema que o Istio soluciona é a segurança. Com o Istio, a comunicação entre services meshes é segura e criptografada por padrão;
  • O Istio também pode ajudar na verificação do token de identidade JWT de "origem" ou do "usuário final";
  • Esses recursos fundamentais de segurança abrem o caminho para a criação de redes de "confiança zero", na qual atribuímos confiança com base na identidade, bem como no contexto e nas circunstâncias, e não apenas no fato do "serviço solicitante estar na mesma rede interna".
     

O Istio ajudou a tornar o conceito de "service mesh" mais concreto e acessível, e com o recente lançamento de sua versão 1.0, podemos esperar um aumento no interesse por esta ferramenta. Jasmine Jaksic fez um ótimo trabalho ao introduzir o Istio e o Service Mesh no artigo "Istio and the Future of Service Mash" publicado no InfoQ, então gostaria de aproveitar a oportunidade para apresentar uma área específica do Istio que trará muito valor aos desenvolvedores e operadores de serviços e aplicações na nuvem: Segurança.

Casos de uso do Istio

O Istio tenta resolver alguns desafios difíceis ao executar aplicações em uma plataforma na nuvem, abordando, especificamente, questões relacionadas à rede de aplicações, confiabilidade e observabilidade. No passado, tentamos utilizar bibliotecas de aplicações criadas com único intuito de solucionar alguns desses desafios, como quebra de circuitos, balanceamento de carga no lado do cliente, coleta de métricas, entre outros. Fazer isso em diferentes linguagens, estruturas e tempos de execução, cria uma carga operacional quase proibitiva que a maioria das empresas não pode escalar.

Além disso, é difícil obter consistência entre as implementações encontradas em cada linguagem, nem pense em bloquear tudo quando for necessário aplicar alguma atualização de versão para fazer alterações ou corrigir bugs. Muitos desafios relacionados à confiabilidade, observabilidade e aplicação de políticas são questões horizontais e não são diferenciais nos negócios. Embora não sejam diferenciais diretos, ao negligenciá-los podemos causar um enorme impacto nos negócios e, por conta disso, precisamos resolvê-los. O Istio tem como objetivo resolver estes problemas.

A importância da segurança de rede

Outra preocupação horizontal difícil de ser resolvida pelas equipes de aplicações, é a segurança. Em alguns casos, a segurança é um item muito postergado e tentamos adicioná-la no momento mais avançado do projeto. Por quê? Porque implementar o modelo de segurança correto é difícil. Por exemplo, algo fundamental como "criptografar o tráfego das aplicações" é trivial, correto? A configuração do TLS/HTTPS nos serviços deveria ser simples, certo? Podemos ter experiências em projetos anteriores, ainda assim, fazer tudo corretamente, ao menos nos projetos em que trabalhei, não é uma tarefa tão fácil quanto parece. Temos os certificados necessários? São assinados por empresas certificadoras aceitas pelos clientes? Habilitamos as cipher suites corretas? Importamos isso para o truststore/keystore de maneira correta? Não seria mais fácil simplesmente ativar o flag "--insegure" na configuração TLS/HTTPS?

A configuração errada neste caso pode ser extremamente perigosa. O Istio fornece bastante ajuda neste assunto, pois implanta proxies sidecar (com base no proxy Envoy) ao lado de cada instância da aplicação que lida com todo o tráfego de rede. Quando uma aplicação tenta conversar com http://foo.com, o faz através do proxy sidecar (pela interface de rede de loopback) e o Istio redireciona esse tráfego para o proxy sidecar do outro serviço, que envia o tráfego para o próximo http, o http://foo.com. Ter estes proxies no caminho da requisição permite, por exemplo, criptografar o transporte automaticamente sem que a aplicação precise saber o que está acontecendo. Dessa forma, obtemos uma criptografia de tráfego aplicada de forma consistente, sem depender de cada equipe de desenvolvimento de aplicações para que tudo funcione corretamente.

Um dos problemas na instalação e manutenção de uma implementação de um TLS e mutual TLS para a arquitetura de serviços é o gerenciamento de certificados. O componente Citadel do Istio no plano de controle lida com a obtenção de certificados e chaves nas instâncias da aplicação. O Citadel pode gerar os certificados e as chaves necessárias para que cada carga de trabalho possa se identificar, além de alternar os certificados periodicamente para que aqueles que forem comprometidos tenham uma vida útil curta. Usando os certificados, os clusters habilitados para o Istio têm TLS mútuo automático. Podemos conectar a raiz de certificados da própria autoridade certificadora, caso seja necessário.

Com o Istio, a comunicação entre os service meshes é segura e criptografada por padrão. Não precisamos mexer nos certificados e nas cadeias das autoridades certificadoras para que o TLS funcione. Os operadores não precisam mais esperar e torcer para que cada desenvolvedor implemente e defina corretamente as configurações de TLS/HTTPS. Tudo é feito automaticamente por meio de algumas configurações do Istio.

Usando o Istio para ativar o mTLS

O Istio segue o mesmo caminho do Kubernetes para configuração. Na verdade, no Kubernetes, o Istio é configurado com objetos de definição de recurso personalizado (CRD, Custom Resource Definition). Os dois principais objetos para configurar as políticas de segurança do Istio são: Policy e DestinationRule. Policy são usados para definir as configurações de segurança de um serviço, ou grupo de serviços. Para configurar todos os serviços em execução no namespace do cliente no Kubernetes, podemos usar o seguinte Policy:

apiVersion: "authentication.istio.io/v1alpha1"
kind: "Policy"
metadata:
    name: "default"
    namespace: "customer"
spec:
    peers:

Quando usamos essa configuração, os serviços executados no namespace do cliente esperam que qualquer tráfego recebido use mTLS. Mas, para usar o mTLS, também precisamos sinalizar aos clientes que utilizem o mTLS quando chamarem um serviço. Para tal, usaremos uma DestinationRule no Istio. Uma DestinationRule é sempre usada para configurar como os clientes se comunicam com um serviço. Com uma DestinationRule, podemos especificar coisas como, quebra de circuito, balanceamento de carga e TLS. Para habilitar o mTLS, podemos usar uma configuração como esta: 

apiVersion: “networking.istio.io/v1alpha3”
kind: “DestinationRule”
metadata:
  name: “default”
  namespace: “foo”
spec:
  host: “*.customer.svc.cluster.local”
  trafficPolicy:
    tls:
      mode: ISTIO_MUTUAL

Essa DestinationRule exigirá que os clientes usem o mTLS ao fazer chamadas para serviços no namespace do cliente. Também estamos configurando o modo do TLS para ser ISTIO_MUTUAL, ou seja, esperamos que o Istio gerencie os certificados e as chaves, além de montá-los nos serviços, usando o Kubernetes secrets para que o service proxy possa utilizá-los para estabelecer o TLS. Se quiséssemos ter o controle sobre os certificados do cliente, poderíamos usar o modo MUTUAL e também fornecer a localização no disco onde o cliente pode encontrar seus certificados e chaves privadas.

Usando o Istio para validar a identidade de origem (com o JWT)

Quando usamos o mTLS como descrito anteriormente, não somente podemos criptografar a conexão, mas, o mais importante, também é possível saber exatamente quem está chamando quem. O Istio usa a especificação SPIFFE (Secure Production Identity Framework for Everyone) para este serviço. As identidades são codificadas nos certificados usados para o mTLS. Dessa forma, o serviço A sabe quando o serviço B está se comunicando com ele, e tem certeza que, de fato, é o serviço B que está enviando as informações. Podemos escrever regras em torno dessas identidades sobre quais regras ou políticas o service mesh deve aplicar. Por exemplo, se o serviço A não tem permissão para chamar o serviço B, podemos garantir que a regra seja seguida utilizando os sidecars que são executados paralelamente à cada aplicação por meio das identidades usadas para estabelecer o mTLS.

Mas o que acontece quando o serviço A está solicitando o serviço B em nome do usuário X? Se o serviço A tem permissão para chamar e pedir ao serviço B para fazer alguma coisa (verificar saldos na conta, por exemplo), mas o usuário X não tem permissão, como podemos verificar e fazer a regra ser cumprida? Em uma arquitetura de serviços, a identidade do usuário final ou de origem (o usuário conectado) é tipicamente comunicada por meio de tokens de identidade como JSON Web Tokens. Esses tokens são fornecidos para representar um usuário autenticado e as declarações que possui.

O Istio pode ajudar na verificação do token de identidade JWT "origem" ou "usuário final". Essa é outra área em que cada combinação de linguagem/estrutura de aplicação, historicamente, teve que confiar em bibliotecas para lidar com a verificação e descompactação dos tokens JWT. Por exemplo, para o popular projeto Keycloak Identity e SSO, há plugins para cada linguagem popular, a fim de que possam lidar com essa responsabilidade. Se estivermos usando o Istio, podemos obter esse tipo de funcionalidade gratuitamente. Por exemplo, a configuração do Istio para usar mTLS e verificar o token JWT em uma solicitação (e cancelar a solicitação se esta não existir, for inválida ou tiver expirado), podemos configurar um Policy. Precisamos lembrar também que os Policies especificam o comportamento que queremos dos serviços:

apiVersion: “authentication.istio.io/v1alpha1”
kind: “Policy”
metadata:
  name: “customer-jwt-policy”
spec:
  targets:
  - name: customer
  peers:
  - mtls:
  origins:
  - jwt:
      issuer: http://keycloak:8080/auth/realms/istio
      jwksUri: http://keycloak:8080/auth/realms/istio/protocol/openid-connect/certs
  principalBinding: USE_ORIGIN

Com essa configuração, se um cliente tentar se conectar ao serviço do cliente, a solicitação não chegará ao serviço, a menos que seja autenticado pelo JWT. Outro ponto positivo sobre a implementação do Istio é que a solicitação também é protegida pelo mTLS. Isso ajuda a proteger o token JWT de ser hackeado e ser usado para algum tipo de ataque de repetição.

O futuro: redes de confiança zero

Cobrimos algumas maneiras pelas quais o Istio pode melhorar a postura de segurança ao criar aplicações nativas na nuvem. Com forte identidade nos serviços transitando informação entre si, bem como tokens de origem e de usuário final, podemos escrever algumas regras poderosas de controle de acesso sobre como o sistema pode se comportar. Esse princípio abre caminho para a construção de redes de "confiança zero", na qual atribuímos confiança com base na identidade, bem como no contexto e nas circunstâncias, e não apenas na ideia de que "o requisitante está na mesma rede interna". Quando começamos a avançar em direção a modelos de implantação em nuvem totalmente conectados e híbridos, precisamos repensar a melhor forma de incorporar a segurança nas arquiteturas. O Istio pode resolver estes desafios, além de oferecer mais opções no futuro.

O Istio fornece alguns recursos muito poderosos para solucionar problemas que as equipes de serviço terão que resolver de uma maneira ou de outra. Provê APIs agradáveis e objetos de configuração para realizar o trabalho fora dos serviços da aplicação. É implementado de uma maneira altamente descentralizada e pretende ser altamente resiliente a falhas. Se adotarmos um service mesh e estivermos considerando a segurança como ponto principal, é importante darmos uma olhada no Istio.

Sobre o autor

Christian Posta (@christianposta) é arquiteto-chefe de aplicações em nuvem na Red Hat e é conhecido na comunidade por ser o autor dos livros: Introducing Istio Service Mesh - O'Reilly 2018 e Microservices for Java Developers - O'Reilly 2016, além de ser blogueiro, palestrante, entusiasta do open source e estar presente em vários projetos open source, incluindo Istio, Apache ActiveMQ, Fabric8, entre outros. Christian passou um bom tempo em empresas de Web-scale e agora ajuda a criar e a implantar arquiteturas distribuídas de larga escala e resilientes, muitas das que chamamos de microservices. Gosta de orientar, treinar e liderar equipes para obter sucesso com conceitos de sistemas distribuídos, microservices, devops e design de aplicações nativos na nuvem.

Avalie esse artigo

Relevância
Estilo/Redação

Conteúdo educacional

BT