AWSアクセスキーをGitリポジトリに混入させないために git-secrets を導入した

git
269件のシェア(すこし話題の記事)

先日開催されたAWS Summit Tokyo 2017、わたしもいくつかセッションを聴講してきたのですが、「DevSecOps on AWS - Policy in Code」というセッション1にてgit-secretsというツールが紹介されていました。

これ以外にも、いくつかのセッションで言及されていたと思います。

git-secretsのことは以前から聞いてはいたのですが、自分自身があまりコードを書く環境にいなかったので、良くないとは思いつつも今まであまり気にしていませんでした。
ただ、AWSアクセスキーの漏洩が原因と思われる話を聞く機会はなかなか減りませんし、考えてみれば自分でも、AWSクレデンシャル情報に触れる機会の多いこの頃。

ちょうど良い機会と思って、自分の環境にも導入しました。

インストール

macOSにHomebrew環境の場合は、下記を実行するだけでインストールは完了です。

$ brew update
$ brew install git-secrets

それ以外の環境への導入は、上述したURLにあるとおりmake installすれば良いでしょう。

というかgit-secretsの実体はBASHスクリプトなので、PATHの通ったところに実行権限付きで置くだけでも動作します(MANPAGEも必要なら別途必要)。
今回自分は試しにそうやってみました。
普段からホームディレクトリ直下のbin/ディレクトリにはPATHを通してあるので、そこへインストールします。

$ curl -O https://raw.githubusercontent.com/awslabs/git-secrets/master/git-secrets
$ chmod +x ./git-secrets
$ mv -i ./git-secrets ~/bin/

$ which git-secrets
/Users/watanabe/bin/git-secrets

git secretsと実行してみて、ヘルプメッセージが表示されればインストール完了です。

$ git secrets
usage: git secrets --scan [-r|--recursive] [--cached] [--no-index] [--untracked] [<files>...]
    :

設定(1)

git-secretsを置くだけでは使えません。AWSアクセスキーの標準パターンをGitの設定ファイルに書き込む必要があります。

$ git secrets --register-aws --global

下記の様に、~/.gitconfigに設定が追記されたら成功です。

diff --git a/.gitconfig b/.gitconfig
index 027f0df..4f37ac5 100644
--- a/.gitconfig
+++ b/.gitconfig
@@ -13,3 +13,10 @@
        trustExitCode = true
 [commit]
        template = /Users/watanabe/.stCommitMsg
