Como posso salvar minhas chaves secretas e senha com segurança no meu sistema de controle de versão?

134

Eu mantenho configurações importantes como os nomes de host e as portas dos servidores de desenvolvimento e produção no meu sistema de controle de versão. Mas eu sei que é uma má prática manter segredos (como chaves privadas e senhas de banco de dados) em um repositório VCS.

Mas as senhas - como qualquer outra configuração - parecem que devem ser versionadas. Então, qual é a maneira correta de manter a versão das senhas controlada?

Eu imagino que isso envolveria manter os segredos em seu próprio arquivo "configurações de segredos" e ter esse arquivo criptografado e controlado por versão. Mas quais tecnologias? E como fazer isso corretamente? Existe uma maneira melhor de fazer isso?


Eu faço a pergunta geralmente, mas no meu exemplo específico eu gostaria de armazenar chaves e senhas secretas para um site Django / Python usando git e github .

Além disso, uma solução ideal faria algo mágico quando eu empurra / puxa com o git - por exemplo, se o arquivo de senhas criptografadas muda, um script é executado, solicitando uma senha e descriptografando-a no lugar.


EDIT: Para maior clareza, estou perguntando sobre onde armazenar segredos de produção .

Chris W.
fonte
1
Na verdade, receba algum dinheiro para manter todo o repositório privado.
John Mee
29
@JohnMee Na verdade, eu já pago por um repositório privado, mas o ponto permanece - você não deve manter informações confidenciais em seu repositório.
Chris W.
1
Eu acho que uma grande parte do motivo pelo qual é difícil obter respostas satisfatórias é que a senha antiga de texto simples para conectar-se a um banco de dados é uma relíquia de uma era menos hostil. A resposta correta é algo como "seu código não deve precisar de segredo", mas os sistemas que você está acessando não oferecem muitas opções.
26712
4
Por quê? Existe um valor zilch na versão que controla senhas para serviços externos. O principal valor do controle de versão é que você pode inspecionar as revisões históricas do seu aplicativo que estão em boas condições de funcionamento e executá-las . No entanto, senhas antigas são inúteis para você. Se eles foram revogados, nunca mais funcionarão.
Coronel Panic

Respostas:

100

Você está certo em criptografar seu arquivo de configurações confidenciais enquanto ainda mantém o arquivo no controle de versão. Como você mencionou, a melhor solução seria aquela em que o Git criptografaria transparentemente certos arquivos confidenciais quando você os enviar para que localmente (ou seja, em qualquer máquina que possua seu certificado) você possa usar o arquivo de configurações, mas Git ou Dropbox ou quem quer que seja armazenar seus arquivos no VC não tem a capacidade de ler as informações em texto sem formatação.

Tutorial sobre criptografia / descriptografia transparente durante push / pull

Esta lista https://gist.github.com/873637 mostra um tutorial sobre como usar o driver de filtro de manchas / limpeza do Git com o openssl para criptografar transparentemente os arquivos enviados. Você só precisa fazer algumas configurações iniciais.

Resumo de como funciona

Basicamente, você criará uma .gitencryptpasta contendo 3 scripts bash,

clean_filter_openssl 
smudge_filter_openssl 
diff_filter_openssl 

que são usados ​​pelo Git para descriptografia, criptografia e suporte ao Git diff. Uma senha mestre e salt (fixos!) São definidos dentro desses scripts e você DEVE garantir que o .gitencrypt nunca seja realmente enviado. clean_filter_opensslScript de exemplo :

#!/bin/bash

SALT_FIXED=<your-salt> # 24 or less hex characters
PASS_FIXED=<your-passphrase>

openssl enc -base64 -aes-256-ecb -S $SALT_FIXED -k $PASS_FIXED

Semelhante para smudge_filter_open_ssle diff_filter_oepnssl. Veja Gist.

Seu repositório com informações confidenciais deve ter um arquivo .gitattribute (não criptografado e incluído no repositório) que faça referência ao diretório .gitencrypt (que contém tudo o que o Git precisa para criptografar / descriptografar o projeto de forma transparente) e que esteja presente na sua máquina local.

.gitattribute conteúdo:

