秘密鍵とパスワードをバージョン管理システムに安全に保存するにはどうすればよいですか?


134

バージョン管理システムでは、開発サーバーと本番サーバーのホスト名やポートなどの重要な設定を保持しています。しかし、VCSリポジトリに秘密秘密鍵やデータベースパスワードなど)を保持することは悪い習慣であることは知っています。

しかし、パスワードは、他の設定と同様に、バージョン管理する必要があるようです。では、パスワードのバージョン管理を維持する適切な方法何でしょうか?

私はそれが維持伴うだろうと想像秘密を自分の「秘密の設定」ファイルにして持っていること、ファイルが暗号化され、バージョン管理します。しかし、どんなテクノロジー?そして、これを正しく行う方法は?それについて完全に取り組むより良い方法はありますか?


私は一般的に質問しますが、私の特定のインスタンスでは、gitgithubを使用してDjango / Pythonサイトの秘密鍵とパスワードを保存したいと思います。

また、理想的なソリューションは、gitでプッシュ/プルするときに魔法のようなものを実行します。たとえば、暗号化されたパスワードファイルが変更された場合、パスワードを要求して所定の位置に復号化するスクリプトが実行されます。


編集:わかりやすくするために、私プロダクションシークレットを格納する場所について質問しています。


1
実際には、レポ全体を非公開にするためにいくらかお金を前に立てます。
John Mee

29
@JohnMee私は実際にプライベートリポジトリの料金を既に支払っていますが、要点は残っています。リポジトリに機密情報を保存するべきではありません。
クリスW.

1
答えを満足させるのが難しい理由の大部分は、データベースに接続するための昔ながらの平文パスワードがそれほど敵意のない時代の遺物であることです。正しい答えは「あなたのコードは秘密を必要とすべきではない」のようなものですが、あなたがアクセスしているシステムはあなたに多くの選択肢を与えません。
msw 2012

4
どうして?外部サービスのパスワードを制御するバージョンにはzilch値があります。バージョン管理の主な価値は、正常に動作していることがわかっているアプリケーションの履歴リビジョンを検査して実行できることです。ただし、古いパスワードは役に立ちません。取り消された場合、二度と機能しなくなります。
大佐パニック

回答:


100

重要な設定ファイルをバージョン管理で維持しながら暗号化するのは、まさに正しいことです。あなたが言及したように、最良の解決策は、Gitが特定の機密ファイルをプッシュするときに透過的に暗号化して、ローカルで(つまり、証明書を持つ任意のマシンで)設定ファイルを使用できるようにすることですが、GitやDropboxなどの誰でもファイルをVCに保存しても、プレーンテキストで情報を読み取ることはできません。

プッシュ/プル中の透過的な暗号化/復号化に関するチュートリアル

この要旨https://gist.github.com/873637は、opensslでGitのsmudge / cleanフィルタードライバーを使用して、プッシュされたファイルを透過的に暗号化する方法のチュートリアルを示しています。初期設定を行うだけです。

仕組みの概要

基本的に、.gitencrypt3つのbashスクリプトを含むフォルダーを作成します。

clean_filter_openssl 
smudge_filter_openssl 
diff_filter_openssl 

復号化、暗号化、およびGit diffのサポートのために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。要旨を参照してください。

機密情報を含むリポジトリには、.gitencryptディレクトリ(Gitがプロジェクトを透過的に暗号化/復号化するために必要なすべてを含む)を参照し、ローカルマシンに存在する.gitattributeファイル(暗号化されておらず、リポジトリに含まれている)が必要です。

.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ホストにプッシュされるリポジトリ全体が透過的に暗号化され、リポジトリ全体が復号化されるため、ローカルで完全に復号化されます。必要な動作を実現するには、1つまたは複数のプロジェクトの機密ファイルを1つのsensitive_settings_repoに配置します。重要なファイルを同じリポジトリに置く必要がある場合は、この透過的な暗号化技術がGitサブモジュールhttp://git-scm.com/book/en/Git-Tools-Submodulesでどのように機能するかを調査できます。

固定パスフレーズを使用すると、攻撃者が多くの暗号化されたリポジトリ/ファイルにアクセスできる場合、理論的にはブルートフォースの脆弱性につながる可能性があります。IMO、この可能性は非常に低いです。このチュートリアルの最後にあるメモで述べたように、固定パスフレーズを使用しないと、異なるマシンのリポジトリのローカルバージョンで、変更が「git status」で発生したことが常に表示されます。


