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

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

但是密码——像任何其他设置一样——似乎应该进行版本控制。那么 保持密码版本控制的正确方法是什么呢?

我想这将涉及保持在他们自己的 秘密“秘密设置”文件和有 那个文件加密和版本控制。但是什么技术呢?如何正确地做到这一点?还有更好的办法吗?


我问的问题一般,但在我的具体情况下,我想存储密钥和密码的 姜戈/巨蟒网站使用 饭桶Github

而且,当我使用 git 进行压缩/拉取操作时,很理想解决方案会做一些神奇的事情——例如,如果加密的密码文件发生变化,就会运行一个脚本,该脚本会询问密码并将其解密到位。


编辑: 为了清晰起见,我询问在哪里存储 制作的秘密。

37148 次浏览

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

根据我的评论更新如下:

顺便说一下,有趣的问题。我刚刚发现这个: Github.com/shadowhand/git-encrypt,看起来非常有希望的自动加密

我建议使用配置文件,而不是版本。

但是,您可以使用文件的版本示例。

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

通常,我把密码作为配置文件分离出来。

/yourapp
main.py
default.cfg.dist

当我运行 main.py时,在复制的 default.cfg中输入真正的密码。

当你使用 git 或 hg 时,你可以忽略 *.cfg文件来创建 .gitignore.hgignore

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

我建议您阅读 十二因素应用程序的配置章节,如果您感兴趣,还可以阅读其他章节。

编辑: 我假设您想要跟踪您以前的密码版本-比如,一个脚本,将防止密码重用等。

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

  1. 您在本地机器上保留一个密钥。
  2. 您将“ mypassword”添加到被忽略的文件。
  3. 在 pre-commit 钩子上,将 mypassword 文件加密到 git 跟踪的 mypassword.gpg 文件中,并将其添加到提交中。
  4. 在合并后的钩子上,你只需要将 mypassword.gpg 解密为 mypassword。

现在,如果您的“ mypassword”文件没有更改,那么对它进行加密将得到相同的加密文本,并且它不会被添加到索引中(没有冗余)。对 mypassword 的轻微修改就会导致临时区域中的加密文本和 mypassword.gpg 与存储库中的加密文本和 mypassword.gpg 大不相同,因此将添加到提交中。即使攻击者得到了你的 gpg 密钥,他仍然需要强行破解密码。如果攻击者能够使用密文访问远程存储库,他可以比较一组密文,但它们的数量不足以给他带来任何不可忽视的优势。

稍后,您可以使用. gittribute 为退出密码 git diff 提供即时解密。

此外,你可以有不同类型的密码等单独的密钥。

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

不,就是不要,即使这是你的私人回购,你从来没有打算分享它,不要。

您应该创建一个 local _ setings.py 将其放在 VCS 忽略上,然后在 setings.py 中执行以下操作

from local_settings import DATABASES, SECRET_KEY
DATABASES = DATABASES


SECRET_KEY = SECRET_KEY

如果你的秘密设置有那么多功能,我很想说你做错了

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

我使用位于我的主文件夹中的 passwords.conf。

Heroku 为设置和密钥按 环境变量的使用:

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

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

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


我个人认为,把密钥和代码放在一起是错误的。它与源代码控制从根本上不一致,因为关键字是针对服务 外在的代码的。一个好处是开发人员可以克隆 HEAD 并在没有任何设置的情况下运行应用程序。但是,假设开发人员检查了代码的历史修订。他们的副本将包括去年的数据库密码,所以应用程序将失败对今天的数据库。

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

您希望在加密敏感设置文件的同时仍然在版本控制中维护该文件,这是完全正确的。正如你提到的,最好的解决方案是当你推送某些敏感文件时,Git 会透明地加密它们,这样你就可以在本地(比如在任何有你证书的机器上)使用设置文件,但是 Git 或 Dropbox 或任何在 VC 下存储你的文件的人都没有能力读取明文信息。

推/拉过程中透明加密/解密教程

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

