アクセスキーのコミットを抑止できて安全便利な awslabs/git-secrets

GitHub で awslabs のリポジトリを眺めてたら git-secrets という便利なツール(シェルで実装されてる)を発見した.

どんなものかを簡単に説明すると,アクセスキーなどを誤ってコミットすることを Git の hooks を使って未然に防ぐツールで,誤って GitHub に push してしまったために,AWS を不正利用されてしまった,みたいな事故もたまに聞くし,そういうのを防ぐことができる.非常に良かったので,一部のリポジトリに git-secrets を設定した.

github.com

インストール

make install でも良いけど,Mac なら brew が使える.

$ brew install git-secrets

インストールすると git secrets コマンドが使えるようになった.

$ git secrets
usage: git secrets --scan [-r|--recursive] [--cached] [--no-index] [--untracked] [<files>...]
   or: git secrets --scan-history
   or: git secrets --install [-f|--force] [<target-directory>]
   or: git secrets --list [--global]
   or: git secrets --add [-a|--allowed] [-l|--literal] [--global] <pattern>
   or: git secrets --add-provider [--global] <command> [arguments...]
   or: git secrets --register-aws [--global]
   or: git secrets --aws-provider [<credentials-file>]

    --scan                Scans <files> for prohibited patterns
    --scan-history        Scans repo for prohibited patterns
    --install             Installs git hooks for Git repository or Git template directory
    --list                Lists secret patterns
    --add                 Adds a prohibited or allowed pattern, ensuring to de-dupe with existing patterns
    --add-provider        Adds a secret provider that when called outputs secret patterns on new lines
    --aws-provider        Secret provider that outputs credentials found in an ini file
    --register-aws        Adds common AWS patterns to the git config and scans for ~/.aws/credentials
    -r, --recursive       --scan scans directories recursively
    --cached              --scan scans searches blobs registered in the index file
    --no-index            --scan searches files in the current directory that is not managed by Git
    --untracked           In addition to searching in the tracked files in the working tree, --scan also in untracked files
    -f, --force           --install overwrites hooks if the hook already exists
    -l, --literal         --add and --add-allowed patterns are escaped so that they are literal
    -a, --allowed         --add adds an allowed pattern instead of a prohibited pattern
    --global              Uses the --global git config

ちなみに,コマンド自体は /usr/local/bin/git-secrets にある.

$ which git-secrets
/usr/local/bin/git-secrets

セットアップ

git-secrets のセットアップはリポジトリ単位に行う.適当なリポジトリのルートディレクトリに移動して git secrets --install を実行すると,3種類の hooks が登録される.

$ 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

ただし,既に hooks を使っている場合,エラーになる.この場合は --force オプションを付けて強制的に上書きする必要がある.

$ git secrets --install
.git/hooks/commit-msg already exists. Use -f to force

残念ながらマージする機能はないため,一度 hooks を退避した後に上書きして,戻す必要がありそう.

$ git secrets --install --force
✓ 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

AWS アクセスキーのコミットを防ぐ場合

AWS 関連のリポジトリの場合は,デフォルトで用意されている git secrets --register-aws を使う.そうすると,アクセスキー/アカウントを対象にコミットを防ぐことができる.

$ git secrets --register-aws

--list オプションで,正規表現などの設定値を確認することができる.secrets.allowed に入ってる値は example AWS keys と README.md に書いてあった.

$ 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

--list オプションは git config を参照しているので,直接 git config を叩いても,同じ情報が確認できる.同じく secrets.allowed に入ってる値は example AWS keys だから問題なし.

$ git config -l | grep secrets
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

実際にアクセスキーをコミットしてみる

正規表現に合致する ABCDEFGHIJKLMN123456 というアクセスキー(サンプル)を README.md に書いてコミットしようとすると,以下のエラーが出てコミットできないようになった.

$ git commit -m'Added access key'
README.md:50:ABCDEFGHIJKLMN123456

[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

今回は AWS の例を試したが,--add オプションを使えば,任意の正規表現も登録できるため,他の SaaS などを使ってる場合などにも簡単に対応できる.

スキャン機能

--scan オプションを使うと,リポジトリを対象に既にコミットされていないかをスキャンすることができる.

$ git secrets --scan

さらにこのオプションでは git secrets --aws-provider で取得した ~/.aws/credentials の値を対象にチェックもしてくれるため,気が利いている.

まとめ

git-secrets は,地味な感じもあるけど,非常に便利なツールだった.AWS としても,誤ってコミットされてしまって事故が起きてしまうことは望んでないだろうし,もっと普及すると良さそう.git-secrets をまだ使ってない人はすぐ使いましょう!