在 git 存储库中处理密码的最佳实践是啥?
Posted
技术标签:
【中文标题】在 git 存储库中处理密码的最佳实践是啥?【英文标题】:What is the best practice for dealing with passwords in git repositories?在 git 存储库中处理密码的最佳实践是什么? 【发布时间】:2011-01-24 18:21:40 【问题描述】:我有一个小 Bash 脚本,用于访问 twitter 并在某些情况下弹出 Growl 通知。使用脚本处理存储密码的最佳方法是什么?
我想将此脚本提交到 git 存储库并在 GitHub 上提供,但我想知道在执行此操作时保持我的登录名/密码私有的最佳方法是什么。目前,密码存储在脚本本身中。我无法在推送之前将其删除,因为所有旧提交都将包含密码。没有密码的开发不是一种选择。我想我应该将密码存储在外部配置文件中,但我想在尝试将某些东西放在一起之前,我会先检查一下是否有既定的方法来处理这个问题。
【问题讨论】:
【参考方案1】:执行此操作的典型方法是从配置文件中读取密码信息。如果您的配置文件名为foobar.config
,那么您将提交一个名为foobar.config.example
的文件到存储库,其中包含示例数据。要运行您的程序,您将使用您的真实密码数据创建一个名为foobar.config
的本地(未跟踪)文件。
要从以前的提交中过滤掉您现有的密码,请参阅Removing sensitive data 上的 GitHub 帮助页面。
【讨论】:
顺便说一句,您可以将示例 foobar.config 添加到 repo,然后将 foobar.config 添加到 .ignore 文件。这样,示例 foobar.config 将在克隆时出现,并且您的实际密码不会添加到存储库中。 @Mr_Chimp:.gitignore
文件不适用于已在存储库中的跟踪文件。例如,git add -u
将添加一个已更改的文件,即使它已经在 .gitignore
中。
作为补充,这里有一个有趣的链接,以防您不小心添加了配置文件并且想从 git 历史记录中删除它:help.github.com/articles/remove-sensitive-data
您将如何与您的团队共享这些密码?一件事是拥有一个本地副本(未提交到 repo),另一件事是与更大的团队共享它,甚至使用自动工具(用于部署等)
我和@dangonfast 有同样的问题。对于大型团队来说,这似乎并不实用。【参考方案2】:
Greg said 什么,但我要补充一点,签入文件 foobar.config-TEMPLATE
是个好主意。
它应该包含示例名称、密码或其他配置信息。那么真正的 foobar.config 应该包含什么就非常明显了,而无需查看所有代码,哪些值必须存在于 foobar.config
中,以及它们应该具有什么格式。
通常配置值可能不明显,例如数据库连接字符串和类似的东西。
【讨论】:
【参考方案3】:如果您在 Rails 上使用 ruby,那么 Figaro gem 非常好、简单且可靠。它对生产环境的头痛系数也很低。
【讨论】:
您能否详细介绍一下该 gem 的功能?这样一来,它可以(可能)被视为适用于多种语言的“实践”。 medium.com/@MinimalGhost/… 有一个概述,它基本上似乎管理从配置文件中拉取东西【参考方案4】:一种方法是使用环境变量设置密码(或 API 密钥)。 所以这个密码不受版本控制。
使用 Bash,您可以使用设置环境变量
export your_env_variable='your_password'
这种方法可以与Travis 等持续集成服务一起使用,存储在GitHub 存储库中的代码(无密码)可由 Travis 执行(使用环境变量设置密码)。
使用 Bash,您可以使用以下方法获取环境变量的值:
echo "$your_env_variable"
使用 Python,您可以使用以下方法获取环境变量的值:
import os
print(os.environ['your_env_variable'])
PS:请注意,这可能有点冒险(但这是一种很常见的做法)https://www.bleepingcomputer.com/news/security/javascript-packages-caught-stealing-environment-variables/
PS2:这篇标题为"How to securely store API keys" 的dev.to
文章可能会很有趣。
【讨论】:
如何防止潜在的“不安全”代码构建读取环境变量的内容? 我建议看看blog.travis-ci.com/2013-06-10-secure-env-in-pull-requests和docs.travis-ci.com/user/pull-requests/…【参考方案5】:可以使用HashiCorp Vault 保护、存储和控制对令牌、密码、证书、API 密钥等的访问。
Ansible 还专门有一个 "Vault" feature(与 HashiCorp 产品无关)用于加密静态机密。
【讨论】:
与仅创建示例配置文件相比,我发现 Ansible Vault 确实过于复杂。 @icc97 是的,这很可悲。但是我们需要提到这种可能性。在我看来,对于比为单用户环境存储少量密码更复杂的任务,最好从一开始就使用专门的解决方案。 为了帮助未来的读者:Vault 和 Ansible Vault 是完全不同的不相关项目,但名称相似【参考方案6】:这是我使用的一种技术:
我在我的主文件夹中创建了一个文件夹,名为:
.config
在该文件夹中,我放置了我想要外部化密码和密钥的任意数量的配置文件。
我通常使用反向域名语法,例如:
com.example.databaseconfig
然后在 bash 脚本中我这样做:
#!/bin/bash
source $HOME/.config/com.example.databaseconfig ||exit 1
|| exit 1
会导致脚本在无法加载配置文件时退出。
我将该技术用于 bash、python 和 ant 脚本。
我很偏执,不认为 .gitignore 文件足够强大以防止无意签入。另外,没有任何监控它,所以如果确实发生了签到,没有人会发现来处理它。
如果特定应用程序需要多个文件,我会创建子文件夹而不是单个文件。
【讨论】:
【参考方案7】:根据您的具体问题,处理存储库中的密码的方式会有所不同。
1。不要这样做。
一些回复中涵盖了避免这样做的方法 - .gitignore、config.example 等
.gitignore:存储在服务器等上,但不存储在 Git 上(弱解决方案) 环境变量:https://***.com/a/30664318/3070485 配置示例:https://***.com/a/2397905/3070485 命令行参数:程序启动时手动输入密码或 2. 仅授权人员访问存储库
即被允许知道密码的人。 chmod
和用户组浮现在脑海中;还有一些问题,比如如果您在外部托管存储库或服务器,是否应该允许 Github 或 AWS 员工查看内容?
或 3. 加密敏感数据(本回复的目的)
如果您想将包含敏感信息(如密码)的配置文件存储在公共位置,则需要对其进行加密。这些文件在从存储库中恢复时可以被解密,甚至可以直接从它们的加密形式中使用。
使用加密配置数据的示例 javascript 解决方案如下所示。
const fs = require('fs');
const NodeRSA = require('node-rsa');
let privatekey = new NodeRSA();
privatekey.importKey(fs.readFileSync('private.key', 'utf8'));
const config = privatekey.decrypt(fs.readFileSync('config.RSA', 'utf8'), 'json');
console.log('decrypted: ', config);
因此,您只需编写几行 Javascript 即可恢复加密的配置文件。
请注意,将文件 config.RSA
放入 git 存储库将有效地使其成为二进制文件,因此它将失去 Git 之类的许多好处,例如能够选择对其进行更改。
解决方案可能是加密键值对或仅加密值。您可以加密所有值,例如,如果您有一个单独的敏感信息文件,或者如果您在一个文件中包含所有值,则只加密敏感值。 (见下文)
我上面的例子对任何想用它进行测试的人来说有点没用,或者作为一个例子开始,因为它假设存在一些 RSA 密钥和加密的配置文件config.RSA
。
所以这里添加了一些额外的代码行来创建 RSA 密钥和一个配置文件。
const fs = require('fs');
const NodeRSA = require('node-rsa');
/////////////////////////////
// Generate some keys for testing
/////////////////////////////
const examplekey = new NodeRSA(b: 2048);
fs.writeFileSync('private.key', examplekey.exportKey('pkcs8-private'));
fs.writeFileSync('public.key', examplekey.exportKey('pkcs8-public'));
/////////////////////////////
// Do this on the Machine creating the config file
/////////////////////////////
const configToStore = Goodbye: 'Cruel world';
let publickey = new NodeRSA();
publickey.importKey(fs.readFileSync('public.key', 'utf8'));
fs.writeFileSync('config.RSA', publickey.encrypt(configToStore, 'base64'), 'utf8');
/////////////////////////////
// Do this on the Machine consuming the config file
/////////////////////////////
let privatekey = new NodeRSA();
privatekey.importKey(fs.readFileSync('private.key', 'utf8'));
const config = privatekey.decrypt(fs.readFileSync('config.RSA', 'utf8'), 'json');
console.log('decrypted: ', config);
仅加密值
fs.writeFileSync('config.RSA', JSON.stringify(config,null,2), 'utf8');
您可以使用类似这样的方式解密具有加密值的配置文件。
const savedconfig = JSON.parse(fs.readFileSync('config.RSA', 'utf8'));
let config = ...savedconfig;
Object.keys(savedconfig).forEach(key =>
config[key] = privatekey.decrypt(savedconfig[key], 'utf8');
);
通过将每个配置项放在单独的行上(例如上面的 Hello
和 Goodbye
),Git 将更好地识别文件中发生的事情,并将对信息项的更改存储为差异而不是完整的文件。 Git 也将能够更好地管理合并和樱桃挑选等。
但是,您越想对敏感信息进行版本控制更改,您就越倾向于安全存储库解决方案 (2) 并远离加密信息 (3) 解决方案。
【讨论】:
【参考方案8】:信任但验证。
在.gitignore
中,这将从存储库中排除“安全”目录:
secure/
但我分享@Michael Potter 的偏执狂。因此,为了验证 .gitignore,这里有一个 Python 单元测试,如果这个“安全”目录被签入,它会发出警报。为了检查,一个合法的目录也被测试了:
def test_github_not_getting_credentials(self):
safety_url = 'https://github.com/BobStein/fliki/tree/master/static'
danger_url = 'https://github.com/BobStein/fliki/tree/master/secure'
self.assertEqual(200, urllib.request.urlopen(safety_url).status)
with self.assertRaises(urllib.error.HTTPError):
urllib.request.urlopen(danger_url)
【讨论】:
以上是关于在 git 存储库中处理密码的最佳实践是啥?的主要内容,如果未能解决你的问题,请参考以下文章
将 Play 代码从 git 存储库部署到生产环境的最佳实践是啥?
使用 ML Studio API 开发 CD/CI 的最佳实践是啥?
Git:将“git clone”到现有文件夹的最佳实践是啥?
MVC 验证 - 使用服务层保持 DRY - 最佳实践是啥?