如何在我的版本控制系统中安全地保存我的密钥和密码?

时间:2012-07-20 08:11:07

标签: python django git version-control

我在版本控制系统中保留了开发和生产服务器的主机名和端口等重要设置。但我知道在VCS存储库中保留机密(如私钥和数据库密码)是不良做法

但是密码 - 就像任何其他设置一样 - 看起来应该是版本化的。那么 是保持密码版本控制的正确方法呢?

我想这将涉及将机密保留在他们自己的“机密设置”文件中,并使 文件加密并受版本控制。但是什么技术呢?以及如何正确地做到这一点?是否有更好的方法来完成它?


我一般会问这个问题,但在我的具体实例中,我想使用 git github为 Django / Python 网站存储密钥和密码

此外,当我使用git推/拉时,理想的解决方案会做一些神奇的事情 - 例如,如果加密的密码文件发生更改,则会运行一个脚本,要求输入密码并将其解密到位

<小时/> 编辑:为清楚起见,我询问存储生产机密的位置。

17 个答案:

答案 0 :(得分:97)

您仍然希望加密敏感设置文件,同时仍然在版本控制中维护文件。正如您所提到的,最佳解决方案是Git会在您推送它们时透明地加密某些敏感文件,以便在本地(即在任何拥有您的证书的计算机上)您可以使用设置文件,但Git或Dropbox或任何人在VC下存储文件无法以纯文本格式读取信息。

推/拉期间透明加密/解密教程

这个要点https://gist.github.com/873637显示了如何使用Git的涂抹/清除过滤器驱动程序和openssl来透明地加密推送文件的教程。你只需要做一些初步设置。

工作原理摘要

您基本上将创建一个包含3个bash脚本的.gitencrypt文件夹,

clean_filter_openssl 
smudge_filter_openssl 
diff_filter_openssl 

,Git用于解密,加密和支持Git diff。在这些脚本中定义了主密码和盐(固定!),您必须确保实际上不会推送.gitencrypt。 示例clean_filter_openssl脚本:

#!/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

类似于smudge_filter_open_ssldiff_filter_oepnssl。见Gist。

包含敏感信息的repo应该有一个.gitattribute文件(未加密并包含在repo中),该文件引用.gitencrypt目录(其中包含Git透明地加密/解密项目所需的所有内容)以及本地计算机上存在的目录。

.gitattribute内容:

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

最后,您还需要将以下内容添加到.git/config文件

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

现在,当您将包含敏感信息的存储库推送到远程存储库时,文件将被透明加密。当您从具有.gitencrypt目录(包含密码)的本地计算机中提取时,文件将被透明地解密。

备注

我应该注意,本教程没有描述仅加密敏感设置文件的方法。这将透明地加密推送到远程VC主机的整个存储库并解密整个存储库,以便在本地完全解密。要实现所需的行为,可以将一个或多个项目的敏感文件放在一个sensitive_settings_repo中。如果您确实需要将敏感文件放在同一个存储库中,您可以调查这种透明加密技术如何与Git子模块http://git-scm.com/book/en/Git-Tools-Submodules一起使用。

如果攻击者可以访问许多加密的回购/文件,理论上使用固定密码短语会导致暴力破解。 IMO,这个概率非常低。如本教程底部的注释所述,不使用固定密码短语将导致不同计算机上的本地版本的repo始终显示“git status”发生了更改。

答案 1 :(得分:51)

Heroku推送the use of environment variables设置和密钥:

  

处理此类配置变量的传统方法是将它们放在源代码下 - 在某种属性文件中。这是一个容易出错的过程,对于开源应用来说尤其复杂,因为开源应用通常需要使用特定于应用的配置来维护单独的(和私有的)分支。

     

更好的解决方案是使用环境变量,并将密钥保留在代码之外。在传统主机上或在本地工作,您可以在bashrc中设置环境变量。在Heroku上,您使用配置变量。

使用Foreman和.env文件Heroku提供了一个令人羡慕的工具链来导出,导入和同步环境变量。


