Este é o terceiro blog de uma série de blogs que abordam vários aspectos do que foi necessário para construir e operar nosso serviço SaaS :
Meu blog inicial forneceu algumas informações básicas sobre as necessidades que nos levaram a construir uma nova plataforma para nuvens distribuídas. Usando esta plataforma, nossos clientes criam um conjunto complexo e diversificado de aplicações — como manufatura inteligente, análise forense de vídeo para segurança pública, negociação algorítmica e redes de telecomunicações 5G.
Como muitas dessas aplicações são de missão crítica, nossos clientes esperam que não apenas forneçamos segurança multicamadas, mas também tenhamos a capacidade de fazer melhorias contínuas para manter seus clusters distribuídos seguros. Este blog específico abordará os desafios de proteger infraestrutura, aplicativos e dados em vários clusters.
Conforme declarado acima, o problema de proteger o acesso do usuário aos aplicativos (por exemplo, acesso às nossas contas bancárias ou aos nossos e-mails) é bem compreendido. No entanto, não é tão simples fazer o mesmo para acesso de aplicativo para aplicativo ou de aplicativo para dados, pois não há envolvimento humano no processo de verificação.
Para que um aplicativo acesse outro recurso de forma segura — por exemplo, dados armazenados em um repositório de objetos ou faça uma chamada de API para outro aplicativo, etc. — o seguinte precisa acontecer:
Como parte do processo de autenticação, o aplicativo solicitante pode apresentar sua identidade na forma de um certificado PKI ou um segredo (por exemplo, uma senha) ou uma chave. Há duas questões que precisam ser abordadas ao usar segredos ou uma chave para identidade:
Executar essas operações de segurança (para interação entre aplicativos) de maneira confiável e repetível não é um problema trivial. Há muitas razões pelas quais isto não é trivial:
Como resultado, proteger infraestrutura, aplicativos e dados em um ambiente dinâmico é um problema muito desafiador. Embora os provedores de nuvem tenham enfrentado esse desafio e fornecido muitas ferramentas para lidar com esses problemas, integrá-los e mantê-los não é fácil pelos seguintes motivos:
Embora muitas empresas sejam um único provedor de nuvem e possa ser suficiente para elas investir recursos no gerenciamento e aprimoramento dos princípios de segurança desse provedor, operamos em um ambiente heterogêneo (nuvem híbrida e de ponta) e tivemos que criar uma nova solução para resolver esses problemas.
Nossa equipe foi encarregada de fornecer segurança para os aplicativos, infraestrutura e dados que podem residir em uma infraestrutura distribuída, conforme mostrado na Figura 1.
Como resultado, nossa equipe de plataforma decidiu criar novos serviços de software que integrassem os quatro aspectos a seguir para fornecer segurança de plataforma em toda a borda, qualquer nuvem e nossos PoPs de rede:
A identidade é uma questão fundamental, pois muitos desafios de segurança podem ser enfrentados mais facilmente quando o problema de identidade é resolvido. Entretanto, para resolver o problema da identidade, precisamos definir o que queremos dizer com isso e como emitir identidade de maneira confiável. Os geeks de criptomoedas gostam de dar sua própria opinião sobre tudo, e a definição de identidade não é exceção:
O conjunto único e completo de características infalsificáveis e criptograficamente verificáveis , criptograficamente certificadas por meio de um protocolo seguro e não delegado por uma autoridade confiável, que compõem o que uma pessoa ou coisa é conhecida ou considerada.
Em essência, o que é necessário é uma identidade infalsificável e criptograficamente verificável, entregue com segurança. A emissão de tal identidade é desafiadora por dois motivos: 1) bootstrapping de identidade e 2) raiz de confiança
Existem algumas abordagens que são frequentemente discutidas em relação à identidade — SPIFFE e Hashicorp Vault. Gostaríamos de esclarecer que SPIFFE é um esquema de nomenclatura que pode ser usado em nosso sistema como um documento de identidade (certificado X.509) — no entanto, o formato não é adequado para alguns atributos de identidade que contêm dados binários. Embora o Vault possa ser usado para emitir um documento de identidade, ele não resolve os desafios do Bootstrapping de Identidade e do problema da Raiz de Confiança:
Por exemplo, quando uma VM é iniciada na AWS, ela recebe uma identidade bootstrap e o serviço de metadados da AWS atua como a raiz de confiança. O documento de identidade (que é assinado pela AWS usando sua própria chave criptográfica) se parece com isto:
Embora o instanceId possa denotar a identidade exclusiva da instância do aplicativo que foi iniciada, ele precisa ser encadeado a algum nome conhecido (myserver.acmecorp.com) que outros aplicativos usarão para se comunicar com essa instância específica. Como resultado, mesmo este documento de identidade do AWS bootstrap é insuficiente, mas pode ser usado para emitir outra identidade que pode ser usada pelos aplicativos para se comunicar com outro aplicativo.
Conforme declarado anteriormente, era fundamental para nós fornecer uma identidade que permitisse que os aplicativos se comuniquem e compartilhem informações entre provedores de nuvem e/ou locais de ponta (Figura 2). Isso significava que precisávamos criar um sistema para bootstrapping de identidade e raiz de confiança que funcionasse em todos esses ambientes.
Como usamos o Kubernetes para gerenciar e orquestrar aplicativos (microsserviços e VMs), isso significava que a criação de uma identidade única para cada pod lançado tinha que ser vinculada ao processo de criação de Pod do Kubernetes. A Figura 3 mostra como nos conectamos ao processo de criação de pods usando o mecanismo de webhook do K8s. Este webhook, chamado Voucher, injeta um sidecar de segurança, chamado Wingman , em todos os Pods criados no cluster e também fornece as informações criptograficamente assinadas necessárias que podem ser usadas como raiz de confiança . Este webhook fornece um token assinado de curta duração que é usado pelo Wingman para solicitar um certificado X.509 da Identity Authority no backend SaaS da Volterra.
A Autoridade de Identidade aplica as regras de cunhagem da identidade de uma forma que minimiza o “raio de explosão” no caso de um dos clusters K8s ser comprometido. Muitas outras soluções que dependem de uma CA raiz comum ou federação de clusters K8s não podem limitar o raio de explosão, o que foi um fator importante em nossa decisão de design.
Para um determinado Pod no K8s, os atributos podem mudar após a criação do Pod — Por exemplo, um Pod pode ser anexado a um novo serviço após sua criação. Isso significava que os certificados de identidade tinham que ser atualizados com o novo serviço. O Wingman monitora continuamente o Voucher que rastreia o servidor da API do K8s em busca de quaisquer atualizações.
Esse mecanismo fornece uma identidade global única e universal para cada instância de aplicativo em execução em nossa plataforma, independentemente de ser nossa própria carga de trabalho ou carga de trabalho do cliente. Essa identidade única e o sidecar (Wingman) são então usados para proteger toda a comunicação, acesso e chaves/segredos em um sistema distribuído.
Ter uma identidade única por Pod é um ótimo começo, pois facilita a tarefa de implementar autenticação mútua entre serviços de comunicação. Nossa infraestrutura subjacente é composta de muitos serviços diferentes que são executados em diferentes protocolos, como gRPC, REST, IPSec, BGP, etc. Desde o início, a equipe estabeleceu uma meta de alcançar autenticação mútua e segurança de comunicação (canal criptografado) para todas as partes que se comunicam, independentemente do protocolo. Isso também significava que não poderíamos vincular nossa identidade a uma solução (por exemplo, Istio) que se limitasse a um conjunto específico de protocolos (por exemplo, HTTP/TCP vs. Baseado em IP).
Como nossa plataforma também permite que os clientes executem cargas de trabalho de sua escolha, esperamos que essas cargas de trabalho possam executar uma variedade de protocolos e a plataforma não deve limitar sua capacidade ao fornecer uma identidade limitada a um conjunto específico de protocolos. Em vez disso, a autenticação é desacoplada da identidade (por meio do Wingman), o que possibilita a conexão com diversas tecnologias de malha de serviço. Nosso sidecar/dataplane de malha de serviço (abordado em um blog anterior) usa essa identidade para fornecer mTLS para cargas de trabalho do cliente.
Como muitos dos nossos próprios serviços de infraestrutura foram escritos usando o Volterra Golang Service Framework (a ser discutido em um blog futuro), decidimos criar a lógica de consumo de identidade (do Wingman) diretamente no framework. Isso ajudou nossos desenvolvedores a proteger suas comunicações de serviço para serviço imediatamente, sem depender do sidecar de malha de serviço para mTLS.
O próximo passo lógico após obter um canal seguro mutuamente autenticado é a Autorização — um processo para o receptor da solicitação (servidor) determinar se deve ou não permitir a solicitação vinda do chamador identificado (cliente). Os motivos para não permitir a solicitação podem ser muitos — limitações de cota, permissões, etc. Como esses motivos e seus limites mudam dinamicamente, um conjunto de regras (políticas) codificadas para autorização não era uma opção para nossa plataforma.
Decidimos usar o mecanismo do Open Policy Agent como ponto de partida e construímos um wrapper para autorização dentro do sidecar do Wingman. Este código wrapper busca as políticas relevantes dinamicamente e as mantém ativas para avaliação rápida. Semelhante à autenticação, desacoplar o mecanismo de autorização da identidade (e autenticação) nos permitiu aplicar políticas de autorização em vários estágios do processamento de solicitações, inclusive nas profundezas da lógica de negócios e não apenas imediatamente após a autenticação.
Como o Wingman é inserido em todas as cargas de trabalho, incluindo as cargas de trabalho do cliente, nossa plataforma fornece um mecanismo de autorização como um recurso integrado. Embora o Open Policy Agent (OPA) seja construído em uma linguagem poderosa chamada Rego, queríamos esconder sua complexidade de nossos desenvolvedores e clientes. Todas as políticas em nossa plataforma também podem ser definidas usando uma estrutura de política muito mais fácil de entender e intuitiva, que não exige que os usuários (DevOps) aprendam Rego e, portanto, evitem erros. Semelhante à configuração de autenticação, nosso Golang Service Framework foi conectado ao mecanismo de autorização do Wingman, chamando automaticamente o Wingman para autorização e ocultando a complexidade da autorização dos desenvolvedores.
Usando uma identidade única (emitida usando o Wingman) para autenticação e um mecanismo de política programável (dentro do Wingman) para autorização, podemos proteger a comunicação usando mTLS e controlar cada acesso usando uma política robusta e programável.
Todos os dias, engenheiros cometem erros inadvertidos ao armazenar chaves e senhas em seus códigos e, de alguma forma, eles chegam a repositórios públicos de códigos ou artefatos. Gerenciar segredos é difícil e, sem um kit de ferramentas fácil de usar e um processo bem definido, espera-se que os desenvolvedores sigam o caminho mais curto. Como resultado, desde o início da empresa, a missão da nossa equipe de segurança de plataforma (diferente da segurança de rede e aplicativo) era garantir que os desenvolvedores não precisassem fazer perguntas como "Onde eu armazeno segredos — código-fonte ou artefatos ou...?"
Avaliamos duas abordagens comuns que estavam disponíveis para nós para gerenciamento de segredos quando começamos a construir nossa plataforma, e ambas tinham certas deficiências:
No nosso caso, sendo um serviço SaaS, tivemos que criar um método mais robusto para proteger os segredos dos nossos clientes, pois qualquer comprometimento não deveria revelar seus segredos.
Como resultado, decidimos implementar uma nova técnica que chamamos de Volterra Blindfold (marca registrada), que funciona em conjunto com nosso sidecar de segurança, Wingman, conforme mostrado na Figura 4. Essa abordagem permite que o proprietário do segredo bloqueie (criptografe) o segredo de tal forma que ele nunca seja revelado abertamente a nenhuma parte indesejada (incluindo o servidor de descriptografia). O segredo nem mesmo é armazenado em um servidor central de descriptografia e esse design, em alguns aspectos, simplifica drasticamente o design do servidor.
Fornecemos aos usuários uma ferramenta de ocultação que pode ser usada em um ambiente completamente offline para criptografar o segredo (S), que pode então ser distribuído — por exemplo, o próprio segredo pode ser armazenado com a carga de trabalho e carregado no registro. Uma vez alcançado isso, as seguintes etapas precisam acontecer:
Isso garante que o plano de controle centralizado nunca tenha acesso ao segredo em claro (S) e também que o segredo só fique disponível na memória de tempo de execução do Pod durante o acesso. Além disso, a política de acesso pode ser aplicada para definir quem tem acesso a um segredo. A política pode ser definida com base nos atributos de identidade, como nome do aplicativo, localização, nível de conformidade etc. Dessa forma, qualquer subconjunto complexo de cargas de trabalho pode ser criado e um controle de acesso preciso pode ser alcançado. A política é criptograficamente incorporada ao processo de criptografia, ocultação, descriptografia e revelação — é computacionalmente inviável derrotar a intenção da política.
Usando nossa técnica exclusiva Blindfold para bloquear cada segredo e Wingman para revelar cada segredo com base em políticas e identidades infalsificáveis, conseguimos superar os problemas com soluções existentes e fornecer gerenciamento de segredos em um ambiente distribuído sem nunca nos preocuparmos com o comprometimento da mina de ouro central.
Embora segredos e gerenciamento de chaves possam soar como dois nomes diferentes para o mesmo problema, há diferenças sutis (mas importantes na prática) entre os dois, dependendo de quem você perguntar e como você deseja implementar as soluções.
Segredo refere-se a qualquer informação que supostamente é secreta e não está disponível para terceiros não autorizados. De certa forma, chaves criptográficas são um caso específico de segredos. Gerenciamento de Chaves, por outro lado, geralmente se refere a um sistema que armazena com segurança material de chave criptográfica sensível e controla o uso do material. Em alguns casos, o sistema de gerenciamento de chaves pode distribuir bytes brutos da chave para partes autorizadas e, portanto, pode ser confundido com um sistema de gerenciamento de segredos. Na maioria dos casos, no entanto, o sistema de gerenciamento de chaves não distribui bytes brutos do material da chave e, em vez disso, executa operações para solicitantes autorizados e envia apenas a saída da operação. Muitos sistemas de gerenciamento de chaves também contam com o suporte de armazenamento de hardware (por exemplo, HSM) para o material da chave, de modo que a chave nunca é exposta de forma clara ao software.
Em ambientes distribuídos, mesmo para um único provedor de nuvem, o problema de gerenciar, sincronizar e rotacionar chaves criptográficas é muito desafiador e as soluções atuais são propensas a erros, ineficientes e até mesmo inseguras. Por exemplo, se alguém usa 3 regiões da AWS hoje e quer usar a mesma chave de criptografia em todas as 3 regiões, será preciso sincronizar e girar as chaves manualmente. O problema se torna ainda pior quando o ambiente abrange vários provedores de nuvem (públicos e/ou privados). Mesmo depois de tudo isso ser dito e feito, os proprietários dos aplicativos ainda precisam escrever códigos complexos para usar esses recursos do KMS.
Nossa plataforma oculta todas as complexidades do gerenciamento de chaves do aplicativo, fazendo com que o sidecar do Wingman faça todo o trabalho pesado e forneça interface(s) simples ao aplicativo para fazer as solicitações de gerenciamento de chaves, incluindo criptografia, descriptografia, HMAC, verificação de HMAC, assinatura digital, verificação de assinatura, busca de chave (quando permitido) etc. Isso faz com que o gerenciamento de chaves não seja nada assustador para nossos próprios serviços de infraestrutura, bem como para as cargas de trabalho dos clientes.
O diagrama a seguir (Figura 5) mostra como o KMS da Volterra funciona em todos os ambientes e ajuda as cargas de trabalho a descarregar suas operações de gerenciamento de chaves e criptografia para o sidecar do Wingman. Dependendo da configuração, o Wingman é capaz de armazenar chaves em cache e atualizar o cache sem que o aplicativo saiba. O fator facilitador aqui é a identidade universal e infalsificável que apresentamos anteriormente. Como cada Pod, independentemente de sua localização, obtém uma identidade globalmente única, é fácil para o sistema Volterra KMS aplicar políticas de acesso a chaves de criptografia e operações específicas, como criptografia, descriptografia, HMAC, verificação de HMAC, assinatura digital e verificação de assinatura de maneira muito precisa.
Como todas as chaves são gerenciadas pelo backend SaaS da Volterra, as cargas de trabalho em execução em ambientes heterogêneos não precisam lidar com sincronização, rotação, revogação de chaves etc. — elas só precisam conhecer APIs simples do Wingman para todas as suas necessidades de segurança de dados em repouso.
Usando segurança de plataforma multicamadas, conseguimos fornecer uma solução abrangente para três problemas críticos de uma maneira totalmente nova! Nosso sistema é capaz de inicializar com segurança uma identidade universal que não sofre do problema de " tartarugas até o fim ", gerenciar segredos que podem ser armazenados e distribuídos sem nunca se preocupar com o problema da mina de ouro e fornecer gerenciamento de chaves para facilitar a segurança de dados em repouso em um ambiente distribuído. Isso levou aos seguintes ganhos para nossas equipes internas e também para nossos clientes:
Esta série de blogs abordará vários aspectos do que foi necessário para construir e operar nosso serviço SaaS distribuído globalmente com muitos clusters de aplicativos em nuvem pública, nossos PoPs de rede privada e sites de ponta. O próximo será Segurança de Aplicativos e Redes …
Estamos buscando alguns desenvolvedores voluntários e arquitetos de soluções para nos ajudar a levar esse recurso para uma comunidade mais ampla como um Projeto de Código Aberto. Entre em contato diretamente com asingla@voltera.io se tiver interesse em fazer parte de algo divertido!