* filter=openssl diff=openssl
[merge]
    renormalize = true

Por fim, você também precisará adicionar o seguinte conteúdo ao seu .git/configarquivo

[filter "openssl"]
    smudge = ~/.gitencrypt/smudge_filter_openssl
    clean = ~/.gitencrypt/clean_filter_openssl
[diff "openssl"]
    textconv = ~/.gitencrypt/diff_filter_openssl

Agora, quando você envia o repositório que contém suas informações confidenciais para um repositório remoto, os arquivos serão criptografados de forma transparente. Quando você puxa de uma máquina local que possui o diretório .gitencrypt (que contém sua senha), os arquivos são descriptografados de forma transparente.

Notas

Devo observar que este tutorial não descreve uma maneira de criptografar apenas seu arquivo de configurações confidenciais. Isso criptografa de forma transparente todo o repositório enviado ao host remoto do VC e descriptografa o repositório inteiro para que seja totalmente descriptografado localmente. Para alcançar o comportamento desejado, você pode colocar arquivos confidenciais para um ou vários projetos em um sensitive_settings_repo. Você pode investigar como essa técnica de criptografia transparente funciona com os submódulos Git http://git-scm.com/book/en/Git-Tools-Submodules se você realmente precisa que os arquivos confidenciais estejam no mesmo repositório.

O uso de uma senha fixa pode teoricamente levar a vulnerabilidades de força bruta se os invasores tiverem acesso a muitos repositórios / arquivos criptografados. IMO, a probabilidade disso é muito baixa. Como menciona uma observação na parte inferior deste tutorial, o não uso de uma senha fixa resultará em versões locais de um repositório em máquinas diferentes, sempre mostrando que ocorreram alterações com o 'status git'.

dgh
fonte
1
Oh, muito interessante. Isso soa quase exatamente como o que eu quero (exceto criptografar todo o repositório).
27512 Chris W.
Você pode manter todos os arquivos de configuração confidenciais para vários aplicativos em um repositório criptografado ou adicionar o repositório criptografado com as configurações confidenciais ao seu projeto como um submódulo Git, conforme descrito aqui git-scm.com/book/en/Git-Tools-Submodules .
dgh 27/07
Armazenar senhas / configurações de produção em um submódulo (criptografado) não é incomum. stackoverflow.com/questions/11207284/… . Isso tornaria ainda mais fácil o gerenciamento de configurações entre projetos.
dgh 27/07
Pode valer a pena consultar github.com/AGWA/git-crypt para obter uma solução atualizada. Ele tem a vantagem de permitir que arquivos individuais sejam criptografados e afirma ser "comprovadamente semanticamente seguro". O próprio autor da essência sugeriu que essa ferramenta é melhor em github.com/shadowhand/git-encrypt .
Geekley 17/07
52

O Heroku aprimora o uso de variáveis ​​de ambiente para configurações e chaves secretas:

A abordagem tradicional para lidar com esses vars de configuração é colocá-los na fonte - em um arquivo de propriedades de algum tipo. Esse é um processo propenso a erros e é especialmente complicado para aplicativos de código aberto que geralmente precisam manter ramificações separadas (e privadas) com configurações específicas do aplicativo.

Uma solução melhor é usar variáveis ​​de ambiente e manter as chaves fora do código. Em um host tradicional ou trabalhando localmente, você pode definir vários ambientes no seu bashrc. No Heroku, você usa vars de configuração.

Com o Foreman e os .envarquivos, o Heroku fornece uma cadeia de ferramentas invejável para exportar, importar e sincronizar variáveis ​​de ambiente.


Pessoalmente, acredito que é errado salvar chaves secretas ao lado do código. É fundamentalmente inconsistente com o controle de origem, porque as chaves são para serviços extrínsecos ao código . O único benefício seria que um desenvolvedor pode clonar HEAD e executar o aplicativo sem nenhuma configuração. No entanto, suponha que um desenvolvedor verifique uma revisão histórica do código. A cópia deles incluirá a senha do banco de dados do ano passado, para que o aplicativo falhe no banco de dados atual.

Com o método Heroku acima, um desenvolvedor pode fazer check-out do aplicativo do ano passado, configurá-lo com as chaves de hoje e executá-lo com sucesso no banco de dados de hoje.