就个人而言,我认为将密钥与代码一起保存是错误的。它与源代码控制基本上不一致,因为密钥用于服务外部代码。一个好处是开发人员可以克隆HEAD并运行应用程序而无需任何设置。但是,假设开发人员签出了代码的历史修订版。他们的副本将包括去年的数据库密码,因此应用程序将在今天的数据库中失败。

使用上面的Heroku方法,开发人员可以查看去年的应用程序,使用今天的密钥配置它,并在今天的数据库上成功运行它。

答案 2 :(得分:16)

我认为最干净的方法是使用环境变量。例如,您不必处理 .dist 文件,生产环境中的项目状态将与本地计算机相同。

如果您感兴趣的话,我建议您阅读The Twelve-Factor App的配置章节。

答案 3 :(得分:11)

一个选项是将项目绑定的凭据放入加密容器(TrueCrypt或Keepass)并推送它。

从以下评论中回复更新:

有趣的问题btw。我刚刚发现:github.com/shadowhand/git-encrypt看起来非常有希望进行自动加密

答案 4 :(得分:9)

我建议使用配置文件,不要对它们进行版本化。

然而,您可以对文件进行版本示例。

我没有看到共享开发设置的任何问题。根据定义,它不应包含任何有价值的数据。

答案 5 :(得分:7)

StackExchange最近发布了

BlackBox,虽然我还没有使用它,但它似乎正好解决了这个问题,并支持这个问题所要求的功能。

来自https://github.com/StackExchange/blackbox的说明:

  

安全地将秘密存储在VCS仓库(即Git或Mercurial)中。这些   命令使您可以轻松地GPG加密仓库中的特定文件   所以他们在休息时加密了#34;在您的存储库中。然而   脚本可以在您需要查看或编辑时轻松解密它们   它们,并解密它们以供生产使用。

答案 6 :(得分:6)

自从提出这个问题以来,我已经找到了一个解决方案,我在与一小组人员一起开发小型应用程序时使用了这个解决方案。

git-crypt

git-crypt使用GPG在名称与某些模式匹配时透明地加密文件。对于intance,如果您添加到.gitattributes文件...

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

...然后像config.secret.json这样的文件将始终通过加密推送到远程存储库,但在本地文件系统上保持未加密状态。

如果我想在您的仓库中添加一个可以解密受保护文件的新GPG密钥(一个人),请运行git-crypt add-gpg-user <gpg_user_key>。这会创建一个新的提交。新用户将能够解密后续提交。

答案 7 :(得分:5)

  

我一般会问这个问题,但在我的具体情况下,我想   使用git存储Django / Python站点的密钥和密码   和github。

不,只是不要,即使这是你的私人回购而你永远不打算分享,不要。

您应该创建一个local_settings.py,将其置于VCS上,并在settings.py中执行类似

的操作
from local_settings import DATABASES, SECRET_KEY
DATABASES = DATABASES

SECRET_KEY = SECRET_KEY

如果你的秘密设置多才多艺,我很想说你做错了什么

答案 8 :(得分:4)

编辑:我认为您要跟踪以前的密码版本 - 例如,对于会阻止密码重复使用的脚本等。

我认为GnuPG是最好的方式 - 它已经在一个与git相关的项目(git-annex)中用于加密存储在云服务上的存储库内容。 GnuPG(gnu pgp)提供非常强大的基于密钥的加密。

  1. 您在本地计算机上保留一个密钥。
  2. 您将'mypassword'添加到被忽略的文件中。
  3. 在预提交挂钩上,您将mypassword文件加密到git跟踪的mypassword.gpg文件中,并将其添加到提交中。
  4. 在合并后的钩子上,您只需将mypassword.gpg解密为mypassword。
  5. 现在,如果您的'mypassword'文件没有更改,那么加密它将导致相同的密文,并且它不会被添加到索引(没有冗余)。 mypassword的最轻微修改导致完全不同的密文,并且临时区域中的mypassword.gpg与存储库中的密文不同,因此将被添加到提交中。即使攻击者获得了你的gpg密钥,他仍然需要强制密码。如果攻击者使用密文访问远程存储库,他可以比较一堆密文,但是他们的数量不足以给他任何不可忽视的优势。

    稍后您可以使用.gitattributes为您的密码的quit git diff提供动态解密。

    此外,您还可以为不同类型的密码设置单独的密钥等。

