Gerenciando segredos com o HashiCorp Vault

Como guardar segredos? No repositório, no sistema de implantação ou no sistema de gerenciamento de configuração? Em um computador pessoal, em servidores ou talvez em uma caixa debaixo da cama? E como gerenciar segredos para evitar vazamentos?

Sergey Noskov ( Albibek ) - o chefe do grupo de segurança da informação da plataforma da Avito , sabe a resposta para essas perguntas e compartilhará conosco. No Avito, o HashiCorp Vault tem usado ativamente o HashiCorp Vault por dois anos, durante os quais obtiveram solavancos e aumentaram a experiência para o nível "Master".

No artigo, falaremos de maneira abrangente sobre o Vault: o que é, onde e como é usado na empresa, como o Avito gerencia segredos usando o HashiCorp Vault, como o Puppet e o Kubernetes são usados, casos de uso com o Puppet e outros SCM, que problemas surgem, o que prejudica a segurança desenvolvedores e, é claro, compartilham idéias sobre como corrigi-lo.


O que é um segredo?


Qualquer informação confidencial:

  • login e senha, por exemplo, para o banco de dados;
  • Chaves de API
  • Chave de certificado do servidor (* .google.com)
  • chave de certificado de cliente (parceiros, dinheiro Yandex, QIWI);
  • chave para assinar aplicativos móveis.

Todas as informações que queremos manter em segredo, chamamos de segredo. Isso cria um problema de armazenamento: é ruim armazenar no repositório, na forma criptografada - você precisa manter as chaves de criptografia em algum lugar.

O HashiCorp Vault é uma das boas soluções para o problema.

  • Armazena e gerencia chaves com segurança.
  • Afiado no mundo dos microsserviços, desde o próprio microsserviço.
  • O HashiCorp Vault fez muito para autenticar e autorizar o acesso a segredos, como ACLs e o princípio de privilégios mínimos.
  • Interface REST com JSON.
  • A segurança não é perfeita, mas em um nível bastante alto.

Na minha opinião, esta é uma ferramenta bastante conveniente.

Novidades no HashiCorp Vault


A ferramenta está em desenvolvimento e, nos últimos anos, muitos recursos interessantes apareceram nela: cabeçalhos CORS para GUI sem intermediários; GUI embutida; integração nativa com o Kubernetes; plug-ins para backends e estrutura lógicos e de autenticação.

A maioria das mudanças que eu pessoalmente gostei é a capacidade de não escrever extensões e adições que ficarão fora da ferramenta.

Por exemplo, existe o Vault, você deseja expandi-lo - escreva uma lógica adicional ou sua própria interface do usuário para automação, o que automatizará algo. Antes das alterações, eu tive que criar um serviço adicional que o Vault enfrenta e proxies todas as solicitações: primeiro as solicitações vão para o serviço e depois para o Vault. Isso é ruim porque no serviço intermediário pode haver um nível reduzido de segurança e todos os segredos passam por ele. Os riscos de segurança são muito maiores quando o segredo passa por vários pontos ao mesmo tempo!

Problema de galinha e ovo


Quando você levanta a questão do armazenamento de informações confidenciais e decide criptografar, assim que você criptografa algo, seu segredo muda do local de criptografia para o local onde a chave está armazenada. Isso acontece o tempo todo: assim que você salva um segredo em algum lugar ou muda um existente, você tem outro e um círculo encantado começa - onde guardar o segredo para ter acesso ao segredo .

O segredo para acessar o segredo é a parte da segurança chamada autenticação . A segurança tem outra parte - autorização. No processo de autorização, é verificado se o usuário pode acessar exatamente onde está solicitando. No caso do Vault, existe um terceiro confiável que decide se deve revelar o segredo ou não. A autorização resolve apenas parcialmente o problema.

HashiCorp Vault em Avito


No Avito, o HashiCorp é instalado na única instalação grande em toda a rede. O HashiCorp Vault possui muitos recursos diferentes. Usamos o back-end baseado no Consul também da HashiCorp, porque o Vault pode suportar apenas sua própria tolerância a falhas através do Consul.