Coronel Panic
fonte
1
Esta resposta não tem atenção suficiente, mas coincide mais com a maneira linux.
Nikolay Fominyh
11
Portanto, se os vários ambientes estiverem definidos no seu bashrc e você estiver implantando um novo servidor, o que cria o bashrc? Isso não apenas move as senhas do repositório de código-fonte para a configuração de implantação? (que é, presumivelmente, também no repo código-fonte ou em um repo própria?)
Jonathan Hartley
@ JonathanHartley, o seu .bashrc não deve estar no repositório de códigos do seu aplicativo Django.
1126 Steve Steve
4
Desculpe, meu comentário é ambíguo, mas é porque estou genuinamente confuso. Adoro o som do ponto de vista desta resposta, mas nunca o entendi completamente. Se estou implantando em vários ambientes diferentes, cada um dos quais contém vários hosts e talvez vários tipos de hosts, obviamente eu preciso automatizar a criação dos arquivos .bashrc que existirão em cada host para definir suas variáveis ​​de ambiente. Então, a resposta está dizendo que eu deveria ter um segundo repo, separado da minha fonte, que contém todas as configurações que se tornarão variáveis ​​de ambiente no .bashrc na implantação?
Jonathan Hartley
1
Eles precisam ser configurados apenas uma vez por máquina na qual você implanta. Se o seu processo de implantação for "girar uma nova máquina e testar se está correto antes de redirecionar o tráfego para ela e depois atirar na cabeça da antiga", qual é a melhor prática do IMHO, você realmente precisa automatizar a criação do que quer que seja env vars.
Jonathan Hartley
16

A maneira mais limpa, na minha opinião, é usar variáveis ​​de ambiente. Você não precisará lidar com arquivos .dist, por exemplo, e o estado do projeto no ambiente de produção seria o mesmo que o da sua máquina local.

Eu recomendo ler o capítulo de configuração do Twelve-Factor App , os outros também, se você estiver interessado.

Samy Dindane
fonte
6
Parece que as variáveis ​​de ambiente são uma boa maneira de executar o aplicativo com as configurações secretas ... mas ainda não responde à pergunta de onde manter essas configurações.
27512 Chris W.
2
Você normalmente deve ter um arquivo LEIA-ME para cada um dos seus aplicativos. Especifique quais variáveis ​​de ambiente devem ser definidas e toda vez que você implantar um projeto, basta seguir as etapas e definir cada uma delas. Você também pode criar um script de shell com muitos export MY_ENV_VAR=e, quando implantar, basta preenchê-lo com os valores certos source. Se por manter você significa a versão das configurações, você não deveria fazer isso em primeiro lugar.
Samy Dindane
Além disso, votou para o The Twelve-Factor App - coisas realmente ótimas.
Chris
4
@ Samy: E se você automatizou a implantação?
9136 Jonathan Hartley
3
@ Samy Ainda não entendo como as variáveis ​​de ambiente seriam definidas. A página do aplicativo com 12 fatores também não deixa isso claro (a menos que você esteja no Heroku, que não é o meu projeto atual.) Estamos dizendo que um script de geração precisa solicitar a um armazenamento de configuração central "Eu sou a máquina X, por favor me dê meus dados de configuração ", e isso responde com os valores das variáveis ​​de ambiente que devem ser definidas. Nesse caso, acho que você não precisa mais de um script gerado. Estou especulando muito aqui, estou latindo na árvore certa?
9133 Jonathan Hartley
10

Uma opção seria colocar credenciais vinculadas ao projeto em um contêiner criptografado (TrueCrypt ou Keepass) e enviá-lo por push.

Atualize como resposta do meu comentário abaixo:

Pergunta interessante btw. Acabei de encontrar o seguinte: github.com/shadowhand/git-encrypt que parece muito promissor para criptografia automática

