こちらは ABEJA アドベントカレンダー 12日目の記事です。
こんにちは。CTO室の村主です。セキュリティ強化も自組織の役割であるため、ABEJAのセキュリティ対策に関する内容を共有したいと思います。
- はじめに
- trufflehog(トリュフホッグ)
- クレデンシャルの埋め込みに対する取り組み
- trufflehog の使い方
- 全リポジトリのスキャン
- pre-commit の設定
- 最後に、GitHub Actions で1日1回更新のあったリポジトリだけリスト化して trufflehog でスキャン
- まとめ
- 採用メッセージ
はじめに
みなさんGitHubのセキュリティ高めてますか?GitHub Organizationのセキュリティベストプラクティス等は Flatt Security さんがすごく良いまとめを公開されているので、それに沿って対応されるのが良いと思います。
今回は、コード内にクレデンシャルを埋め込まないようにするためと、仮に埋め込まれてpushされたとしてもなんとか検知できるようなセキュリティ対策を紹介したいと思います。
特に弊社は1,000以上のリポジトリが存在しており、リポジトリごとにセキュリティチェックの設定を入れるのは骨が折れるので、包括的に設定できないか試行錯誤した結果も紹介します。
trufflehog(トリュフホッグ)
みなさん trufflehog って知ってますか?すごい便利なツールだったので紹介したいと思います。
Truffle Security社が開発しているオープンソースで、gitsecret 等と同様のクレデンシャルを検知するツールです。trufflehog は他と違って優れている部分は「credential detector」です。
For every potential credential that is detected, we've painstakingly implemented programatic verification against the API that we think it belongs to. Verification eliminates false positives. For example, the AWS credential detector performs a
GetCallerIdentity
API call against the AWS API to verify if an AWS credential is active.
コードにクレデンシャルが埋め込まれていることを検知するだけではなく、そのクレデンシャルが現在有効かどうか もチェックしてくれます。AWSの例だと GetCallerIdentity
のAPIをコールして有効性をチェックしています。
つまり、現状でリスクが高いコード(クレデンシャル)だけを洗い出して効率的に対処することができます。 すごく筋が良いツールですね。
さらに、AWSだけではなく約700のcredential detectorsが実装されているようです。(2022/12現在)
弊社で利用しているSendgirdやAuth0、Datadogなども含まれていてすごく有難いです。
クレデンシャルの埋め込みに対する取り組み
この trufflehog を使って、クレデンシャルの埋め込みの対策を実施しました。
1. まず現在のリポジトリがクリーンな状態を担保するために、全リポジトリをスキャンしました(1,000以上…)
これで全リポジトリは問題ないことを担保できました。スキャン方法は至って単純で「全リポジトリリストを取得、リストしたリポジトリをスキャン」です。
実施方法は後述します。
2. 次に新しいコミットに対してクレデンシャルが埋め込まれないように全エンジニアに pre-commit に trufflehog を設定してもらいました
これで新しいコミットにもクレデンシャルが埋め込まれなくなりました。しかし、新しく入社した人が設定し忘れたりPC交換時に設定し忘れたりといったリスクは残っています。 設定が漏れた場合はリポジトリにクレデンシャルが埋め込まれてしまうので、リポジトリ側で検知できる仕組みが欲しいと思いました。
また、個々のリポジトリで「push時にGitHub Actionsが起動してtrufflehogでスキャンする」と言ったことは容易ですが、1,000個もGitHub Actionsを設定しまわるのは骨が折れるのと、リポジトリ作成時にスキャン設定が漏れると(以下略
3. そこで、GitHub Actions を利用して、1日1回、更新のあったリポジトリだけリスト化して、trufflehogでスキャンする仕組みを構築しました
これらの実装により以下が実現できました。やったね
それでは trufflehog の使い方や上記の実装方法を解説していきます。
trufflehog の使い方
インストールはこれだけです。
brew tap trufflesecurity/trufflehog brew install trufflehog trufflehog git https://github.com/abeja-inc/abeja-cli.git
実行方法は以下です。 --only-verified
を付与するとクレデンシャルが有効な場合に検知し、付与しない場合はクレデンシャルが埋め込まれているだけで検知するようになります。
$ gitleaks-playground % trufflehog git file://. --only-verified 🐷🔑🐷 TruffleHog. Unearth your secrets. 🐷🔑🐷 Found verified result 🐷🔑 Detector Type: AWS Raw result: AKIAXXXXXXXXXXXXXXXXX Repository: https://github.com/abeja-inc/xxxx-xxxx.git Timestamp: 2022-08-23 17:12:35.030695 +0900 JST m=+0.086615668 Commit: unstaged File: test.py Email: unstaged
ちなみにクレデンシャルを1文字変更したら有効性を確認できなくなり検知しなくなりました。
$ vim test.py $ trufflehog git file://. --only-verified 🐷🔑🐷 TruffleHog. Unearth your secrets. 🐷🔑🐷
正しくは unverified で引っ掛かってるようで、 —only-verified にしてるから表示されていないだけです。
$ trufflehog git file://. 🐷🔑🐷 TruffleHog. Unearth your secrets. 🐷🔑🐷 Found unverified result 🐷🔑❓ Detector Type: AWS Raw result: AKIAXXXXXXXXXXXXXXXXX Timestamp: 2022-08-23 17:16:45.979598 +0900 JST m=+0.087489918 Commit: unstaged File: test.py Email: unstaged Repository: https://github.com/abeja-inc/xxxx-xxxx.git
全リポジトリのスキャン
全リポジトリのスキャンは以下な感じで適当に実行できると思います。大したことないのでサンプル程度にご確認ください。
なお、git file://.
みたいにファイルシステムを指定しなくても、GitHub上のコードを直接スキャンすることもできます。
#!/bin/bash GITHUB_ORG="xxx" i=1 REPO_LIST=$(gh repo list ${GITHUB_ORG} -L 2000 | awk '{print $1}') REPO_COUNT=$(echo ${REPO_LIST} | grep -c "") echo ${REPO_LIST} for x in $(echo ${REPO_LIST}) do REPO="$x" REPODIR=$(echo ${REPO}|cut -d"/" -f2) echo "## Start (${i}/${REPO_COUNT}) ==>> $REPODIR" trufflehog git https://github.com/${REPO} --only-verified --json >> ${REPODIR}.json i=$(($i + 1)) done
pre-commit の設定
まずは社内のプライベートリポジトリを作成し、pre-commit の共通設定ファイル hooks/pre-commit
を配置します。
#!/bin/bash # Prioritize local pre-commit. GIT_ROOT=$(git rev-parse --show-toplevel) LOCAL_HOOK="${GIT_ROOT}/.git/hooks/pre-commit" if [ -e $LOCAL_HOOK ]; then source $LOCAL_HOOK fi # The following is a pre-commit for additional global settings. ## Check for valid credentials by TruffleHog trufflehog git --only-verified --fail file://.
次に各端末に trufflehog をインストールしてもらいます。
# pre-commit Install → https://pre-commit.com/ brew install pre-commit # TruffleHog Install. # Click here for non-Mac users -> https://github.com/trufflesecurity/trufflehog brew tap trufflesecurity/trufflehog brew install trufflehog
そして、先ほど作成したプライベートリポジトリをcloneし、pre-commitの設定をしてもらいます。
mkdir -p ~/.config/ cd ~/.config/ git clone https://github.com/aaaaa/bbbb.git git config --global core.hooksPath "~/.config/bbbb/hooks"
最後に、pre-commit の共通設定ファイルに更新があった場合に同期されるように以下を実行してもらいます。以上です。
# Sync ## bash echo 'bash -c "cd ~/.config/agsg/hooks && git pull 1>/dev/null"' >> ~/.bashrc ## zsh echo 'bash -c "cd ~/.config/agsg/hooks && git pull 1>/dev/null"' >> ~/.zshrc
なお、この方法では Husky などを利用中のお場合は core.hooksPath が干渉するのでご注意ください。
最後に、GitHub Actions で1日1回更新のあったリポジトリだけリスト化して trufflehog でスキャン
先ほど作成したプライベートリポジトリ内でも良いのですが、.github/workflows/security_check.yml
というファイルを作成します。
name: TruffleHog periodic check on: schedule: - cron: '0 1 * * *' jobs: get_checkrepolist: runs-on: ubuntu-latest outputs: matrix: ${{ steps.matrix.outputs.value }} steps: - uses: actions/checkout@v3 - name: Get list of repositories pushed 1 day ago id: matrix run: | YESTERDAY=$(date --date '1 day ago' "+%Y-%m-%d") LIST=$(gh repo list ${{ env.GH_ORG }} -L 100 --json name,pushedAt | jq --arg yesterday $YESTERDAY '.[] | select(.pushedAt >= $yesterday)' | jq .name -c | grep -v -f .ignore | jq -s) echo "::set-output name=value::$(echo $LIST)" env: GH_TOKEN: ${{ secrets.PAT }} GH_ORG: "XXXX" check_trufflehog: needs: get_checkrepolist runs-on: ubuntu-latest strategy: fail-fast: false matrix: value: ${{ fromJson(needs.get_checkrepolist.outputs.matrix) }} steps: - uses: actions/checkout@v2 - name: TruffleHog Install run: | mv files/trufflehog /usr/local/bin trufflehog --version - name: Exec TruffleHog run: | trufflehog git https://${{ env.GH_USER }}:${{ env.GH_TOKEN }}@github.com/${{ env.GH_ORG }}/${{ matrix.value }} --only-verified --fail env: GH_TOKEN: ${{ secrets.PAT }} GH_USER: "XXXX" GH_ORG: "XXXX" - name: Create Issue if: failure() uses: imjohnbo/issue-bot@ebb016264b7ca514eea6315872b0d768868fd8c1 with: title: "[TruffleHog] ${{ matrix.value }} is Failure" labels: "trufflehog" body: | [${{ matrix.value }}](https://github.com/${{ env.GH_ORG }}/${{ matrix.value }}) is Failure. See [the action log](https://github.com/${{ env.GH_ORG }}/${{ matrix.value }}/actions/runs/${{ github.run_id }}) for more details. Assign a team administrator for the repository to be the resolver of this issue. env: GH_ORG: "XXXX"
補足としては、
- env に設定している環境変数(GH_ORGやGH_USER)は適時設定ください。
- env に設定している secrets.PAT は Actions secrets に PAT という名前で、全リポジトリを参照できるGitHubのパーソナルアクセストークンを設定ください。これがキモで、GitHub Actionsでデフォルトで設定されているGitHubのTokenは自リポジトリのみの参照権限のため、全リポジトリを参照できるパーソナルアクセストークンが必要になります。
- .ignore というファイルを作成すれば、除外するリポジトリを指定できるようになっています。
- 最後に、filesというディレクトリにtrufflehogのバイナリファイルを配置してください。trufflehog と imjohnbo/issue-bot は外部のツールになるため、脆弱な変更が加わらないようにバイナリやバージョンを固定化するようにしています。
以上です。
まとめ
- 1,000を超える全リポジトリでクレデンシャルの埋め込みをチェックしたい。trufflehog を使って現在も利用可能なクレデンシャルのみ検知するようにした。
- pre-commit を設定して、クレデンシャルを埋め込む前に検知できるようにした。(お作法)
- 仮に pre-commit の設定が漏れたとしても受け取り側のリポジトリで検知できるようにした。
採用メッセージ
ABEJAではエンジニア採用を積極的に行っております!ご興味があればご確認くださいませ。 careers.abejainc.com