A remoção do lacre é uma maneira de não manter a chave mestra em um só lugar. Quando o Vault é iniciado, ele criptografa tudo em uma chave e, novamente, o problema do ovo e da galinha aparece: onde guardar um segredo, que criptografará todos os outros segredos. Para evitar esse problema, o Vault fornece uma chave composta, que requer várias partes da chave, que distribuímos para vários funcionários. No Avito, configuramos o Unseal nas opções para 3 pessoas em 7. Se iniciarmos o Vault, pelo menos 3 pessoas deverão entrar e inserir sua parte da chave para que ele comece a funcionar. A chave é dividida em 7 partes e você pode trazer qualquer uma delas.

Reunimos um pequeno Vault de teste, uma caixa de areia para desenvolvedores onde eles podem jogar. É na forma de um contêiner do Docker e cria segredos simples para que as pessoas possam tocar na ferramenta com as mãos e se sentirem confortáveis. Não há Consul e clustering na sandbox, é apenas um sistema de arquivos no qual o Vault contém segredos criptografados e um pequeno script para inicializar.

Aqui está o que agora armazenamos no Vault:

  • Quase todos os segredos dos microsserviços do Kubernetes: senhas de bancos de dados, chaves de API, todas as opções acima.
  • Segredos para colocar nos servidores "de ferro" e no LXC.
  • Também colocamos segredos para compilações de CI / CD no TeamCity no Vault. A cobertura não é 100%, mas é aceitável.
  • As chaves de todos os certificados: PKI interna, CAs externas, por exemplo, GeoTrust e similares.
  • Segredos comuns para as equipes.

Por dentro, o Vault armazena tudo apenas em JSON, nem sempre é conveniente e requer ações adicionais do desenvolvedor, portanto, basicamente, publicamos segredos na forma de um arquivo.

Tentamos entregar segredos na forma de arquivos.

Não dizemos ao desenvolvedor: "Vá para o Vault, pegue um segredo!", Mas coloque o arquivo no disco e diga: "Desenvolvedor, um arquivo aparecerá no seu disco, tire o segredo dele e já descobriremos como obtê-lo do Vault e trazê-lo para você. "


Adotamos um contrato simples para os campos JSON, nos quais indicamos com quais direitos o upload do arquivo. Esses são metadados para o sistema de arquivos, e o campo de dados é uma sequência codificada com o próprio segredo, que se tornará o conteúdo do arquivo.

Fantoche + Hiera + Cofre


Quase toda a infraestrutura Avito usa Puppet, lança todos os servidores.

O Puppet tem uma ferramenta conveniente para organizar hierarquias - Hiera . O Vault se integra muito bem ao Hiera por meio de um módulo complementar, porque uma solicitação de valor-chave é enviada para esta biblioteca e o próprio Vault é um banco de dados de valores-chave, mas com todos os recursos de segurança - com criptografia transparente e a capacidade de escolher o acesso às chaves.

Portanto, a primeira coisa que implementamos é o Vault in Puppet, mas com uma adição - temos uma camada intermediária chamada de roteador back-end . Back-end do roteador - um módulo Hiera separado, apenas arquivos no disco que indicam onde Hiera deve buscar a chave - no Vault ou em outro local.

Ele é necessário para que Hiera não vá ao Vault constantemente, porque ela sempre percorre toda a hierarquia. Este não é um problema do Vault ou carrega nele, mas um recurso do próprio Hiera. Portanto, se você deixar apenas o módulo para o Vault sem o back-end do roteador, o mestre do Puppet levará muito tempo para coletar a configuração do agente Puppet, pois verificará cada chave no Vault.


Para o Puppet, o problema da galinha e dos ovos é resolvido devido ao fato de a parte autorizadora ser o mestre do Puppet. É ele quem dá o segredo para acessar o segredo. O mestre de marionetes tem acesso a todos os segredos de uma só vez, mas cada host pode receber apenas o que se destina a ele. O host no mestre do Puppet já está autorizado por seu certificado, que é gerado localmente e não deixa os limites do host. Em princípio, o segredo para acessar o segredo permanece, mas isso não é tão crítico.