1
とても面白いです。これは、私が望んでいるものとほぼ同じように聞こえます(リポジトリ全体の暗号化を除いて)。
Chris W.

複数のアプリケーションのすべての機密設定ファイルを1つの暗号化されたリポジトリに保存するか、機密設定を含む暗号化されたリポジトリをGitサブモジュールとしてプロジェクトに追加することができます(git-scm.com/book/en/Git-Tools-Submodules)
12

(暗号化された)サブモジュールに本番パスワード/設定を保存することは珍しくありません。stackoverflow.com/questions/11207284/…。プロジェクト間の設定の管理も簡単になります。
12

github.com/AGWA/git-cryptで更新されたソリューションを確認することをお勧めします。個々のファイルを暗号化できるという利点があり、「おそらく意味的に安全」であると主張しています。要点の著者自身は、このツールの方が優れているとgithub.com/shadowhand/git-encrypt提案しています。
geekley

52

Heroku は設定と秘密鍵のための環境変数の使用を推進ます:

このような構成変数を処理するための従来のアプローチは、ソースの下にそれらを配置することです-ある種のプロパティファイルに。これはエラーが発生しやすいプロセスであり、多くの場合、アプリ固有の構成で個別の(そしてプライベートな)ブランチを維持する必要があるオープンソースアプリでは特に複雑です。

より良い解決策は、環境変数を使用し、コードにキーを入れないことです。従来のホストまたはローカルでの作業では、bashrcに環境変数を設定できます。Herokuでは、config varsを使用します。

Foremanと.envファイルを使用して、Herokuは環境変数をエクスポート、インポート、同期するためのうらやましいツールチェーンを提供します。


個人的には、秘密の鍵をコードと一緒に保存するのは間違っていると思います。キーはコードに付帯していないサービス用であるため、ソース管理とは根本的に矛盾しています。。1つの恩恵は、開発者がHEADのクローンを作成し、セットアップなしでアプリケーションを実行できることです。ただし、開発者がコードの履歴リビジョンをチェックアウトするとします。コピーには昨年のデータベースパスワードが含まれるため、アプリケーションは今日のデータベースに対して失敗します。

上記のHerokuメソッドを使用すると、開発者は昨年のアプリをチェックアウトして、今日のキーで構成し、今日のデータベースに対して正常に実行できます。


1
この答えには十分な注意が払われていませんが、ほとんどの場合Linuxの方法と一致しています。
Nikolay Fominyh

11
したがって、環境変数がbashrcに設定されていて、新しいサーバーをデプロイしている場合、bashrcは何によって作成されますか?パスワードをソースコードリポジトリから展開構成に移動するだけではありませんか?(おそらく、ソースコードリポジトリにも、独自のリポジトリにもありますか?)
ジョナサンハートレー

@JonathanHartley Djangoアプリのコードリポジトリに.bashrcを含めないでください。
スティーブ

4
申し訳ありませんが、私のコメントはあいまいですが、それは私が本当に混乱しているためです。私はこの答えの視点の音が好きですが、それを完全に理解したことはありません。それぞれが複数のホスト、そしておそらく複数のタイプのホストを含​​むいくつかの異なる環境にデプロイしている場合、当然、各ホストに存在する.bashrcファイルの作成を自動化して、環境変数を設定する必要があります。それで、私のソースとは別に、展開時に.bashrcの環境変数になるすべての設定を含む2番目のリポジトリが必要だという答えはありますか?
Jonathan Hartley

1
これらは、導入先のPERマシンで1度構成するだけで済みます。展開プロセスが「新しいマシンを起動し、トラフィックをリダイレクトする前に問題がないことをテストしてから、古いマシンを頭の中で撃つ」場合、これはIMHOがベストプラクティスであり、実際にセットの作成を自動化する必要があります。環境変数。
ジョナサンハートレイ

16

私の意見では、最もクリーンな方法は環境変数を使用することです。たとえば、.distファイルを処理する必要はなく、本番環境でのプロジェクトの状態はローカルマシンの状態と同じになります。

Twelve-Factorアプリを読むことをお勧めしますの設定の章をます。興味がある場合は他の章もください。