schneck
fonte
Seria bom ter algo que eu pudesse automatizar. De modo que, se meu arquivo de senha criptografada for alterado, ele descriptografará automaticamente o novo arquivo.
Chris W.
7
Pergunta interessante btw. Acabei de encontrar o seguinte: github.com/shadowhand/git-encrypt, que parece muito promissor para criptografia automática.
schneck
1
Uau, ótimo. A descrição de git-encryptsons exatamente como o que estou procurando "Ao trabalhar com um repositório git remoto hospedado em um servidor de armazenamento de terceiros, a confidencialidade dos dados às vezes se torna uma preocupação. Este artigo orienta você nos procedimentos de configuração de repositórios git para os quais seus diretórios de trabalho locais são normais (não criptografados), mas o conteúdo confirmado é criptografado ". (Claro, eu só quero um subconjunto do meu conteúdo criptografado ...)
Chris W.
@schneck publique seu comentário como resposta para que Chris possa aceitá-lo - parece que é o que ele está procurando.
21812 Tony Abou-Assaleh
9

Sugiro usar arquivos de configuração para isso e não os versão.

No entanto, você pode exemplos de versão dos arquivos.

Não vejo problema em compartilhar configurações de desenvolvimento. Por definição, ele não deve conter dados valiosos.

tiktak
fonte
1
Mas então onde armazenar os registros de senha canônicos? Me deixaria nervoso ter esses dados apenas em um arquivo de configuração em uma máquina que pode explodir algum dia.
Chris W.
@ChrisW. Se a máquina explodir, você não precisará mais necessariamente da senha ... No entanto, se você tiver apenas uma cópia dos dados em sua máquina de produção, isso deverá exibir uma bandeira vermelha. Mas isso não significa que deve estar no VCS. Deve haver RAID, backups completos complementados por backups incrementais em mídia magnética e óptica. Muitas empresas têm um procedimento de controle de alterações que pode ditar como e onde armazenar senhas e outros materiais confidenciais também em papel.
Steve Buzonas 29/07/2012
@ Chrishr Não quero ser grosseiro, mas parece que você não nos diz a verdade e as senhas que deseja armazenar não são usadas no desenvolvimento, mas na produção. Isso não é verdade? Caso contrário, por que você se importa com uma máquina de desenvolvimento ou teste e com senhas de desenvolvimento? Ninguém faria isso.
21412 tiktak
Aliás, em nossa empresa, todas as senhas de desenvolvimento estão disponíveis em papel e na intranet. Porque eles não têm valor. Eles estão lá porque o software que desenvolvemos precisa de autenticação.
21712 Tiktak
@ tiktak, você está correto - minha pergunta é sobre o que fazer com relação às senhas de produção. Não me preocupo particularmente com o armazenamento de senhas de desenvolvimento no A VCS. Desculpe se eu não deixei isso claro o suficiente.
Chris W.
7

O BlackBox foi lançado recentemente pelo StackExchange e, embora eu ainda precise usá-lo, parece abordar exatamente os problemas e dar suporte aos recursos solicitados nesta pergunta.

Na descrição em https://github.com/StackExchange/blackbox :

Armazene com segurança segredos em um repositório VCS (ou seja, Git ou Mercurial). Esses comandos facilitam a criptografia GPG de arquivos específicos em um repositório, para que eles sejam "criptografados em repouso" no seu repositório. No entanto, os scripts facilitam descriptografá-los quando você precisar visualizá-los ou editá-los e descriptografá-los para uso na produção.

Chris W.
fonte
7

Desde que fiz essa pergunta, decidi por uma solução, que uso no desenvolvimento de aplicativos pequenos com uma pequena equipe de pessoas.

git-cripta

O git-crypt usa GPG para criptografar arquivos de forma transparente quando seus nomes correspondem a determinados padrões. Por exemplo, se você adicionar ao seu .gitattributesarquivo ...

*.secret.* filter=git-crypt diff=git-crypt

... então um arquivo como config.secret.json sempre será enviado para repositórios remotos com criptografia, mas permanecerá sem criptografia no sistema de arquivos local.

Se eu quiser adicionar uma nova chave GPG (uma pessoa) ao seu repositório, que pode descriptografar os arquivos protegidos, execute git-crypt add-gpg-user <gpg_user_key>. Isso cria um novo commit. O novo usuário poderá descriptografar confirmações subsequentes.

Chris W.
fonte
5