工作原理摘要

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

clean_filter_openssl
smudge_filter_openssl
diff_filter_openssl

它们被 Git 用于解密、加密和支持 Git diff。一个主密码和盐(固定!)是在这些脚本中定义的,您必须确保。Gitcrypt 实际上从未被推送。 示例 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参见要点。

你的敏感信息回购应该有一个。属性文件(未加密,包含在 repo 中) ,它引用。Gitcrypt 目录(其中包含 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

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

笔记

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

如果攻击者可以访问许多加密的回购/文件,那么使用固定的密码短语理论上会导致暴力漏洞。我的天,这种可能性非常低。正如本教程底部提到的,不使用固定密码短语将导致不同机器上的本地版本的回购,总是显示“ git status”发生了变化。

提供覆盖配置的方法

这是管理您选中的配置的一组合理默认值的最佳方法,而不需要完成配置,或者包含主机名和凭证之类的内容。有几种方法可以覆盖默认配置。

环境变量(正如其他人已经提到的)是实现这一点的一种方法。

最好的方法是查找覆盖默认配置值的外部配置文件。这允许你通过一个组态管理系统来管理外部配置,比如 Chef、 Puppet 或者 Cfengine。组态管理是独立于代码库的配置管理的标准答案,所以你不需要通过发布来更新单个主机或一组主机上的配置。

仅供参考: 加密证书并不总是最佳实践,特别是在资源有限的地方。可能的情况是,加密信用证不会为您带来额外的风险缓解,只会增加不必要的复杂性层。在做决定之前,确保你做了正确的分析。

不,私钥和密码不受修订控制。没有理由让每个具有对存储库的读访问权限的人都知道生产中使用的敏感服务凭据,因为很可能并非所有人都应该具有对这些服务的访问权限。

从 Django 1.4开始,您的 Django 项目现在附带了一个定义了 application对象project.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 进程才能读取文件的内容。

如果您的系统提供了 EncFS,那么您可以使用 EncFS。因此,您可以将加密的数据保存为存储库的子文件夹,同时为应用程序提供一个对挂载到一边的数据的解密视图。由于加密是透明的,因此在 pull 或 push 上不需要特殊的操作。

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

如果您需要 VCS 来保存您的秘密,那么您至少应该将它们保存在与您的实际代码分离的第二个存储库中。所以你可以让你的团队成员进入原始码储存库他们不会看到你的证件。此外,将这个存储库托管到其他地方(例如,在您自己的服务器上使用加密的文件系统,而不是在 github 上) ,为了将其签出到生产系统,您可以使用类似于 Git 子模块的东西。

BlackBox 最近由 StackExchange 发布,虽然我还没有使用它,但它似乎正好解决了这个问题,并支持这个问题中要求的特性。

根据 https://github.com/StackExchange/blackbox的描述:

安全地将秘密存储在 VCS 回购(即 Git 或 Mercurial)中 命令使你很容易 GPG 加密特定的文件在一个回购 因此,它们在您的存储库中是“加密的” 当您需要查看或编辑脚本时,可以很容易地对它们进行解密 并将其解密以便生产中使用。

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

自从提出这个问题以来,我已经确定了一个解决方案,我在与一个小团队开发小型应用程序时使用这个解决方案。

地窖

Git-crypt 在文件名匹配特定模式时使用 GPG 对文件进行透明加密。例如,如果您添加到您的 .gitattributes文件..。

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

... 那么像 config.secret.json这样的文件总是会被加密推送到远程回购,但在本地文件系统中保持未加密状态。

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

这就是我的工作:

  • 保持所有的秘密作为 env vars 在 $HOME/。秘密(去-r 烫发) $HOME/。Bashrc 源代码(如果您打开。在别人面前,他们不会看到秘密)
  • 配置文件作为模板存储在 VCS 中,例如 config.properties 存储为 config.Properties.tmpl
  • 模板文件包含该机密的占位符,例如:

    Password = # # MY _ Password # #

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