6
環境変数は、秘密の設定でアプリケーションを実行するための良い方法のようです...しかし、それでもそれらの設定をどこに保持するかという質問には答えません
Chris W.

2
通常、各アプリのREADMEファイルが必要です。そこで、設定する環境変数を指定します。プロジェクトをデプロイするたびに、手順に従って各環境変数を設定します。多くexport MY_ENV_VAR=のでシェルスクリプトを作成することもできます。デプロイするときは、適切な値とsourceそれを入力するだけです。よるならば続けるあなたは平均バージョンの設定を、あなたは最初の場所でこれを行うべきではありません。
Samy Dindane-2012

また、Twelve-Factorアプリに賛成票を投じてください。これは本当に素晴らしいことです。
Chris W.

4
@Samy:展開を自動化した場合はどうなりますか?
Jonathan Hartley、2013

3
@Samy私はまだ環境変数がどのように設定されるのか理解していません。12ファクターアプリのページでも明確になりません(現在のプロジェクトではないHerokuを使用している場合を除きます)。生成スクリプトは中央の構成ストアに問い合わせる必要があると言っていますか?設定データをください」と表示され、設定する環境変数の値が返されます。その場合、生成されたスクリプトはもう必要ないと思います。私は乱暴にここで推測しています、私は正しい木を吠えていますか?
ジョナサンハートレイ

10

オプションは、プロジェクトにバインドされた認証情報を暗号化されたコンテナ(TrueCryptまたはKeepass)に入れてプッシュすることです。

以下の私のコメントからの回答として更新:

ところで興味深い質問です。私はこれを見つけました:github.com/shadowhand/git-encryptこれは自動暗号化に非常に有望に見えます


自動化できるものがあるといいですね。暗号化されたパスワードファイルが変更されると、新しいファイルが自動的に復号化されます。
Chris W.

7
ところで興味深い質問。私はこれを見つけました:github.com/shadowhand/git-encryptこれは自動暗号化に非常に有望に見えます。
シュネック2012

1
すごい。説明をgit-encrypt正確に私は、サードパーティのストレージサーバにホストされているリモートのgitリポジトリで作業する場合、データの機密性が時々心配になります。この記事では、Gitのリポジトリを設定するための手順を紹介します」を探しています何のような音ローカルの作業ディレクトリは通常どおり(暗号化されていません)、コミットされたコンテンツは暗号化されています。」(もちろん、私は自分のコンテンツのサブセットのみを暗号化したい...)
Chris W.

@schneckは、コメントを回答として投稿して、Chrisがそれを受け入れることができるようにします-彼が探しているもののようです。
Tony Abou-Assaleh 2012

9

そのために構成ファイルを使用し、バージョン管理しないことをお勧めします。

ただし、ファイルの例をバージョン管理することはできます。

開発設定の共有に問題はありません。当然のことながら、貴重なデータは含まれていません。


1
しかし、正規のパスワードレコードはどこに保存するのでしょうか。ある日突然爆発する可能性のあるマシンの構成ファイルにのみそのデータを置くと、私は緊張します。
クリスW.

@ChrisW。マシンが爆発した場合、必ずしもパスワードが必要になるとは限りません...しかし、運用マシンにデータのコピーが1つしかない場合は、赤信号が発生します。しかし、それはVCSにあるべきだという意味ではありません。磁気および光学メディア上の増分バックアップによって補足されたRAID、フルバックアップが必要です。多くの企業には、パスワードやその他の機密情報を紙に保存する方法と場所を決定する変更管理手順があります。
Steve Buzonas

@ChrisW私は荒っぽくなりたくないのですが、あなたは私たちに真実を語らず、保存したいパスワードは開発ではなく本番で使用されているようです。これは本当ではないですか?そうでなければ、なぜ開発またはテストマシンと開発パスワードを気にするのですか?誰もそんなことはしないだろう。
tiktak 2012

ところで、私たちの会社では、すべての開発パスワードは紙とイントラネットで入手できます。価値がないからです。私たちが開発するソフトウェアには認証が必要なため、そこにあります。
ティクタク

@tiktak、あなたは正しいです-私の質問は、製品のパスワードに関して何をするかについてです。私は特に、開発用パスワードをA VCSに平文で保存することは気にしません。それを十分に明確にしていない場合は申し訳ありません。
Chris W.

7

