bash 在 git 存储库中处理密码的最佳实践是什么?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2397822/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-09 19:00:59  来源:igfitidea点击:

What is the best practice for dealing with passwords in git repositories?

gitbashsecuritygithubpasswords

提问by kubi

I've got a little Bash script that I use to access twitter and pop up a Growl notification in certain situations. What's the best way to handle storing my password with the script?

我有一个小 Bash 脚本,用于访问 Twitter 并在某些情况下弹出 Growl 通知。使用脚本处理存储密码的最佳方法是什么?

I would like to commit this script to the git repo and make it available on GitHub, but I'm wondering what the best way to keep my login/password private while doing this is. Currently, the password is stored in the script itself. I can't remove it right before I push because all the old commits will contain the password. Developing without a password isn't an option. I imagine that I should be storing the password in an external config file, but I thought I'd check to see if there was an established way to handle this before I tried and put something together.

我想将此脚本提交到 git repo 并使其在 GitHub 上可用,但我想知道在执行此操作时保持登录名/密码私有的最佳方法是什么。目前,密码存储在脚本本身中。我无法在推送之前立即删除它,因为所有旧提交都将包含密码。没有密码的开发不是一种选择。我想我应该将密码存储在一个外部配置文件中,但我想在我尝试将一些东西放在一起之前,我会检查是否有一种既定的方法来处理这个问题。

回答by Greg Hewgill

The typical way to do this is to read the password info from a configuration file. If your configuration file is called foobar.config, then you would commit a file called foobar.config.exampleto the repository, containing sample data. To run your program, you would create a local (not tracked) file called foobar.configwith your realpassword data.

执行此操作的典型方法是从配置文件中读取密码信息。如果您的配置文件名为foobar.config,那么您将向foobar.config.example存储库提交一个名为的文件,其中包含示例数据。要运行您的程序,您需要创建一个foobar.config使用真实密码数据调用的本地(未跟踪)文件。

To filter out your existing password from previous commits, see the GitHub help page on Removing sensitive data.

要从以前的提交中过滤掉现有密码,请参阅 GitHub 帮助页面上的删除敏感数据

回答by scls

An approach can be to set password (or API key) using an environment variable. So this password is out of revision control.

一种方法是使用环境变量设置密码(或 API 密钥)。所以这个密码不受版本控制。

With Bash, you can set environment variable using

使用 Bash,您可以使用设置环境变量

export your_env_variable='your_password'

This approach can be use with continuous integration services like Travis, your code (without password) being stored in a GitHubrepository can be executed by Travis (with your password being set using environment variable).

这种方法可以与Travis等持续集成服务一起使用,存储在GitHub存储库中的代码(无密码)可以由 Travis 执行(使用环境变量设置密码)。

With Bash, you can get value of an environment variable using:

使用 Bash,您可以使用以下方法获取环境变量的值:

echo "$your_env_variable"

With Python, you can get value of an environment variable using:

使用 Python,您可以使用以下方法获取环境变量的值:

import os
print(os.environ['your_env_variable'])

PS: be aware that it's probably a bit risky (but it's a quite common practice) https://www.bleepingcomputer.com/news/security/javascript-packages-caught-stealing-environment-variables/

PS:请注意,这可能有点冒险(但这是一种很常见的做法)https://www.bleepingcomputer.com/news/security/javascript-packages-caught-stealing-environment-variables/

PS2: this dev.toarticle titled "How to securely store API keys"may be interesting to read.

PS2:dev.to这篇题为“如何安全地存储 API 密钥”的文章可能很有趣。

回答by Prof. Falken contract breached

What Greg saidbut I'd add that it's a good idea to check in a file foobar.config-TEMPLATE.

什么格雷格说,但我想补充一点,这是一个好主意,在一个文件检查foobar.config-TEMPLATE

It should contain example names, passwords or other config info. Then it is very obvious what the real foobar.config should contain, without having to look in all the code for which values must be present in foobar.configand what format they should have.

它应该包含示例名称、密码或其他配置信息。然后很明显真正的 foobar.config 应该包含什么,而不必查看所有值必须存在的代码foobar.config以及它们应该具有什么格式。

Often config values can be non obvious, like database connection strings and similar things.

通常配置值可能不明显,比如数据库连接字符串和类似的东西。

回答by Ivan

Dealing with passwords in repositories would be handled different ways depending on what your exact problem is.

根据您的确切问题是什么,处理存储库中的密码将采用不同的方式。

1. Don't do it.

1. 不要这样做。

And ways to avoid doing are covered in some replies - .gitignore, config.example, etc

一些回复中涵盖了避免这样做的方法 - .gitignore、config.example 等

or 2. Make repository accessible only to authorized people

或 2. 使存储库仅供授权人员访问

I.e. people that are allowed to know the password. chmodand user groups comes to mind; also problems like should Github or AWS employees be allowed to see things if you host your repositories or servers externally?

即被允许知道密码的人。chmod和用户群体浮现在脑海中;还有一些问题,比如如果您在外部托管存储库或服务器,是否应该允许 Github 或 AWS 员工查看内容?

or 3. Encrypt the sensitive data (purpose of this reply)

或 3. 加密敏感数据(此回复的目的)

If you want to store your config files containing sensitive information (like passwords) in a public location then it needs to be encrypted. The files could be decrypted when recovered from the repository, or even used straight from their encrypted form.

如果要将包含敏感信息(如密码)的配置文件存储在公共位置,则需要对其进行加密。这些文件可以在从存储库中恢复时被解密,甚至可以直接从它们的加密形式中使用。