Eu faço a pergunta geralmente, mas no meu exemplo específico eu gostaria de armazenar chaves e senhas secretas para um site Django / Python usando git e github.

Não, apenas não, mesmo que seja seu repositório particular e você nunca pretenda compartilhá-lo, não faça.

Você deve criar um local_settings.py colocá-lo em VCS ignore e em seu settings.py fazer algo como

from local_settings import DATABASES, SECRET_KEY
DATABASES = DATABASES

SECRET_KEY = SECRET_KEY

Se suas configurações de segredos são tão versáteis, estou ansioso para dizer que você está fazendo algo errado

Hedde van der Heide
fonte
9
Mas ainda precisarei acompanhar esses segredos em algum lugar . Por exemplo, keypass ou algo nesse sentido, certo?
Chris W.
A regulamentação e a implementação do armazenamento de dados particulares dependem da política da empresa para a qual o projeto se destina. Eu duvido que o código-fonte do projeto é o lugar apropriado como qualquer terceiro tester partido ou programador poderia ver estes
Hedde van der Heide
4

EDIT: Suponho que você deseja acompanhar as versões anteriores de suas senhas - por exemplo, para um script que evite a reutilização de senhas etc.

Eu acho que o GnuPG é o melhor caminho a percorrer - ele já é usado em um projeto relacionado ao git (git-anexo) para criptografar o conteúdo do repositório armazenado nos serviços em nuvem. O GnuPG (gnu pgp) fornece uma criptografia baseada em chave muito forte.

  1. Você mantém uma chave na sua máquina local.
  2. Você adiciona 'minha senha' aos arquivos ignorados.
  3. No gancho de pré-confirmação, você criptografa o arquivo mypassword no arquivo mypassword.gpg rastreado pelo git e o adiciona ao commit.
  4. No gancho pós-mesclagem, basta descriptografar mypassword.gpg em mypassword.

Agora, se o arquivo 'minha senha' não foi alterado, a criptografia resultará no mesmo texto cifrado e não será adicionado ao índice (sem redundância). A modificação mais leve do mypassword resulta em texto cifrado radicalmente diferente e mypassword.gpg na área de teste diferem muito da do repositório, portanto serão adicionados ao commit. Mesmo que o invasor segure sua chave gpg, ele ainda precisará aplicar força à senha. Se o invasor obtiver acesso ao repositório remoto com texto cifrado, ele poderá comparar um monte de textos cifrados, mas o número deles não será suficiente para lhe proporcionar uma vantagem não negligenciável.

Posteriormente, você pode usar .gitattributes para fornecer uma descriptografia imediata para sair do git diff da sua senha.

Além disso, você pode ter chaves separadas para diferentes tipos de senhas, etc.

pielgrzym
fonte
3

Normalmente, separo a senha como um arquivo de configuração. e distingui-los.

/yourapp
    main.py
    default.cfg.dist

E quando eu corro main.py, coloque a senha real na default.cfgcópia.

ps. quando você trabalha com git ou hg. você pode ignorar *.cfgarquivos para criar .gitignoreou.hgignore

admirar
fonte
Arquivos .dist são o que eu estava falando: exemplos de arquivos de configuração reais. Uma boa prática é que só seja possível executar o software renomeando, removendo a extensão ".dist" (ou melhor: copiando), ou seja, você poderá tentar o software em segundos, sem precisar configurá-lo durante o dia todo.
21712 Tiktak
3

Forneça uma maneira de substituir a configuração

Essa é a melhor maneira de gerenciar um conjunto de padrões sãos para a configuração que você fez check-in sem exigir que a configuração seja concluída ou conter itens como nomes de host e credenciais. Existem algumas maneiras de substituir as configurações padrão.

Variáveis ​​de ambiente (como outros já mencionaram) são uma maneira de fazê-lo.

A melhor maneira é procurar um arquivo de configuração externo que substitua os valores de configuração padrão. Isso permite gerenciar as configurações externas por meio de um sistema de gerenciamento de configurações como Chef, Puppet ou Cfengine. O gerenciamento de configuração é a resposta padrão para o gerenciamento de configurações, separado da base de código, para que você não precise fazer uma liberação para atualizar a configuração em um único host ou grupo de hosts.