Nosso processo de revelar um novo segredo no Puppet consiste nas seguintes etapas.

  • Nós levamos um segredo para algum lugar - alguém nos dá ou o divulga.
  • Colocando um segredo no Vault, com uma hierarquia como em Hiera: /puppet/role/www/site.ssl.key .
  • Registramos um prefixo no manifesto Puppet, indicando que o arquivo está no Vault e onde obtê-lo.
  • Escrevemos o caminho no Vault no YAML para o roteador Hiera e o back-end para que Hiera possa encontrá-lo.
  • Puxe a solicitação via GIT para o repositório de manifesto.
  • Execute ou aguarde a execução do agente Puppet.

Agentes de marionetes fogem conosco a cada 30 minutos, então você deve esperar um pouco até que o segredo seja revelado. Isso não causa problemas - não compartilhamos segredos todos os dias . Desde que a Kubernetes não esteja envolvida nos negócios, não há muita sobrecarga e estamos prontos para colocar segredos no Vault com nossas mãos com automação mínima.

Além disso, obtemos o "chip" Hiera - o segredo pode ser divulgado imediatamente para um grupo de hosts ou dependendo do papel do host, definido na função variável.

O único perigo : se você tem o Puppet e usa o Hiera, não substitua nada por modelos de variáveis, porque muitos fatos e variáveis ​​são coletados no lado do cliente. Se um atacante substituir um fato no cliente, o mestre dos Marionetes lhe dará os segredos de outras pessoas. Certifique-se de verificar as variáveis : use apenas aquelas que o Puppet-master não permite determinar no lado do cliente.

O que fazer com o SCM sem um assistente?


Se de repente você não tem Marionete, provavelmente Ansible. Para Chef e outros SCMs centralizados, suas soluções são um plug-in que pode acessar o Vault. Eu ofereço várias opções que podem ser implementadas com o Ansible.

Agente local


Localmente para o servidor, gere um token, que é realmente a senha para acessar o Vault. O token é válido o tempo todo. Você pode atualizá-lo ou automatizá-lo. Com esse token, você vai ao Vault e tira seus segredos.

A ideia é que, no servidor em que você precisa entregar segredos, o agente que vem ao Vault esteja girando, analise todos os segredos e os coloque na forma de arquivos. Usamos o agente em vários servidores separados onde não há Puppet.

Contras:

  • É fácil inserir o token em um segmento pequeno, mas se você tiver várias dezenas de servidores implantados por dia, precisará gerar um token para cada servidor e prescrever uma política. Isso é inconveniente.
  • O token precisa ser atualizado.
  • O agrupamento de servidores por função, objetivo ou fato é difícil, ele deve ser sincronizado com o Vault.

Criptografia de trânsito


O Vault possui uma função de criptografia de trânsito, cuja essência é que o Vault atua como um servidor de criptografia . Você apenas traz a ele texto simples, e ele, em sua chave privada, que somente ele possui, criptografa e emite o texto fechado. Então você escolhe quem pode descriptografar este texto fechado.

Ansible tem uma entidade, também chamada Vault. Este não é um cofre HashiCorp, mas um cofre Ansible . Não há necessidade de confundir, e os segredos podem ser armazenados no primeiro e no segundo. O Ansible possui um plugin pronto para fornecer segredos do Hashicorp Vault. Se você der acesso pessoal ao Vault, poderá descriptografar segredos. Quando você lança o Ansible, ele acessa o Vault em seu nome, descriptografa os segredos que são criptografados no repositório e os lança em produção.

Há também uma desvantagem - cada administrador obtém acesso a segredos . Mas há uma auditoria: o Vault sabe como manter um log de atividades sobre qual usuário entrou, qual segredo leu, qual teve acesso. Você sempre sabe quem, quando e o que fez com um segredo. Esta opção parece boa para mim.

Grande falha # 1


A maior desvantagem que causa a maior dor em nós é que no Vault você não pode delegar o controle total de nenhuma parte dos dados a ninguém. No Vault, o acesso ao segredo é realizado de maneira semelhante à do UNIX - os nomes geralmente são separados por barras, e o resultado é um "diretório". Quando você tem esse caminho, às vezes deseja participar do caminho e entregá-lo a outra pessoa para controle.