BlackBoxは最近StackExchangeによってリリースされましたが、まだ使用していませんが、問題に正確に対処し、この質問で要求されている機能をサポートしているようです。

https://github.com/StackExchange/blackboxの説明から:

シークレットをVCSリポジトリ(GitまたはMercurialなど)に安全に保存します。これらのコマンドを使用すると、リポジトリ内の特定のファイルをGPGで簡単に暗号化できるため、リポジトリで「保存時に暗号化」されます。ただし、スクリプトを使用すると、スクリプトを表示または編集する必要があるときに簡単に復号化し、本番環境で使用するために復号化できます。


7

この質問をして以来、私は解決策を決めました。これは、小さなチームで小さなアプリケーションを開発するときに使用する解決策です。

git-crypt

git-cryptはGPGを使用して、ファイルの名前が特定のパターンに一致する場合にファイルを透過的に暗号化します。一応、.gitattributesファイルに追加すると...

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

...のようなファイルconfig.secret.jsonは常に暗号化されたリモートリポジトリにプッシュされますが、ローカルファイルシステムでは暗号化されません。

保護されたファイルを復号化できる新しいGPGキー(人物)をリポジトリに追加する場合は、を実行しgit-crypt add-gpg-user <gpg_user_key>ます。これにより、新しいコミットが作成されます。新しいユーザーは、後続のコミットを復号化できます。


5

私は一般的に質問しますが、私の特定のインスタンスでは、gitとgithubを使用してDjango / Pythonサイトの秘密鍵とパスワードを保存したいと思います。

いいえ、しないでください。たとえそれがあなたのプライベートリポジトリであり、それを共有するつもりがない場合でも、そうしないでください。

local_settings.pyを作成してVCS ignoreに配置し、settings.pyで次のようにします。

from local_settings import DATABASES, SECRET_KEY
DATABASES = DATABASES

SECRET_KEY = SECRET_KEY

シークレットの設定が多用途である場合、私はあなたが何か間違ったことをしていると言いたいです


9
しかし、私はまだそれらの秘密をどこかに追跡する必要があります。たとえば、これらの線に沿ったキーパスまたは何か、そうですか?
クリスW.

個人データの保存の規制と実施は、プロジェクトの対象となる会社の方針に依存します。サードパーティのテスターやプログラマーがこれらを見ることができるので、プロジェクトのソースコードが適切な場所であると私は強く疑います
Hedde van der Heide

4

編集:私はあなたが以前のパスワードのバージョンを追跡したいと思います-たとえば、パスワードの再利用を防止するスクリプトなどのために。

私はGnuPGが最善の方法だと思います-クラウドサービスに格納されたリポジトリコンテンツを暗号化するために、すでに1つのgit関連プロジェクト(git-annex)で使用されています。GnuPG(gnu pgp)は、非常に強力な鍵ベースの暗号化を提供します。

  1. ローカルマシンにキーを保持します。
  2. 無視されたファイルに「mypassword」を追加します。
  3. コミット前のフックでは、mypasswordファイルをgitによって追跡されるmypassword.gpgファイルに暗号化し、それをコミットに追加します。
  4. マージ後のフックでは、mypassword.gpgをmypasswordに復号化するだけです。

「mypassword」ファイルが変更されなかった場合は、暗号化すると同じ暗号文が生成され、インデックスに追加されません(冗長性なし)。mypasswordをわずかに変更すると、大幅に異なる暗号文が生成され、ステージング領域のmypassword.gpgはリポジトリ内のものと大きく異なるため、コミットに追加されます。攻撃者がgpgキーを手に入れても、パスワードをブルートフォースにする必要があります。攻撃者が暗号文を使用してリモートリポジトリにアクセスした場合、一連の暗号文を比較できますが、その数は無視できない利点を与えるには不十分です。

後で.gitattributesを使用して、パスワードのgit diffを終了するためのオンザフライの復号化を提供できます。

また、異なるタイプのパスワードなどに個別のキーを使用することもできます。


3

通常、私はパスワードを設定ファイルとして分離します。そしてそれらをdistにします。

/yourapp
    main.py
    default.cfg.dist

そして、私が実行するとき、コピーされmain.pyたものに実際のパスワードを入れますdefault.cfg

ps。gitまたはhgで作業する場合。*.cfg作成するファイルを無視する.gitignoreか、.hgignore