FYI: Criptografar creds nem sempre é uma prática recomendada, especialmente em um local com recursos limitados. Pode ser que as criptografadas creds não ofereçam mais mitigação de riscos e simplesmente adicionem uma camada desnecessária de complexidade. Certifique-se de fazer a análise adequada antes de tomar uma decisão.

dietbuddha
fonte
2

Criptografe o arquivo de senhas, usando, por exemplo, GPG. Adicione as chaves na sua máquina local e no seu servidor. Descriptografe o arquivo e coloque-o fora de suas pastas de recompra.

Eu uso um passwords.conf, localizado na minha pasta inicial. Em cada implantação, esse arquivo é atualizado.

Willian
fonte
Em seguida, o software precisa descriptografar o arquivo de senha.
tiktak 30/07/2012
Bem, só quando a implantação do site a senha se descriptografado e gravados em um arquivo de senhas de texto simples
Willian
2

Não, chaves privadas e senhas não se enquadram no controle de revisão. Não há razão para sobrecarregar todos os que têm acesso de leitura ao seu repositório ao conhecerem as credenciais de serviço confidenciais usadas na produção, quando é provável que nem todas elas tenham acesso a esses serviços.

A partir do Django 1.4, seus projetos do Django agora são enviados com um project.wsgimódulo que define o applicationobjeto e é um local perfeito para começar a impor o uso de um project.localmódulo de configurações que contém configurações específicas do site.

Esse módulo de configurações é ignorado do controle de revisão, mas é necessária presença ao executar a instância do projeto como um aplicativo WSGI, típico para ambientes de produção. É assim que deve ser:

import os

os.environ.setdefault("DJANGO_SETTINGS_MODULE", "project.local")

# This application object is used by the development server
# as well as any WSGI server configured to use this file.
from django.core.wsgi import get_wsgi_application
application = get_wsgi_application()

Agora você pode ter um local.pymódulo cujo proprietário e grupo podem ser configurados para que somente pessoal autorizado e os processos do Django possam ler o conteúdo do arquivo.

Filip Dupanović
fonte
2

Se você precisar de VCS para seus segredos, pelo menos mantenha-os em um segundo repositório separado do seu código real. Assim, você pode dar aos membros da sua equipe acesso ao repositório de código-fonte e eles não verão suas credenciais. Além disso, hospede este repositório em outro lugar (por exemplo, no seu próprio servidor com um sistema de arquivos criptografado, não no github) e, para fazer o check-out no sistema de produção, você pode usar algo como o git-submódulo .

Bernhard Vallant
fonte
1

Outra abordagem seria evitar completamente salvar segredos nos sistemas de controle de versão e usar uma ferramenta como o vault da hashicorp , um armazenamento secreto com rolagem e auditoria de chaves, com uma API e criptografia incorporada.

Kai Peters
fonte
1

Isto é o que eu faço:

  • Mantenha todos os segredos como envs em $ HOME / .secrets (go-r perms) que as fontes $ HOME / .bashrc (desta forma, se você abrir .bashrc na frente de alguém, eles não verão os segredos)
  • Os arquivos de configuração são armazenados no VCS como modelos, como config.properties armazenados como config.properties.tmpl
  • Os arquivos de modelo contêm um espaço reservado para o segredo, como:

    my.password = ## MY_PASSWORD ##

  • Na implantação do aplicativo, é executado um script que transforma o arquivo de modelo no arquivo de destino, substituindo espaços reservados por valores de variáveis ​​de ambiente, como alterar ## MY_PASSWORD ## pelo valor de $ MY_PASSWORD.

Pavel Chernikov
fonte
0

Você poderia usar o EncFS se o seu sistema fornecer isso. Assim, você pode manter seus dados criptografados como uma subpasta do seu repositório, fornecendo ao seu aplicativo uma visualização descriptografada para os dados montados de lado. Como a criptografia é transparente, nenhuma operação especial é necessária em pull ou push.

No entanto, seria necessário montar as pastas EncFS, o que poderia ser feito pelo seu aplicativo com base em uma senha armazenada em outro local fora das pastas com versão (por exemplo, variáveis ​​de ambiente).

dronus
fonte