Por exemplo, você possui certificados chamados / certs e deseja entregá-los a agentes de segurança individuais que lidam com a PKI. O Vault não pode fazer isso. Você não pode dar o direito de emitir direitos dentro desse prefixo - para que os próprios seguranças possam distribuir os direitos dos certificados para outra pessoa.

O Vault não tem a capacidade de conceder seletivamente direitos para conceder direitos . Assim que você concedeu o direito de conceder direitos, também teve a oportunidade de obter acesso total a todos os segredos. Em outras palavras, você não pode dar acesso à parte do Vault.

Este é um dos maiores problemas. Eu tenho uma idéia de como resolvê-lo, falarei sobre isso mais tarde.

Kubernetes


No RIT ++, falei sobre um sistema separado que implementamos para o Kubernetes : ele serve como terceiro, acessa a API, verifica o acesso e solicita um segredo no Vault.

Agora, nosso sistema perdeu relevância, porque no Vault 0.9, o suporte nativo ao Kubernetes apareceu. Agora, o próprio Vault sabe como acessar o Kubernetes e garantir que o acesso ao segredo seja permitido. Ele faz isso com um token de conta de serviço . Por exemplo, quando você tem um pod implementado, há um JWT especial, assinado e autorizado para ele, projetado para solicitações à API do Kubernetes. Com um token, você também pode fazer login no Vault e obter segredos especificamente para o seu espaço para nome.

Tudo é feito no nível do Vault. É verdade que será necessário iniciar uma função para cada espaço para nome, ou seja, informar ao Vault que existe um espaço para nome, haverá autorização nele e registrar para onde ir no Kubernetes. Isso é feito uma vez e, em seguida, o Vault acessa a API, confirma a validade do JWT e emite seu próprio token de acesso.

Regras do Kubernetes


Em termos de nome do serviço e metadados adicionais, confiamos nos desenvolvedores. Há uma pequena chance de que os desenvolvedores acidentalmente ou intencionalmente obtenham os segredos de outros serviços que giram em um espaço para nome, por isso introduzimos uma regra: um serviço - um espaço para nome.

Novo microsserviço? Obtenha um novo espaço para nome com seus segredos. Você não pode atravessar a fronteira para a vizinha - eles têm seu próprio token de conta de serviço. A fronteira de segurança no Kubernetes no momento é o espaço para nome. Se em dois namespace diferentes, você precisar de um segredo - copie-o.

Kubernetes tem segredos kubernetes . Eles são armazenados no etcd no Kubernetes de forma não criptografada e podem "acender" no painel ou quando o kubectl get pods é iniciado. Se a autenticação no etcd estiver desabilitada no seu cluster ou se você tiver concedido acesso completo somente leitura a alguém, todos os segredos estarão visíveis para ele. Por isso, introduzimos duas regras: é proibido usar segredos do kubernetes e é proibido especificar segredos em variáveis ​​de ambiente em manifestos . Se você escreve um segredo no ambiente em deployment.yaml, isso é ruim, porque o manifesto em si pode ser visto por qualquer pessoa que não seja preguiçosa.

Kubernetes Delivery


Como eu disse, devemos de alguma forma colocar o arquivo no Kubernetes. Temos algum tipo de segredo: a essência, a senha, escrita em JSON no Vault. Como transformá-lo em um arquivo dentro do contêiner no Kubernetes agora?


A primeira opção de entrega.

  • Iniciamos um init-container especial.
  • Começa a partir da nossa imagem.
  • A imagem contém um pequeno utilitário que vai para o Vault com o Token de conta de serviço, pega o segredo e o coloca no volume compartilhado.
  • Para o utilitário, um volume compartilhado especial é montado apenas na memória TMPFS, para que os segredos não passem pelo disco.
  • O contêiner Init vai para o Vault, coloca neste volume na forma de arquivos todos os segredos que encontra no caminho especificado.
  • Em seguida, o volume compartilhado é montado no contêiner principal no qual é necessário.
  • Quando o contêiner principal é iniciado, ele obtém imediatamente o que o desenvolvedor precisa - segredos na forma de um arquivo em disco.