答案 9 :(得分:3)

通常,我将密码作为配置文件分开。让他们分开。

/yourapp
    main.py
    default.cfg.dist

当我运行main.py时,将真实密码放在复制的default.cfg中。

PS。当你使用git或hg时。您可以忽略*.cfg个文件来制作.gitignore.hgignore

答案 10 :(得分:3)

提供覆盖配置的方法

这是管理您签入的配置的一组理智默认值的最佳方法,无需配置完整,或包含主机名和凭据等内容。有几种方法可以覆盖默认配置。

环境变量(正如其他人已经提到的)是这样做的一种方式。

最好的方法是查找覆盖默认配置值的外部配置文件。这允许您通过Chef,Puppet或Cfengine等配置管理系统管理外部配置。配置管理是管理与代码库分开的配置的标准答案,因此您无需在单个主机或一组主机上更新配置。

仅供参考:加密信用卡并不总是最佳做法,尤其是在资源有限的地方。可能的情况是,对信用卡进行加密将不会为您带来额外的风险缓解,只需添加一个不必要的复杂层。确保在做出决定之前进行适当的分析。

答案 11 :(得分:2)

使用例如GPG加密密码文件。在本地计算机和服务器上添加密钥。解密文件并将其放在repo文件夹之外。

我使用的是位于我的家庭文件夹中的passwords.conf。在每次部署时,此文件都会更新。

答案 12 :(得分:2)

不,私钥和密码不受版本控制。通过了解生产中使用的敏感服务凭证,没有理由让每个人都对您的存储库具有读访问权,而很可能并非所有人都能访问这些服务。

从Django 1.4开始,您的Django项目现在附带一个定义application objectproject.wsgi模块,它是开始强制使用包含project.local设置模块的完美场所特定于站点的配置。

此修订控件会忽略此设置模块,但在将项目实例作为WSGI应用程序运行时需要它,这对于生产环境来说是典型的。这就是它应该是这样的:

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()

现在您可以拥有一个local.py模块,可以配置所有者和组,以便只有授权人员和Django进程才能读取文件的内容。

答案 13 :(得分:2)

如果您需要VCS来保密,至少应该将它们保存在与实际代码分开的第二个存储库中。因此,您可以让您的团队成员访问源代码存储库,他们将无法看到您的凭据。此外,在其他地方托管此存储库(例如,在您自己的服务器上使用加密文件系统,而不是在github上),并将其签出到生产系统,您可以使用类似git-submodule的内容。

答案 14 :(得分:1)

另一种方法可能是完全避免在版本控制系统中保存秘密,而是使用像vault from hashicorp这样的工具,一个带有密钥滚动和审计的秘密存储,以及API和嵌入式加密。

答案 15 :(得分:1)

这就是我的所作所为:

  • 将所有秘密保存为$ HOME / .secrets(go-r perms)中的env vars $ HOME / .bashrc来源(这样如果你在某人面前打开.bashrc,他们就不会看到这些秘密)
  • 配置文件作为模板存储在VCS中,例如config.properties存储为config.properties.tmpl
  • 模板文件包含秘密的占位符,例如:

    my.password = ## MY_PASSWORD ##

  • 在应用程序部署中,运行脚本将模板文件转换为目标文件,用环境变量值替换占位符,例如将## MY_PASSWORD ##更改为$ MY_PASSWORD的值。

答案 16 :(得分:0)

如果您的系统提供了EncFS,您可以使用它。因此,您可以将加密数据保存为存储库的子文件夹,同时为应用程序提供解密视图,以便将数据放在一边。由于加密是透明的,因此在拉或推时不需要特殊操作。

然而,它需要安装EncFS文件夹,这可以由您的应用程序根据存储在版本化文件夹之外的其他地方的密码(例如环境变量)来完成。