はじめに
サーバのID/Passwordをソースにべた書きして開発することは誰しもあるかと思います。しかし先日話題になっていた「AWSから120万円の高額請求が来た話」というQiitaエントリのように、public gitリポジトリにAWSのアクセス情報を置こうものならばあっという間に悪用されてしまいます。
そんな他人に知られると悪用されかねない情報は「他人が容易にアクセス可能な場所に置かないこと」が鉄則なのですが、心掛けだけではどうやってもヒューマンエラーを避けることができません。そこで本エントリでは、そういったヒューマンエラーが起きた際の水際防止策として「gitリポジトリへのアクセス情報(ID/Passwordなど)の含まれたファイルのコミット」を機械的にリジェクトするgit-secretsの使い方を簡単に紹介します。1
Q: git-secretsは何ができる?
A: gitのcommit/commit message等をスキャンし、その中に事前設定した秘密情報が含まれていたら、そのcommitをリジェクトします。
より正確には、
-
git commit
時にそのcommitの中に、 - 任意のタイミングで過去のgit historyの中に、
- あるいは任意のタイミングで任意のファイルの中に、
事前設定された正規表現にマッチする情報が存在するか否かを検査します。awslabsが中心で開発しているだけあって、何よりもまず、AWSのcredentialの含まれたcommitを弾くのに非常に向いています。
準備
まずはマニュアル通りにインストールします。macOS Xならhomebrewが簡単です。
brew install git-secrets
そうでない場合は、make install
です。
$ git clone https://github.com/awslabs/git-secrets.git
$ cd git-secrets
$ make install
基本的な使い方
導入として、最も単純な例として、git commit
実行時、そのcommitの中にAWS向けの秘密情報が含まれているか否かを検査する方法を紹介しましょう。
はじめに、新規に立ち上げたgitリポジトリ、あるいは既存のgitリポジトリに対して、git secrets --install
を行うことで、当該のリポジトリをgit-secretsに対応させます。
$ git init
$ git secrets --install
✓ Installed commit-msg hook to .git/hooks/commit-msg
✓ Installed pre-commit hook to .git/hooks/pre-commit
✓ Installed prepare-commit-msg hook to .git/hooks/prepare-commit-msg
続いて、当該リポジトリのgit-secretsの設定を行います。git-secretsでは、予め用意されているコマンドオプションgit secrets --register-aws
を実行することで、自力で細かな設定をすることなくAWS向けのcommit検査設定を導入することができます。
$ git secrets --register-aws
試しにAWSのアクセスキー(ダミー)を入れたファイルを作成、git add
してcommitしてみます。
$ touch secret.txt
$ echo "aws_secret_access_key = ABcDe1F2hIjkl3nop45sTUv6XYz7aBcDEFghIJKL" > secret.txt
$ git commit -a
secret.txt:1:aws_secret_access_key = ABcDe1F2hIjkl3nop45sTUv6XYz7aBcDEFghIJKL
[ERROR] Matched one or more prohibited patterns
Possible mitigations:
- Mark false positives as allowed using: git config --add secrets.allowed ...
- Mark false positives as allowed by adding regular expressions to .gitallowed at repository's root directory
- List your configured patterns: git config --get-all secrets.patterns
- List your configured allowed patterns: git config --get-all secrets.allowed
- List your configured allowed patterns in .gitallowed at repository's root directory
- Use --no-verify if this is a one-time false positive
no changes added to commit
無事、リジェクトされました。
なお、上記のエラーメッセージにあるように、一時的に検査を除外してcommitしたい場合にはgit commit
コマンドに対して--no-verify
オプションを付与します。また、既存のリポジトリにあとからgit-secretsを対応させた場合、過去のcommit履歴を検査したいことがあるでしょう。その場合は、git secrets --scan-history
を行うことで、git historyをスキャンして検査することができます。まとめて以下に例示します。
git commit -a --no-verify
[master 61d9545] added credential with --no-verify
1 file changed, 1 insertion(+), 1 deletion(-)
$ git secrets --scan-history
61d954586149283a4f9ab70355320c15b846aa75:secret.txt:1:aws_secret_access_key = ABcDe1F2hIjkl3nop45sTUv6XYz7aBcDEFghIJKL
[ERROR] Matched one or more prohibited patterns
Possible mitigations:
- Mark false positives as allowed using: git config --add secrets.allowed ...
- Mark false positives as allowed by adding regular expressions to .gitallowed at repository's root directory
- List your configured patterns: git config --get-all secrets.patterns
- List your configured allowed patterns: git config --get-all secrets.allowed
- List your configured allowed patterns in .gitallowed at repository's root directory
- Use --no-verify if this is a one-time false positive
無理矢理追加したcommitが正しく検出されました。
検査設定のカスタマイズ
AWS向けの秘密情報の検査設定については便利なショートカットオプションが用意されていますが、他の情報については自力で設定が必要です。設定方法には
- 正規表現で検出パターンを定義する方法、
- 秘密情報のファイル(
~/.aws/credentials
など)を読み込み、その内容の各行のexact-matchの検出パターンとして設定する方法、
の2種類があります。
正規表現での検出パターン定義
git-secretsによりAWS向けの秘密情報「以外」を検出したい場合、commitから除外したい秘密情報のフォーマットに応じた正規表現を、ひとつひとつ登録していきます。ここでは、
password="top secret"
のように与えられるパスワードを検出パターンの正規表現 "password\s*=\s*\".+\"$"
として登録します。
$ git secrets --add "password\s*=\s*\".+\""
$ echo "password=\"ok my password\"" > password.txt
$ git add password.txt
$ git commit -a
password.txt:1:password="ok my password"
[ERROR] Matched one or more prohibited patterns
Possible mitigations:
- Mark false positives as allowed using: git config --add secrets.allowed ...
- Mark false positives as allowed by adding regular expressions to .gitallowed at repository's root directory
- List your configured patterns: git config --get-all secrets.patterns
- List your configured allowed patterns: git config --get-all secrets.allowed
- List your configured allowed patterns in .gitallowed at repository's root directory
- Use --no-verify if this is a one-time false positive
実際に検出できました。
秘密情報ファイルを読み込んだ検出パターン設定
秘密情報ファイルなどを読み込んで、その各行をexact-matchでの検出パターンとして設定する方法も存在します。
$ git secrets --add-provider -- <command to show secret info>
$ git secrets --add-provider -- cat ~/.my.password.list.txt
パスワードが1行ごとに羅列されているようなテキストファイルが存在、あるいは秘密情報を列挙するようなコマンドが存在するようなフレームワーク向けとして有効な手段です。(が、そういった条件に当たったことがなく、あまり利用したことはありません。)
サンプルパスワードなどの例外パターン設定
モックテストなどを行う際、決め打ちのサンプルパスワードを利用することは多いかと思います。本番のパスワードは検査で発見・除外してほしいけど、そういったパスワードまで除外されるちょっと困ります。なので、そういったサンプルパスワードは、検出されてもリジェクトされない例外パターンとして設定します。
前述の例では、正規表現"password\s*=\s*\".+\"$"
を検出パターンとして設定していました。このとき、このパターンに引っかかるpassword="my example password"
を例外として設定しましょう。
$ git secrets --add --allowed --literal "password=\"my example password\""
$ echo "my example password" > password.txt
$ git add password.txt
$ git commit -a
[master (root-commit) aa9098a] example password
1 file changed, 1 insertion(+)
create mode 100644 passowrd.txt
無事commitできました。なお、--add --allowed
とする(--literal
を抜く)と、例外パターンを正規表現で登録できます。が、例外はあくまで例外ですので、false negative 2 を避けるためにも正規表現などは使わずexact-matchで登録するべきです。
設定状況一覧の表示
現在のgit-secretsの設定状況はgit secrets --list
を実行することで一覧できます。参考として、--register-aws
オプションで設定される検出パターンは以下の通りです。
$ git secrets --list
secrets.providers git secrets --aws-provider
secrets.patterns [A-Z0-9]{20}
secrets.patterns ("|')?(AWS|aws|Aws)?_?(SECRET|secret|Secret)?_?(ACCESS|access|Access)?_?(KEY|key|Key)("|')?\s*(:|=>|=)\s*("|')?[A-Za-z0-9/\+=]{40}("|')?
secrets.patterns ("|')?(AWS|aws|Aws)?_?(ACCOUNT|account|Account)_?(ID|id|Id)?("|')?\s*(:|=>|=)\s*("|')?[0-9]{4}\-?[0-9]{4}\-?[0-9]{4}("|')?
secrets.allowed AKIAIOSFODNN7EXAMPLE
secrets.allowed wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
その他のTIPSとか
ファイルの検査
git-secretsはcommitではなくてファイル実体が除外設定に触れていないか否かの検査をすることも可能です。
$ git secrets --scan secrets.txt // ファイルの検査
$ git secrets --scan secretDir // ディレクトリの検査 **git ls-filesで出てくるものが対象**
$ git secrets --scan -r secretDir // サブディレクトリ内部も含めて検査
端末全体の保護
git secrets --register-aws
, --add
, --add-provider
コマンドに対して、--global
オプションを追加することで、global設定として~/.gitconfig
にgit-secretsの除外設定が書き込まれることになります。以降、既存のものも含み、git secrets --install
を実行したgitリポジトリに対して、当該のglobal設定がデフォルトで有効化されます。
git secrets --install
の省略
git init
後のgit secret --install
を忘れないために、こちらの記事の通り、
$ git secrets --install ~/.git-templates/git-secrets
$ git config --global init.templatedir '~/.git-templates/git-secrets'
を実行し、git init
時のテンプレートを作成しておきましょう。これでgit init
実行時にgit secrets --install
を実行したことと同じになります。
まとめ
AWS以外の場合、自分で検出パターンを指定するのがちょっとめんどくさいですが、「自分固有の秘密情報を不意に公開しない」という目的3のためにはgit-secretsは非常に有用です。特にAWSの設定については各リポジトリごとではなく、--register-aws --global
で端末全体のglobal設定で保険を掛けるのがいい手かと思います。
ただし、git-secretsさえ使っていれば安心というわけではなく、そもそもそういったファイルをgitリポジトリに追加しないようにすることが最も重要です。githubのREADME.mdにも「git-secretsの--register-aws
では、AWSの秘密情報のパターンはほとんど網羅してるけど全部とは限らないのでgit-secretsはあくまで追加の保険として利用しましょう」と明示的に記載されています。冒頭でも書きましたが、git-secretsのようなツールは、ヒューマンエラーが起きた際の水際防止策と考えておきましょう。
-
git-secretという似たプロジェクともありますが、こちらはgitリポジトリそのものをgpgで暗号化してアクセス制御しちゃおう、というものです。秘密情報が入ったファイルは
.gitsecret
というディレクトリに暗号化されて記録されていきます。こちらについても別エントリで紹介予定です。 ↩ -
git-secretsによる検査を通過してしまうが実際は本当のパスワードだったりする場合。 ↩
-
逆に、秘密情報を他人と共有して利用している場合には、別ルートでその秘密情報の受け渡しが必要となるのでgit-secretsは向いていません。秘密情報入りのgitリポジトリを複数人で共有したい、という場合には git-secret (sなし) が良い手かと思います。 ↩