O desenvolvedor só precisa se lembrar do caminho em que reside seu segredo.

Usamos algo como este prefixo:

/k8s/<cluster>/<namespace>/<service>/some_secret 

O nome do prefixo contém o nome do cluster, o espaço para nome e o nome do serviço. Cada serviço tem seu próprio segredo, cada espaço para nome tem seu próprio segredo.

A segunda opção é o seu próprio ponto de entrada . Agora estamos migrando para ele no Avito, porque os desenvolvedores têm problemas com o init-container. No diagrama, esta opção está à direita.

Nem todo mundo pode pagar seu próprio ponto de entrada. Podemos, portanto, em cada contêiner, forçamos nosso ponto de entrada especial.

Nosso ponto de entrada faz o mesmo que o init-container: ele acessa o Vault com um token de conta de serviço, pega segredos e os expõe. Além dos arquivos, ele os coloca de volta no ambiente. Você tem a oportunidade de executar o aplicativo conforme recomendado pelo conceito de aplicativo de doze fatores : o aplicativo obtém todas as configurações, incluindo segredos, das variáveis ​​de ambiente.

As variáveis ​​de ambiente não são visíveis no manifesto e no painel, pois são definidas pelo PID 1 (o processo principal do contêiner) na inicialização. Essas não são variáveis ​​de ambiente de deployment.yaml, mas variáveis ​​de ambiente definidas pelo ponto de entrada no processo. Eles não são visíveis no painel, eles não são visíveis, mesmo se você fizer o kubectl exec em um contêiner, porque nesse caso outro processo é iniciado, paralelo ao PID1.

Workflow


Do ponto de vista organizacional, o processo é o seguinte. O desenvolvedor aprende com o campeão de segurança ou com a documentação que ele não deve guardar segredos no repositório, mas apenas no Vault. Então ele vem até nós e pergunta onde colocar segredos - ele envia um aplicativo à segurança para estabelecer um prefixo. No futuro, você pode criar um prefixo sem uma solicitação, imediatamente ao criar um serviço.

O desenvolvedor está esperando, e isso é ruim, porque o principal para ele é o tempo de colocação no mercado. Então ele lê as instruções, lida com arquivos longos - “insira essa linha ali, insira esta linha aqui”. Um desenvolvedor nunca iniciou um contêiner init antes, mas é forçado a descobrir e registrá-lo em deployment.yaml (helm chart).

Commit -> deploy -> feel pain -> fix -> repeat

Ele confirma, aguarda o lançamento do TeamCity, vê erros no TeamCity, começa a sentir dor, tenta consertar algo, sente dor novamente. Além disso, é sobreposto que cada lançamento no TeamCity ainda pode ser colocado na fila. Às vezes, um desenvolvedor não consegue descobrir por si mesmo, chega até nós e resolvemos isso juntos.

Basicamente, o desenvolvedor sofre devido a seus próprios erros: init-container especificado incorretamente ou não leu a documentação .

A segurança também tem problemas. O guarda de segurança recebe um aplicativo no qual há sempre pouca informação e ainda descobrimos as perguntas que faltam: descubra os nomes dos clusters, o espaço para nome do serviço, pois o desenvolvedor não os indica no aplicativo e nem sempre sabe o que é. Quando descobrimos tudo, criamos políticas e funções no Vault, prescrevemos políticas para grupos e, juntamente com o desenvolvedor, começamos a descobrir onde e por que ele cometeu um erro, e juntos lemos os logs.

A unidade "Arquitetura" ajuda a resolver o problema ocultando o desenvolvedor deployment.yaml. Eles estão desenvolvendo uma peça que gera tudo para o desenvolvedor, incluindo o ponto de entrada. Devido ao fato de substituirmos nosso ponto de entrada, podemos usá-lo não apenas para fornecer segredos, mas também para outras coisas que você pode precisar fazer na inicialização.