.distファイルは、私が話していたものです:実際の構成ファイルの例。".dist"拡張子を削除して名前を変更する(またはそれ以上:コピーする)ことによってのみソフトウェアを実行できるようにすることをお勧めします。つまり、ソフトウェアを数秒で試すことができます。一日。
tiktak 2012

3

設定を上書きする方法を提供する

これは、構成を完全にしたり、ホスト名や資格情報などを含めたりせずに、チェックインする構成の適切なデフォルトのセットを管理する最良の方法です。デフォルトの設定を上書きする方法はいくつかあります。

(他の人がすでに述べたように)環境変数はそれを行う1つの方法です。

最良の方法は、デフォルトの構成値を上書きする外部構成ファイルを探すことです。これにより、Chef、Puppet、Cfengineなどの構成管理システムを介して外部構成を管理できます。構成管理は、コードベースとは別の構成を管理するための標準的な回答です。そのため、単一のホストまたはホストのグループで構成を更新するためにリリースを行う必要はありません。

参考までに:特にリソースが限られている場所では、クレデンシャルの暗号化が常にベストプラクティスであるとは限りません。クレデンシャルを暗号化しても、追加のリスク軽減は得られず、単に不必要な複雑なレイヤーが追加されるだけの場合もあります。決定を下す前に、適切な分析を行っていることを確認してください。


2

たとえばGPGを使用して、パスワードファイルを暗号化します。ローカルマシンとサーバーにキーを追加します。ファイルを復号化し、レポフォルダーの外に置きます。

ホームフォルダにあるpasswords.confを使用しています。デプロイのたびに、このファイルは更新されます。


次に、ソフトウェアはパスワードファイルを復号化する必要があります。
tiktak 2012

まあ、サイトを展開するときだけ、パスワードは解読されてプレーンテキストのパスワードファイルに書き込まれます
Willian

2

いいえ、秘密鍵とパスワードはリビジョン管理の対象にはなりません。すべてのユーザーがこれらのサービスにアクセスできるとは限らない場合でも、本番環境で使用される機密サービス資格情報を知っていることで、リポジトリへの読み取りアクセスで全員に負担をかける理由はありません。

Django 1.4以降、Djangoプロジェクトにproject.wsgiapplicationオブジェクトを定義するモジュールが同梱されており、これを使用して、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プロセスのみがファイルの内容を読み取ることができるようにすることができます。


2

シークレットにVCSが必要な場合は、少なくとも実際のコードから分離された2番目のリポジトリにそれらを保持する必要があります。したがって、チームメンバーにソースコードリポジトリへのアクセス権を与えることができ、チームメンバーはあなたの資格情報を見ることができません。さらに、このリポジトリを別の場所(たとえば、githubではなく暗号化されたファイルシステムを使用する独自のサーバー)でホストし、本番システムにチェックアウトするには、git-submoduleなどを使用できます。


1

別のアプローチとしては、バージョン管理システムでのシークレットの保存を完全に回避し、代わりに、キーのローリングと監査が可能なシークレットストレージであるhashicorpのvaultなどのツールを使用し、APIと埋め込み暗号化を使用する方法があります。


1

これが私がすることです:

  • $ HOME / .bashrcがソースとする$ HOME / .secrets(go-r perms)にすべてのシークレットを環境変数として保持します(このようにすると、誰かの前で.bashrcを開くと、シークレットは表示されません)。
  • 設定ファイルは、config.properties.tmplとして保存されたconfig.propertiesなどのテンプレートとしてVCSに保存されます
  • テンプレートファイルには、次のようなシークレットのプレースホルダーが含まれています。

    my.password = ## MY_PASSWORD ##

  • アプリケーションの配備時に、テンプレートファイルをターゲットファイルに変換するスクリプトが実行され、## MY_PASSWORD ##を$ MY_PASSWORDの値に変更するなど、プレースホルダーを環境変数の値に置き換えます。


0

システムが提供している場合は、EncFSを使用できます。したがって、暗号化されたデータをリポジトリのサブフォルダとして保持しながら、アプリケーションに、マウント解除されたデータの復号化されたビューを提供できます。暗号化は透過的であるため、プルまたはプッシュ時に特別な操作は必要ありません。

ただし、EncFSフォルダーをマウントする必要があります。これは、バージョン付きフォルダー以外の場所に保存されているパスワード(環境変数など)に基づいてアプリケーションで実行できます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.