问题:如何将我的秘密密钥和密码安全地保存在版本控制系统中?
我在版本控制系统中保留了重要的设置,例如开发和生产服务器的主机名和端口。但是我知道,将秘密(例如私钥和数据库密码)保存在VCS存储库中是一种不好的做法。
但是像其他设置一样,密码似乎应该进行版本控制。那么保持密码版本控制的正确方法是什么?
我想这将涉及保持秘密,在自己的“秘密设置”文件,并有该文件的加密和版本控制。但是什么技术呢?以及如何正确执行此操作?有没有更好的方法可以完全解决这个问题?
我通常会问这个问题,但是在我的特定实例中,我想使用git和github存储Django / Python站点的秘密密钥和密码。
同样,当我使用git推/拉时,理想的解决方案也会做一些神奇的事情-例如,如果加密的密码文件更改了运行的脚本,该脚本会要求输入密码并将其解密到位。
编辑:为清楚起见,我正在询问在哪里存储的生产秘密。
回答 0
您完全想在保持版本控制的同时加密敏感设置文件是正确的。正如您提到的,最好的解决方案是Git在推送某些敏感文件时透明地对其进行加密,以便在本地(即在具有证书的任何计算机上)可以使用设置文件,但Git或Dropbox或在VC下存储文件无法读取纯文本信息。
推/拉期间的透明加密/解密教程
这个要点https://gist.github.com/873637显示了有关如何将Git的smudge / clean过滤器驱动程序与openssl一起使用的教程,以透明方式加密推送的文件。您只需要进行一些初始设置即可。
工作原理摘要
您基本上将创建一个.gitencrypt
包含3个bash脚本的文件夹,
clean_filter_openssl
smudge_filter_openssl
diff_filter_openssl
Git用于解密,加密和支持Git差异。在这些脚本中定义了主密码和盐(已修复!),您必须确保.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_ssl
和类似diff_filter_oepnssl
。参见要点。
您的带有敏感信息的仓库应该有一个.gitattribute文件(未加密并包含在仓库中),该文件引用.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一起使用。
如果攻击者可以访问许多加密的存储库/文件,则在理论上使用固定的密码短语可能会导致暴力破解漏洞。海事组织,这种可能性非常低。正如本教程底部提到的那样,不使用固定密码短语将导致不同机器上的本地回购版本始终显示“ git status”已发生更改。
回答 1
Heroku推动使用环境变量进行设置和密钥:
处理此类config var的传统方法是将它们放在源代码下-放在某种属性文件中。这是一个容易出错的过程,对于经常需要使用应用程序特定配置维护单独的(和私有的)分支的开源应用程序而言,这尤其复杂。
更好的解决方案是使用环境变量,并将键保留在代码之外。在传统主机上或在本地工作,您可以在bashrc中设置环境变量。在Heroku上,您使用config vars。
借助Foreman和.env
文件,Heroku提供了令人羡慕的工具链来导出,导入和同步环境变量。
就个人而言,我认为将秘密密钥与代码一起保存是错误的。从根本上说,它与源代码管理不一致,因为密钥是针对代码外部的服务的。一个好处是开发人员可以克隆HEAD并运行应用程序而无需进行任何设置。但是,假设开发人员检查了该代码的历史版本。他们的副本将包含去年的数据库密码,因此该应用程序将无法使用今天的数据库。
使用上面的Heroku方法,开发人员可以签出去年的应用程序,使用今天的密钥对其进行配置,然后针对当今的数据库成功运行它。
回答 2
我认为最干净的方法是使用环境变量。例如,您不必处理.dist文件,生产环境中的项目状态将与本地计算机的状态相同。
我建议阅读“十二要素应用程序 ”的配置章节,如果您有兴趣的话,也阅读其他章节。
回答 3
一种选择是将项目绑定的凭据放入加密的容器(TrueCrypt或Keepass)中并推送。
从下面的评论中更新为答案:
有趣的问题顺便说一句。我刚刚发现了这一点:github.com/shadowhand/git-encrypt对于自动加密而言,它看起来很有希望
回答 4
我建议为此使用配置文件,而不要对其进行版本控制。
但是,您可以版本文件的示例。
我看不到共享开发设置的任何问题。根据定义,它不应包含任何有价值的数据。
回答 5
BlackBox是由StackExchange最近发布的,虽然我尚未使用它,但它似乎可以完全解决问题并支持此问题中要求的功能。
从https://github.com/StackExchange/blackbox的描述中:
将机密安全存储在VCS仓库中(即Git或Mercurial)。这些命令使您可以轻松地对存储库中的特定文件进行GPG加密,以便在存储库中对它们进行“静态加密”。但是,使用脚本可以轻松地在需要查看或编辑脚本时对其进行解密,并可以将其解密以用于生产。
回答 6
自从问了这个问题之后,我就确定了一个解决方案,该解决方案是在与一小群人一起开发小型应用程序时使用的。
git-crypt使用GPG对文件名进行匹配的透明加密。例如,如果您添加到.gitattributes
文件中…
*.secret.* filter=git-crypt diff=git-crypt
…然后,像这样的文件config.secret.json
将始终通过加密方式推送到远程存储库,但在本地文件系统上保持未加密状态。
如果我想向您的存储库添加一个新的GPG密钥(一个人),可以解密受保护的文件,请运行git-crypt add-gpg-user <gpg_user_key>
。这将创建一个新的提交。新用户将能够解密后续提交。
回答 7
我通常会问这个问题,但是在我的特定实例中,我想使用git和github存储Django / Python站点的秘密密钥和密码。
不,只是不要,即使这是您的私人存储库,并且您从不打算共享它,也不要。
您应该创建一个local_settings.py,将其放在VCS上忽略,然后在settings.py中执行类似的操作
from local_settings import DATABASES, SECRET_KEY
DATABASES = DATABASES
SECRET_KEY = SECRET_KEY
如果您的机密设置用途广泛,我很想说您做错了
回答 8
编辑:我假设您想跟踪以前的密码版本-例如,对于防止密码重用等的脚本。
我认为GnuPG是最好的方法-已经在一个与git相关的项目(git-annex)中用于加密存储在云服务上的存储库内容。GnuPG(gnu pgp)提供了非常强大的基于密钥的加密。
- 您将密钥保留在本地计算机上。
- 您将’mypassword’添加到忽略的文件。
- 在pre-commit挂钩上,您将mypassword文件加密为git跟踪的mypassword.gpg文件,并将其添加到提交中。
- 在合并后钩子上,您只需将mypassword.gpg解密为mypassword。
现在,如果您的“ mypassword”文件未更改,则将使用相同的密文对其进行加密,并且不会将其添加到索引中(无冗余)。稍加修改mypassword会导致密文截然不同,并且登台区域中的mypassword.gpg与存储库中的密文有很大不同,因此将被添加到提交中。即使攻击者掌握了您的gpg密钥,他仍然需要暴力破解密码。如果攻击者可以使用密文访问远程存储库,则他可以比较一堆密文,但是它们的数量不足以给他带来任何不可忽视的优势。
稍后,您可以使用.gitattributes为您的密码退出git diff提供即时解密。
您也可以为不同类型的密码等设置单独的密钥。
回答 9
通常,我将密码分隔为配置文件。并使其成为dist。
/yourapp
main.py
default.cfg.dist
当我跑步时main.py
,输入真实密码default.cfg
该副本中。
ps。当您使用git或hg时。您可以忽略*.cfg
要制作的文件.gitignore
或.hgignore
回答 10
提供一种方法来覆盖配置
这是管理您签入的配置的一组合理默认值的最佳方法,而无需完成配置或包含主机名和凭据之类的内容。有几种方法可以覆盖默认配置。
环境变量(如其他人已经提到的)是做到这一点的一种方法。
最好的方法是寻找一个覆盖默认配置值的外部配置文件。这使您可以通过诸如Chef,Puppet或Cfengine之类的配置管理系统来管理外部配置。配置管理是与代码库分开进行配置管理的标准答案,因此您无需发布即可在单个主机或一组主机上更新配置。
仅供参考:加密凭证并非总是最佳做法,尤其是在资源有限的地方。可能情况是,加密凭据不会为您带来额外的风险缓解,而只会增加不必要的复杂性。在做出决定之前,请确保您进行了正确的分析。
回答 11
使用例如GPG加密密码文件。将密钥添加到本地计算机和服务器上。解密文件并将其放在您的repo文件夹之外。
我使用homefolder中的passwords.conf。在每次部署中,此文件都会更新。
回答 12
不可以,私钥和密码不属于版本控制。当大多数情况下并非所有人都应该有权访问这些服务时,没有理由让每个人都拥有对存储库的读取访问权的负担,因为他们知道生产中使用的敏感服务凭证。
从Django 1.4开始,您的Django项目现在附带了project.wsgi
定义application
对象的模块,这是开始强制使用a的理想场所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
如果您需要VCS作为秘密,则至少应将其保存在与实际代码分开的第二个存储库中。因此,您可以授予团队成员访问源代码存储库的权限,而他们不会看到您的凭据。此外,将此存储库托管在其他位置(例如,在具有加密文件系统的您自己的服务器上,而不是在github上),并将其检出到生产系统中,可以使用git-submodule之类的东西。
回答 14
另一种方法可能是完全避免在版本控制系统中保存机密,而是使用诸如hashicorp的Vault之类的工具,该工具是具有密钥滚动和审核,具有API和嵌入式加密功能的秘密存储。
回答 15
这是我的工作:
- 将所有秘密保留为$ HOME / .bashrc来源的$ HOME / .secrets(go-r权限)中的env vars(这样,如果您在某人面前打开.bashrc,他们将看不到这些秘密)
- 配置文件作为模板存储在VCS中,例如config.properties存储为config.properties.tmpl
模板文件包含机密的占位符,例如:
my.password = ## MY_PASSWORD ##
在应用程序部署中,将运行脚本,该脚本将模板文件转换为目标文件,并用环境变量的值替换占位符,例如将## MY_PASSWORD ##更改为$ MY_PASSWORD的值。
回答 16
如果您的系统提供了此功能,则可以使用EncFS。因此,您可以将加密的数据保留为存储库的子文件夹,同时为应用程序提供对已装入数据的解密视图。由于加密是透明的,因此在拉或推上不需要任何特殊操作。
但是,它将需要挂载EncFS文件夹,这可以由您的应用程序根据存储在版本化文件夹之外的其他位置的密码(例如,环境变量)来完成。