+[secrets]
+ providers = git secrets --aws-provider
+ patterns = [A-Z0-9]{20}
+ patterns = (\"|')?(AWS|aws|Aws)?_?(SECRET|secret|Secret)?_?(ACCESS|access|Access)?_?(KEY|key|Key)(\"|')?\\s*(:|=>|=)\\s*(\"|')?[A-Za-z0-9/\\+=]{40}(\"|')?
+ patterns = (\"|')?(AWS|aws|Aws)?_?(ACCOUNT|account|Account)_?(ID|id|Id)?(\"|')?\\s*(:|=>|=)\\s*(\"|')?[0-9]{4}\\-?[0-9]{4}\\-?[0-9]{4}(\"|')?
+ allowed = AKIAIOSFODNN7EXAMPLE
+ allowed = wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY

ちなみにallowedの行にあるのは、AWS自身が公式ドキュメントで使用しているアクセスキーのサンプルですね。2
これらに対しては警告を出さないよう、例外指定ができる機能があります。

やってみる(1)

試しにやってみます。

上記のサンプルからちょっとだけ変更したキー情報を含む、試験用のクレデンシャルファイルを作成しました。

  • AKIAIOSFODNN7EXAMPLo
  • wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEo

これらが検知できればスキャンは成功です。

Gitリポジトリじゃないファイルやディレクトリをスキャンするには--no-indexオプションを使用すると良いみたいです。

$ ls -l
total 8
-rw-r--r--  1 watanabe  staff  116  6 11 21:41 aws_credentials.txt

$ cat aws_credentials.txt
[default]
aws_access_key_id = AKIAIOSFODNN7EXAMPLo
aws_secret_access_key = wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEo

$ git secrets --scan --no-index
fatal: Not a git repository (or any of the parent directories): .git
aws_credentials.txt:2:aws_access_key_id = AKIAIOSFODNN7EXAMPLo
aws_credentials.txt:3:aws_secret_access_key = wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEo

[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

「Gitリポジトリじゃない」と言いながらも、ちゃんとスキャンしてくれました。なんというツンデレ

やってみる(2)

対象がGitリポジトリであればオプションは要らないし、fatalなんて言われません。

$ git init
$ git add .
$ git commit -m 'first'

$ git secrets --scan
aws_credentials.txt:2:aws_access_key_id = AKIAIOSFODNN7EXAMPLo
aws_credentials.txt:3:aws_secret_access_key = wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEo

[ERROR] Matched one or more prohibited patterns
    :

この場合はgit ls-filesでリストアップされるファイルだけが対象になります。
.gitignoreに書いてあるような、リポジトリに含まれないファイルはスキャンしないので、毎回false positiveが発生するようなこともないでしょうね。

設定(2) & やってみる(3)

とはいえこのままだと、毎回手動でスキャンする必要があります。

git-secretsにはコミット時にhookする機能もあるので、こちらを有効にしてみます。

$ 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

先ほど作成したサンプルのクレデンシャルファイルをコピーして、レポジトリに追加してみます。

$ cp -p aws_credentials.txt aws_credentials2.txt
$ git add ./aws_credentials2.txt

$ git commit -m 'hook test'
aws_credentials2.txt:2:aws_access_key_id = AKIAIOSFODNN7EXAMPLo
aws_credentials2.txt:3:aws_secret_access_key = wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEo

[ERROR] Matched one or more prohibited patterns
    :

$ git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    new file:   aws_credentials2.txt

見事にコミットが食い止められました。

公開を前提とするようなリポジトリには、忘れず有効にしておきたいですね。

設定(3)

リポジトリごとの設定も試してみます。
例えば先ほどallowedの話をしましたが、このレポジトリに限っては「AKIAIOSFODNN7EXAMPLo」も例外扱いにしてみます。

$ git secrets --scan
aws_credentials.txt:2:aws_access_key_id = AKIAIOSFODNN7EXAMPLo
aws_credentials.txt:3:aws_secret_access_key = wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEo
    :

$ git secrets --add --allowed AKIAIOSFODNN7EXAMPLo

$ git secrets --scan
aws_credentials.txt:3:aws_secret_access_key = wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEo
    :

2行目は警告されなくなりました。

この設定はリポジトリローカルの設定ファイル(.git/config)に書き込まれているので、他のレポジトリには影響しません3

こんな感じで、全体的にgit-secretsを使えるようにしつつ、リポジトリごとにカスタマイズしていくことが出来るようになっています。

Sourcetreeでも使ってみる

ふと思い立って、GUIのGitクライアントであるSourcetreeで上記のリポジトリを扱ってみました。

その結果がこちらになります:

1

git-secretsが正しく読み込まれず、hookに設定したスクリプトがエラーを吐いてしまいました。
これはよろしくありません。ツンデレさんは扱いが面倒です

解決方法はいくつかあるのではないかと思うのですが、自分で試してみた限り、

  • GitはSourcetreeビルトインのものではなく、システム(macOS)のものを使うよう設定する
  • 指定したgitと同じパスにgit-secretsを置く

という条件が必要でした。

手軽に解決するためには、下記の手順がよいかと思います。

  1. gitgit-secretsをHomebrewで導入する($ brew install git git-secrets
  2. Sourcetreeの設定で/usr/local/bin/gitを指定する(環境設定 > Git > 「システムの Git を使用する」)

2

特に 2. は、/usr/bin/git/usr/local/Cellar/git/2.13.1/bin/git4等にならないよう注意が必要です。

こうしておけば、commit時にちゃんとgit-secretsが働いてくれました。ちょろい

3

所感

使う前は「Set it and Forget it (一度設定したら後は放っておけばよい)」的なものかと思っていたんですが、残念ながらそうではなさそうでした。

とはいえ「リポジトリ単位」に限って言えば、最初に設定してしまえばずっと有効ですし、リポジトリごとにカスタマイズできたりhookを手軽に導入できたりと、その使い勝手の良さと有効性は大きいように思えます。

転ばぬ先の杖として、これまで使ったことのない方も導入を検討してみては如何でしょうか。

蛇足

なおHomebrewにはgit-secret(末尾に「s」なし)というものもあって、最初間違えてインストールしそうになってしまったのは秘密です。。。

$ brew info git-secret
git-secret: stable 0.2.2 (bottled), HEAD
Bash-tool to store the private data inside a git repo.
https://sobolevn.github.io/git-secret/

でもこれはこれで面白そうなツールなので、いつか折を見て使ってみたいと思います。

参考


  1. 正確には、併催されていたDev Day Tokyo 2017のセッションになります 
  2. 試しに使ってみたのですが、「The security token included in the request is invalid.」って言われました。残念 
  3. --globalオプションを使えば~/.gitconfigに書き込むことも可能です 
  4. Homebrewがバイナリの実体を放り込むディレクトリ。/usr/local/binにはシンボリックリンクが作成されます