最近、アプリケーションなどから利用するAWSの認証情報(credentials)をgithubなどの公開リポジトリに誤ってコミットしてしまい、不正利用され高額な使用料を請求されるケースが増えています。
いくらルートアカウントを無効化してIAMユーザーを使おうが、2段階認証を導入しようが、認証情報をヒューマンミスで公開してしまっては意味がありません。
万が一、認証情報を公開してしまった場合は、一刻も早くAWSの管理コンソールから公開してしまった認証情報のアクセス権限を取り消しましょう。もしそれが会社で使っている認証情報だとしたら本当に1分1秒を争いますので、深夜だろうが構わずにAWSを管理しているエンジニアを電話で叩き起こして助けを求めてください。放置すると高確率で首が飛びます。
こういった大事故を防ぐためにAWSが公開している git-secrets というgitのプラグインがあります。
https://github.com/awslabs/git-secrets
インストールする
つい先月末までは、インストールするためにソースをローカルにクローンしてきた後で make install する必要がありました。しかし、先月の26日にformulaがHomebrewのmasterにマージされ、brew経由でより簡単にインストールできるようになりました。
昔からhomebrewを使っていた人は、formulaの一覧を更新しないとインストールできないため、まずupdateしてからinstallします。
| 
					 1 2  | 
						$ brew update $ brew install git-secrets  | 
					
git secrets コマンドが使えるようになっているはずです。
リポジトリへ設定
git-secretsはまだ有効になっていません。
リポジトリ単位で有効化する必要があるので、ここでは適当に新しいリポジトリを作ることにします。
| 
					 1 2  | 
						$ mkdir test; cd $_ $ git init  | 
					
リポジトリの中にcdしたら –install で有効化。
| 
					 1 2 3 4  | 
						$ 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  | 
					
見ての通り、pre-commitをフックして実現しています。
拒否ルールの設定
次にどのルールにマッチしたとき、コミットを拒否するか指定します。AWSの認証情報については、 --register-aws パラメータを使えます。
| 
					 1  | 
						git secrets --register-aws  | 
					
設定された拒否ルールは、 --list パラメータで確認できます。
| 
					 1 2 3 4 5 6 7  | 
						$ 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  | 
					
上の出力3行目では、大文字英数20文字にマッチして拒否しているようですね。乱暴じゃないかと思いましたが、実際プログラミングをしていて大文字固定で20文字も打ちませんからね。
6,7行目はAWSの公式ドキュメントなどでも使われている、サンプルのアクセスキー/シークレットキー(Allowed patterns for example AWS keys)だそうです。
実際に使ってみる
ちゃんと弾いてくれるか確認してみます。
| 
					 1  | 
						vim test.php  | 
					
| 
					 1 2 3  | 
						<?php $AWSAccessKeyId = "AKIAIOSFODNN1EXAMPLE"; $AWSSecretKey = "wJalrXUtnFEMI/K1MDENG/bPxRfiCYEXAMPLEKEY";  | 
					
適当にそれっぽいのを書いて、これでコミット。
| 
					 1 2 3 4 5 6 7 8 9 10 11 12  | 
						$ git add test.php $ git commit -m "first commit" test.php:2:$AWSAccessKeyId = "AKIAIOSFODNN1EXAMPLE"; test.php:3:$AWSSecretKey = "wJalrXUtnFEMI/K1MDENG/bPxRfiCYEXAMPLEKEY"; [ERROR] Matched one or more prohibited patterns Possible mitigations: - Mark false positives as allowed using: git config --add secrets.allowed ... - List your configured patterns: git config --get-all secrets.patterns - List your configured allowed patterns: git config --get-all secrets.allowed - Use --no-verify if this is a one-time false positive  | 
					
弾いてくれました!
まとめ
実際の運用では、認証情報やパスワードなど本当に外部に漏れてマズいものは、環境変数にセットするのが個人的にはオススメです。そもそもファイルに書かない運用であれば、ファイルの取扱い不備でリークする可能性がゼロになり、セキュリティリスクを減らせます。
とはいえ、実情そんなこと言ってられないケースも多いですので、ファイル+.gitignoreで気をつけて運用するのが一般的でしょうか…。万が一のためにAWS内外問わず、トークンごとに権限設定ができるものは必要最小限の付与に留めるようにしましょう。AWSの場合、ルートキーでないと使えないAPIがあったりもするみたいですが……。
今回のgit secretsは他にも、既にインデックスされているファイルの中にキーが混ざっていないかどうかをスキャンしたりすることもできます。詳しく知りたい方は公式のドキュメントをどうぞ。
所感
AWSなんかは凄い勢いで請求額が増えていくサービスが山ほどあります。ルートキーなんかが漏洩したと思うとゾッとしますね……。従量課金制のクラウドサービスを使う際には、そのセキュリティにはより一層の注意を払って取り扱いたいですね。