Problemas óbvios com os segredos do Kubernetes.


  • Fluxo de trabalho muito complicado para o desenvolvedor e o guarda de segurança.
  • Você não pode delegar nada a ninguém. O guarda de segurança tem acesso total ao Vault, e o acesso parcial não é possível (consulte Grande falha 1).
  • Dificuldades surgem ao mover desenvolvedores de cluster para cluster, de namespace para namespace, quando segredos compartilhados são necessários, porque é assumido inicialmente que segredos diferentes são diferentes em diferentes clusters.

Dizemos: “Por que você precisa de segredos de produção no cluster de desenvolvimento? Consiga um segredo de teste, vá em frente! Como resultado, existem minas e segredos que são difíceis de gerenciar. Se o segredo mudou, você não deve esquecê-lo, alterá-lo em todos os lugares e, embora não haja maneira de determinar se é o mesmo segredo, exceto pelo nome do serviço.

Idéia: Kubernetes KMS


Nas novas versões do Kubernetes, o subsistema KMS, Serviço de Gerenciamento de Chaves, é um novo recurso de criptografia secreta do Kubernetes. Na v1.11, ele estava no estado alfa, na v1.12, foi transferido para o beta.

A imagem é do site do projeto do provedor KMS do Vault e há um erro. Se você encontrar - escreva nos comentários.

O significado do KMS é eliminar uma única desvantagem - armazenamento de dados não criptografados no etcd.

O KMS, como o Ansible, pode fazer isso.

  • Vá a algum lugar, criptografe o segredo nativo do Kubernetes e coloque-o na forma criptografada.
  • Se necessário, entregue no pod, descriptografar e colocar na forma descriptografada.

Os desenvolvedores criaram um serviço especial que faz isso usando criptografia de trânsito. A ideia parece estar funcionando, mas é importante lembrar que os segredos deixam de estar apenas sob o controle do Vault e vão para outro lugar, na área de responsabilidade dos administradores do Kubernetes.

Contras KMS.

  • Descentralização de armazenamento - Transferência do Vault para o Kubernetes (etcd) . Segredos tornam-se incontroláveis ​​pelo Vault, e é bom como um repositório centralizado de segredos. Acontece que metade dos segredos no Vault e metade em outro lugar.
  • Solução apenas para Kubernetes . Se você possui uma infraestrutura exclusiva do Kubernetes, escolhe o Vault e quase não pensa no que está armazenado lá, porque contém apenas as chaves de criptografia que você gerencia corretamente - gire regularmente, etc. ... Os segredos estão no Kubernetes, e isso é conveniente.
  • É difícil compartilhar segredos entre clusters . Para cada novo cluster, é necessário iniciar tudo de novo, a cópia de segredos, como no caso de um único Vault, pode não funcionar.

Profissionais do KMS.

  • Suporte nativo no Kubernetes, incluindo ocultar ao mostrar o ambiente.
  • Autorização na área de responsabilidade de Kubernetes .
  • Praticamente não é necessário suporte ao Vault .
  • Rotação da chave fora da caixa .

CI / CD: TeamCity


Tudo é simples no TeamCity, porque o JetBrains escreveu um plug-in que pode prescrever segredos para acessar o segredo, criptografá-los com o TeamCity e substituí-lo em porcentagem no modelo em algum lugar do modelo. Nesse momento, o próprio agente do TeamCity vai para o Vault, pega o segredo e o traz para a compilação como parâmetro.

Alguns segredos são necessários durante a implantação, por exemplo, migração de banco de dados ou alertas no Slack. O AppRole é iniciado para cada projeto - as configurações também contêm um segredo (dados para AppRole), mas são inseridos no modo somente gravação - o TeamCity não permite a leitura mais tarde.

O próprio TeamCity cuida para que, quando um segredo entre nos logs de construção, ele se disfarce automaticamente. Como resultado, o segredo não “passa” pelo disco ou é limpo do disco usando as ferramentas do TeamCity. Como resultado, toda a segurança do segredo é bem assegurada pelo próprio TeamCity e pelo plug-in, e danças adicionais com um pandeiro não são necessárias

CI / CD não é TeamCity?


