gitリポジトリでパスワードを処理するためのベストプラクティスは何ですか?


225

Twitterにアクセスし、特定の状況でGrowl通知をポップアップ表示するために使用する小さなBashスクリプトを持っています。スクリプトを使用してパスワードを保存するのに最適な方法は何ですか?

このスクリプトをgitリポジトリにコミットしてGitHubで利用できるようにしたいのですが、これを実行している間、ログイン/パスワードをプライベートに保つための最良の方法は何なのでしょうか。現在、パスワードはスクリプト自体に格納されています。古いコミットにはすべてパスワードが含まれているため、プッシュする直前に削除することはできません。パスワードなしで開発することはできません。パスワードを外部の構成ファイルに保存する必要があると思いますが、何かを試す前に、これを処理するための確立された方法があるかどうかを確認したいと思いました。

回答:


256

これを行う一般的な方法は、構成ファイルからパスワード情報を読み取ることです。構成ファイルがと呼ばれている場合、サンプルデータを含む、リポジトリにfoobar.config呼び出されるファイルをコミットしますfoobar.config.example。プログラムを実行するにfoobar.configは、実際のパスワードデータで呼び出されるローカル(追跡されていない)ファイルを作成します。

以前のコミットから既存のパスワードを除外するには、機密データの削除に関するGitHubヘルプページをご覧ください。


4
ところで、foobar.configの例をリポジトリに追加してから、foobar.configを.ignoreファイルに追加できます。このように、サンプルのfoobar.configがクローンされたときに表示され、実際のパスワードはリポジトリに追加されません。
Mr_Chimp

16
@Mr_Chimp:.gitignoreファイルは、すでにリポジトリにある追跡ファイルには適用されません。たとえばgit add -u、変更されたファイルがすでににある場合でも追加されます.gitignore
グレッグヒューギル

1
補足として、ここにあなたが事故によって設定ファイルを追加し、あなたがGitの履歴から、それを削除したい場合は興味深いリンクです:help.github.com/articles/remove-sensitive-data
ロイック・ロペス

16
これらのパスワードをチームと共有するにはどうしますか?1つはローカルコピー(リポジトリにコミットされていない)を持っていること、もう1つはそれを自動ツール(デプロイメントなど)を使用するより大きなチームと共有することです
blueFast

2
@dangonfastと同じ質問があります。これは、大規模なチームには実用的ではないようです。
ジェイコブシュタム2017

25

アプローチは、環境変数を使用してパスワード(または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:このdev.to記事「APIキーを安全に保管する方法」というタイトルの記事は興味深いかもしれません。


1
ビルドの潜在的な「安全でない」コードが環境変数の内容を読み取らないようにするにはどうすればよいですか?
gorootde


16

グレッグは言ったが、私はそれがファイルをチェックインすることをお勧めしますことを付け加えたいですfoobar.config-TEMPLATE

名前、パスワード、その他の設定情報の例を含める必要があります。次に、実際のfoobar.configに何を含める必要があるかは非常に明白です。値が存在しなければならないすべてのコードfoobar.configと、それらの形式を調べる必要はありません。

多くの場合、データベース接続文字列などのように、設定値は明白ではない場合があります。


7

リポジトリでのパスワードの扱いは、正確な問題に応じて異なる方法で処理されます。

1.しないでください。

そして、それを回避する方法は、いくつかの返信でカバーされています-.gitignore、config.exampleなど

  • .gitignore:サーバーなどに保存しますが、Gitには保存しません(弱いソリューション)
  • 環境変数:https : //stackoverflow.com/a/30664318/3070485
  • Config.example:https ://stackoverflow.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などの多くの利点、たとえば変更をチェリー・ピックする機能を失うことに注意してください。

これに対する解決策は、キーと値のペアまたはおそらく単なる値を暗号化することです。たとえば、機密情報用の別のファイルがある場合はすべての値を暗号化でき、1つのファイルにすべての値がある場合は機密値のみを暗号化できます。(下記参照)

上記の私の例は、それを使用してテストを実行するすべての人にとって、またはいくつかの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)ソリューションから離れます。


3

トークン、パスワード、証明書、APIキーなどへのアクセスを保護、保存、制御するVaultを使用できます。たとえば、Ansibleは、プレイブックで使用されるパスワードまたは証明書を処理するAnsible Vaultを使用します


Ansible Vaultは、サンプルの構成ファイルを作成するだけに比べて、非常に複雑であることは確かです。
icc97

@ icc97はい、それは悲しいことです。しかし、この可能性について言及する必要があります。私の意見では、タスクがより複雑で、シングルユーザー環境用にいくつかのパスワードを保存することは、最初から特殊なソリューションを使用することをお勧めします。
El Ruso

2
将来の読者を支援するために:VaultとAnsible Vaultは、類似した名前を持つまったく異なる無関係なプロジェクトです
bltavares

2

これが私が使うテクニックです:

私のホームフォルダーに次のフォルダーを作成します。 .config

そのフォルダーに、パスワードとキーを外部化したいものの設定ファイルを配置します。

私は通常、次のような逆ドメイン名構文を使用します。

com.example.databaseconfig

次に、bashスクリプトでこれを行います。

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

|| exit 1設定ファイルをロードできない場合に終了するには、スクリプトが発生します。

私はbash、python、およびantスクリプトにその手法を使用しました。

私はかなり偏執狂的で、.gitignoreファイルが不注意なチェックインを防ぐのに十分堅牢であるとは思いません。さらに、それを監視するものは何もないため、チェックインが行われた場合、誰もそれを処理することはできません。

特定のアプリケーションで複数のファイルが必要な場合は、単一のファイルではなくサブフォルダーを作成します。


1

Railsでルビーを使用している場合、フィガロの宝石は非常に優れており、簡単で、信頼性があります。本番環境でも頭痛の種は少ないです。


4
その宝石の機能について詳しく教えてください。そうすれば、(潜在的に)多くの言語に適用できる「実践」と見なすことができます。
mattumotu

medium.com/@MinimalGhost/…には概要があり、基本的には構成ファイルからの
取り込み

0

信頼するが検証する。

.gitignore、このレポから「安全な」ディレクトリを除外します:

secure/

しかし、私は@ Michael Potterのパラノイアを共有します。したがって、.gitignoreを検証するために、この「安全な」ディレクトリがチェックインされた場合にklaxonを生成する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)
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.