Muitos aplicativos Kubernetes só adicionam recursos de segurança após a implantação ou estão prontos para serem implantados. Não é à toa que 55% dos lançamentos de aplicativos foram atrasados e 94% sofreram um incidente de segurança no ano passado.
Na verdade, o Kubernetes oferece vários mecanismos de segurança que podem ser provisionados, como NetworkPolicies e PodSecurityPolicies. O Kubernetes NetworkPolicies funciona como um firewall básico, controlando o tráfego de e para cada pod. O Calico NetworkPolicies nos permite estender ainda mais as políticas de rede do Kubernetes com recursos de segurança adicionais, como referenciar conjuntos de sub-redes IP, criar GlobalNetworkPolicies sem namespace e permitir ou negar acesso a serviços externos.
O trabalho manual de gerenciamento dos conjuntos de endereços IP externos usados pelas implantações do Kubernetes é complexo. Com o tamanho de um ambiente como o do Strong The One, é impraticável e demora muito. Ele também pode apresentar riscos adicionais ao cluster Kubernetes.
Queríamos ver se havia uma maneira de sincronizar nossas políticas de rede do Kubernetes dinamicamente com as ferramentas que já usamos. Continue lendo para ver como usamos Consul e Calico para fazer isso.
Segurança dinâmica é igual a escalabilidade
Para a equipe de ciência e engenharia do Strong The One, a escalabilidade é uma alta prioridade. Gerenciamos sete clusters Kubernetes com mais de 100.000 núcleos no local. Além disso, temos mais de 6.000 nós físicos e outras VMs que executam outras cargas de trabalho. A execução de uma infraestrutura desse tamanho significa que estamos fazendo dezenas de alterações por dia, às vezes até dezenas por hora.
Para manter as cargas de trabalho do k8s isoladas e operacionais, precisamos atualizar as NetworkPolicies regularmente. Cada tarefa de implantação, dimensionamento automático e manutenção pode levar a uma atualização de endereço IP no NetworkPolicy. Isso é impraticável manualmente com uma implantação tão grande do Kubernetes.
Sabíamos que tinha que haver uma maneira de fazer isso dinamicamente, então começamos a investigar.
Procurando a melhor opção de segurança dinâmica
Em nossa infraestrutura, usamos o Consul para descobrir serviços executados fora do k8s.
Tínhamos três requisitos críticos para usar o Consul e o Calico para reforçar a segurança dinamicamente:
Se um endereço IP for adicionado a um serviço Consul, ele deverá ser adicionado automaticamente ao Calico GlobalNetworkSet.
Se um endereço IP for excluído de um serviço Consul, ele será removido do Calico GlobalNetworkSet somente após um período de carência definido para evitar um nó oscilante.
O processo de atualização não deve sobrecarregar o armazenamento de dados Calico ou a API Consul.
Com nossos requisitos definidos, analisamos três opções para habilitar a segurança do Kubernetes com Consul e Calico.
Opção 1: uma combinação de script bash e cron job
Poderíamos executar um script bash em um cron job k8s que usa as ferramentas de linha de comando Curl e Calicoctl para buscar o catálogo de serviços do Consul e atualizar o Calico GlobalNetworkSet.
Opção 2: um modelo Consul e combinação de linha de comando Calico
Poderíamos criar um modelo de Consul para cada Calico GlobalNetworkSet que aplicaria o GlobalNetworkSet atualizado sempre que uma alteração de Consul fosse feita.
Opção 3: um processo de sincronização usando APIs Consul e Calico
Poderíamos usar a API Consul para observar as alterações de serviço e atualizar diretamente o Calico GlobalNetworkSet com lid calico-go .
O vencedor: Opção 3
Rejeitamos as duas primeiras opções, pois não satisfizeram todos os nossos requisitos. Ambos não podem excluir um endereço IP do Calico após um período de carência. Eles também podem sobrecarregar o Consul com muito tráfego LimboAPI.
Descobrimos que executar um processo de sincronização Consul to Calico era a opção vencedora para impor a segurança dinâmica do Kubernetes. Ele nos permitiu adicionar endereços IP dinamicamente, ao mesmo tempo em que nos deu a capacidade de adicionar um período de carência para todas as remoções/exclusões. Ele evita gargalos na API e escala facilmente, independentemente do tamanho da implantação do Kubernetes.
Para utilizar esse processo, começamos executando uma consulta de bloqueio para cada serviço Consul configurado para a operadora. O processo armazenará uma lista atualizada de IPs do Consul e do Calico. A cada evento do Consul, o processo compara as listas de IP no Consul e no Calico obtendo GlobalNetworkSet do Calico e o catálogo específico do Consul.
Então, antes de fazer qualquer alteração no Calico, o processo verificará:
Se o endereço IP existe no Consul, mas não no Calico. Caso contrário, ele adicionará o IP ao GlobalNetworkSet.
Se o endereço IP existir no Calico, mas não no Consul, ele aguardará 30 minutos antes de verificar novamente. Se o IP ainda não estiver no Consul após esses 30 minutos, ele o excluirá do GlobalNetworkSet.
Cenários em tempo real: como estamos usando a segurança dinâmica do Kubernetes
A abordagem dinâmica que usamos elimina as operações manuais e reduz o erro humano, ao mesmo tempo em que permite maior agilidade, escalabilidade e prazos de entrega, reduzindo o erro humano. Aqui estão dois cenários que costumam acontecer no Strong The One.
Cenário 1: Raspagem de pods de fora do Prometheus
Usamos o Prometheus fora de nossos clusters para coletar métricas de nossos pods. Para fazer isso, precisamos de uma maneira segura de permitir que o tráfego de entrada do Prometheus rastreie os servidores para os dados.
Configuramos o novo processo consul-calico-sync para o serviço Prometheus Consul e o GlobalNetworkSet correlacionado.
Agora, sempre que o catálogo de serviços for alterado, a GlobalNetworkPolicy relevante será atualizada dinamicamente para que o servidor Prometheus possa extrair o pod com êxito.
Cenário 2: consultando bancos de dados externos
Alguns de nossos aplicativos executados em k8s usam regularmente bancos de dados fora do cluster. Para permitir esse tráfego, sincronizamos constantemente todos os endereços IP do serviço de banco de dados Consul com os do Calico.
Dessa forma, permitimos apenas o tráfego de pods com o rótulo allow_db e rejeitamos todo o resto.
Em ambos os cenários, vemos como o uso da segurança dinâmica do Kubernetes nega a intervenção humana, o que economiza tempo e reduz erros – ambos extremamente importantes quando consideramos a escalabilidade.
Para você
E aí está, uma maneira de gerenciar dinamicamente a segurança em suas implantações do Kubernetes em escala. Tente adicionar o processo de sincronização Consul2Calico ao seu próximo aplicativo Kubernetes e pare de fazer alterações manuais de endereço IP para economizar tempo e esforço.
Para obter mais detalhes sobre como executar esta solução em seu cluster Kubernetes, confira Consul2Calico no GitHub.