An example javascript solution to using encrypted configuration data is shown below.

下面显示了使用加密配置数据的示例 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);

Decrypted Config File

解密的配置文件

So you can recover an encrypted config file writing just a few lines of Javascript.

因此,您只需编写几行 Javascript 即可恢复加密的配置文件。

Note that putting a file config.RSAinto a git repository would effectively make it a binary file and so it would lose many of the benefits of something like Git, e.g. ability to cherry pick changes to it.

请注意,将文件config.RSA放入 git 存储库将有效地使其成为二进制文件,因此它将失去 Git 之类的许多优点,例如能够对其进行挑选更改。

The solution to that might be to encrypt key value pairs or perhaps just values. You could encrypt all values, for example if you have a separate file for sensitive information, or encrypt just the sensitive values if you have all values in one file. (see below)

解决方案可能是加密密钥值对或可能只是值。您可以加密所有值,例如,如果您有一个单独的敏感信息文件,或者如果您将所有值都放在一个文件中,则只加密敏感值。(见下文)

My example above is a bit useless to anyone wanting to do a test with it, or as an example to start from as it assumes the existence of some RSA keys and an encrypted config file config.RSA.

我上面的例子对任何想要用它进行测试的人来说都是无用的,或者作为一个例子,因为它假设存在一些 RSA 密钥和加密的配置文件config.RSA

So here's some extra lines of code added to create RSA keys and a config file to play with.

所以这里添加了一些额外的代码行来创建 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);

Encrypting values only

仅加密值

fs.writeFileSync('config.RSA', JSON.stringify(config,null,2), 'utf8');

enter image description here

在此处输入图片说明

You can decrypt a config file with encrypted values using something like this.

您可以使用类似的方法解密带有加密值的配置文件。

const savedconfig = JSON.parse(fs.readFileSync('config.RSA', 'utf8'));
let config = {...savedconfig};
Object.keys(savedconfig).forEach(key => {
    config[key] = privatekey.decrypt(savedconfig[key], 'utf8');
});

With each configuration item on a separate line (e.g. Helloand Goodbyeabove), Git will recognize better what's going on in a file and will store changes to items of information as differences rather than complete files. Git will also be able to manage merges and cherry picks etc better.

将每个配置项放在单独的一行(例如HelloGoodbye以上),Git 将更好地识别文件中发生的事情,并将对信息项的更改存储为差异而不是完整的文件。Git 也将能够更好地管理合并和樱桃选择等。

However the more you want to version control changes to sensitive information, the more you are moving towards a SAFE REPOSITORY solution (2) and away from an ENCRYPTED INFO (3) solution.

然而,您越想对敏感信息的更改进行版本控制,您就越倾向于使用安全存储库解决方案 (2) 而远离加密信息 (3) 解决方案。

回答by Michael Potter

Here is a technique I use:

这是我使用的一种技术:

I create a folder in my home folder called: .config

我在我的主文件夹中创建一个文件夹,名为: .config

In that folder I place the config files for any number of things that I want to externalize passwords and keys.

在那个文件夹中,我将配置文件放置在我想要外部化密码和密钥的任意数量的东西中。

I typically use reverse domain name syntax such as:

我通常使用反向域名语法,例如:

com.example.databaseconfig

com.example.databaseconfig

Then in the bash script I do this:

然后在 bash 脚本中我这样做:

#!/bin/bash
source $HOME/.config/com.example.databaseconfig ||exit 1

The || exit 1causes the script to exit if it is not able to load the config file.

|| exit 1如果脚本无法加载配置文件,则会导致脚本退出。

I used that technique for bash, python, and ant scripts.

我将该技术用于 bash、python 和 ant 脚本。

I am pretty paranoid and don't think that a .gitignore file is sufficiently robust to prevent an inadvertent check-in. Plus, there is nothing monitoring it, so if a check-in did happen no one would find out to deal with it.

我很偏执,不认为 .gitignore 文件足够健壮以防止无意中签入。另外,没有任何监控它,所以如果签入确实发生了,没有人会发现处理它。

If a particular application requires more than one file I create subfolder rather than a single file.

如果特定应用程序需要多个文件,我会创建子文件夹而不是单个文件。

回答by El Ruso

One can use Vaultwhich secures, stores, and controls access to tokens, passwords, certificates, API keys, etc. For example Ansibleuses the Ansible Vaultwhich deals with passwords or certificates used in playbooks

可以使用Vault来保护、存储和控制对令牌、密码、证书、API 密钥等的访问。例如Ansible使用Ansible Vault来处理剧本中使用的密码或证书

回答by ahnbizcad

If you're using ruby on rails, the Figaro gem is very good, easy, and reliable. It has a low headache factor with the production environment too.

如果您在 rails 上使用 ruby​​,那么 Figaro gem 非常好、简单且可靠。它对生产环境的头痛因素也很低。

回答by Bob Stein

Trust but verify.

信任但要验证。

In .gitignorethis would exclude a "secure" directory from the repo:

.gitignore这将排除回购了“安全”目录:

secure/

But I share @Michael Potter's paranoia. So to verify .gitignore, here's a Pythonunit testthat would raise a klaxon if this "secure" directory ever gets checked in. And to check the check, a legitimate directory is tested too:

但我分享@迈克尔波特的偏执。所以为了验证 .gitignore,这里有一个Python单元测试,如果这个“安全”目录被签入,它会引发一个 klaxon。为了检查检查,一个合法的目录也会被测试:

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)