Esses são os principais problemas a serem considerados se você estiver usando um sistema diferente (não o TeamCity) como o IC.

  • Isolamento: limite o escopo de um segredo a um projeto, equipe etc.
  • Quem autoriza o acesso ao segredo.
  • Exclua a capacidade de visualizar o segredo da parte autorizadora.
  • Um estágio separado da compilação é importar o segredo para os arquivos.
  • Limpe depois de si mesmo.

Como resultado, provavelmente você escreverá algo muito semelhante ao plug-in TeamCity para o seu CI / CD. A parte autorizadora aqui provavelmente será o CI / CD, e será ela quem decidirá se essa compilação pode ter acesso a esse segredo e se deve ou não fornecer o próprio segredo com base nos resultados.

É importante não esquecer de limpar os resultados da compilação no final da montagem , se eles foram dispostos em um disco, ou garantir que eles estejam apenas na memória.

Certificações


Não há nada de especial nos certificados - usamos o Vault principalmente para armazenamento.


O Vault possui um back-end PKI especial para emissão de certificados, no qual você pode criar uma Autoridade de Certificação e assinar novos certificados. Temos uma única PKI interna ... A CA raiz e a CA de segundo nível existem separadamente e já gerenciamos a CA de terceiro nível através do Vault. Para armazenar certificados emitidos de qualquer nível, incluindo certificados assinados por CAs externas, usamos um prefixo separado e colocamos quase todos os certificados válidos para fins de contabilidade e monitoramento. O formato para armazenar certificados é proprietário, adequado para armazenar uma chave privada separada e o próprio certificado.

Sumário


Muito trabalho manual para o guarda de segurança, muito limiar de entrada para o desenvolvedor e nenhuma ferramenta de delegação integrada, embora eu realmente queira ...

Como ser Então os sonhos começam.

Ideias: como fazer melhor


Como posso me livrar de várias cópias de um segredo?

Mestre-escravo de entrega


Temos um segredo mestre e um daemon especial que anda por aí, olha o segredo e seus metadados, coloca-o onde necessário, acaba sendo um segredo escravo. No caminho em que o daemon postou o escravo, nada pode ser alterado manualmente, porque o daemon virá e recolocará o segredo mestre em cima do escravo.

Inicialmente, queríamos criar um mecanismo de link simbólico para simplesmente indicar: “Procure esse segredo lá!”, Como no Linux. Verificou-se que existem problemas com os direitos de acesso: não se sabe como verificar os direitos de acesso - como no Linux ou não, com caminhos pai, com transições entre pontos de montagem. Existem muitos momentos ambíguos e chances de cometer um erro, então recusamos os links simbólicos.

Autorização de Propriedade


A segunda coisa que queremos fazer é determinar o proprietário de cada segredo . Por padrão, o segredo pertence à pessoa que o criou. Se necessário, você pode expandir a área de responsabilidade para a unidade emitindo um grupo de proprietários.

Quando aprendermos a delegar, daremos ao proprietário o direito a um segredo, e ele poderá fazer com o segredo o que ele deseja.

  • Espalhe no k8s - uma política é gerada, uma cópia escrava é criada.
  • Espalhe no servidor - uma política é gerada, uma cópia escrava é criada.
  • Espalhe em CI / CD - ...
  • Transferir para outro proprietário.
  • Dê novo acesso, gere novas ACLs.

Agora somos responsáveis ​​por todos os segredos e segurança, mas queremos passar a responsabilidade para o criador. A segurança não será afetada , porque a pessoa que veio até nós com uma solicitação para manter um segredo entende que precisa manter um segredo com segurança e está ciente de sua responsabilidade.

Como ele é o proprietário do segredo, para a opção de entrega mestre-escravo, ele pode escolher onde e em que formato o segredo deve ser entregue a ele. Acontece que o proprietário gerencia tudo sozinho, não há necessidade de enviar solicitações, você pode usar o prefixo necessário, também pode criar e excluir segredos.

Delegação por meio de modelos da ACL


A política de acesso à Lista de controle de acesso no Vault é dividida em duas partes:

  • Lista de controle de acesso na exibição clássica, que descreve o acesso ao prefixo, qual o caminho para ler e escrever, qual apenas para ler etc.
  • Ao criar uma ACL interna, você pode escrever um asterisco no final, o que significa "esse prefixo e tudo abaixo dele". O prefixo pode ser designado como uma operação separada, fornecida ao usuário ou grupo, ou seja, anexada a várias entidades diferentes.

No momento, apenas o administrador do Vault pode alterar a ACL. Tendo obtido acesso a essa ACL, você pode prescrever tudo o que deseja dentro, por exemplo, o path “*” { capabilities = [sudo, ...] } e obter acesso total. Essa é a essência da maior falha nº 1 - é impossível proibir a alteração do conteúdo da ACL.

Queremos definir as ACLs com um modelo pronto que contém o caminho e os espaços reservados nos quais é permitido gerar novas ACLs para esse modelo.

Exemplo


Abaixo está a fonte amarela, o caminho da ACL padrão finalizada do Vault e ainda mais as ações permitidas nesse caminho. Consideramos como uma ACL a permissão para alterar outra ACL abaixo, que é fornecida na forma de um modelo.


Queremos delegar acesso a / k8s, permitimos que apenas esses modelos sejam gerados. Por exemplo, conceda acesso somente leitura a um cluster, espaço para nome, serviço específico, mas não altere o campo de recursos.


Além disso, queremos dar permissão para vincular essas ACLs e emitir direitos diferentes.

Aplicamos o modelo para conceder direitos ao desenvolvedor. Ao modelar, ele executou o $ vault write policy-mgr/create/k8s-microservice ... E, como resultado, obtivemos uma ACL que indica cluster = prod, namespace = ..., service = ... etc. Os direitos foram definidos automaticamente, uma política foi criada com o nome /k8s/some-srv - este é apenas o nome da ACL que pode ser gerado a partir do modelo.


Como resultado, o desenvolvedor, a nosso critério, atribui essa ACL a quem quiser, e se torna o próprio proprietário, pode gerenciá-la como um segredo: excluir, dar e receber usuários e grupos. Agora, a própria pessoa é responsável por seu prefixo: ele gerencia todos os segredos, gera ACLs de acordo com o modelo, pode atribuir ACLs àqueles que deseja. Naturalmente, também podemos limitar.

Toda mágica funciona com a nova entidade do Vault - plugins . Eles são um serviço separado, muito parecido com o que mencionei no início, e funcionam quase exatamente da mesma forma. A única diferença importante é que eles não são proxies. Os plug-ins são lançados "ao lado" do Vault e iniciam o processo principal do Vault. Por esse motivo, todas as solicitações não passam pelo serviço, mas pelo Vault, que já interage com o plug-in, enviando uma solicitação verificada e limpa.

Sobre plugins, como eles são organizados e como escrevê-los, você pode ler no site do Vault . É melhor escrevê-los no Go, o que é bastante simples, porque Existe uma estrutura para o Go. O Vault se comunica com o plug-in via grpc, lança-o como um serviço, mas não se assuste, você não o toca - tudo já está no quadro. Você acabou de escrever um aplicativo REST mais ou menos padrão no qual especifica pontos de extremidade, fornece funções prontas, manipuladores que terão lógica neles.

Não tenha medo de quebrar algo no Vault principal. Um plug-in é um serviço separado. Mesmo que seu plug-in entre em pânico e falhe, ele não interromperá o trabalho do Vault. O Vault simplesmente reiniciará o plug-in e continuará a funcionar.

Além disso, existem configurações adicionais para o próprio plugin: ele sempre verifica as somas de hash para que ninguém mude o binário. A segurança dos plugins em execução é fornecida .

Links úteis:



Falaremos sobre DevOps e segurança, CI / CD, k8s, Puppet e tudo isso no HighLoad ++ (o mais próximo de São Petersburgo em abril) e DevOpsConf . Venha compartilhar sua experiência ou olhar para os outros. Para não esquecer, assine o blog e o boletim informativo , no qual iremos lembrá-lo dos prazos e coletar materiais úteis.

Source: https://habr.com/ru/post/pt438740/


All Articles