GitHub Actions のシークレットは push できるユーザーであれば誰でも見れる
Posted on
GitHub Actions には暗号化されたシークレットを保存できます。この値は一度設定すると、ブラウザや GitHub CLI から確認することはできません。
公式ドキュメントの "Encrypted secrets" のページを読むと、シークレットの値は Sodium を使ってクライアント側で暗号化され、ワークフローで使用されるまで暗号化されていることが保証されています。なので、ブラウザや GitHub CLI から確認できないのだと思います。
GitHub uses a libsodium sealed box to help ensure that secrets are encrypted before they reach GitHub and remain encrypted until you use them in a workflow.
ワークフローの中でシークレットを echo
してもマスクされて表示されます。ですが、シークレットの文字列を少し細工するだけで簡単にハックできてしまいます。検索するといろいろな方法が見つかりますが、たとえば sed
でスペースを挟むだけでも表示されます。
name: Leak the secret
on: push
jobs:
leak:
runs-on: ubuntu-latest
steps:
- name: Leak the secret
run: echo ${{ secrets.DUMMY_SECRET }} | sed 's/./& /g'
# DUMMY_SECRET が "123456" だと "1 2 3 4 5 6 " のように表示される
シークレットを設定するにはリポジトリの Admin ロールが必要ですが、Write ロール以上のユーザーであれば適当なワークフローを push してシークレットの値を抜き出せてしまいます。これは未検証ですが、Write ロールであれば GitHub Actions の履歴も消せそうなので証跡も残りません。
これを踏まえると GitHub Actions のシークレットは次のように捉えておいたほうが良さそうです。
- シークレットの値は GitHub に安全に保存されているが、リポジトリに push できる人なら誰でもシークレットを見れる
- 永続的な API キー (e.g. AWS credential) などを保存している場合、退職者が出たらシークレットのローテーションが必須である
- クラウドプロバイダーが OpenID Connect に対応している場合は積極的に使う
- 全リポジトリで共通して使うシークレットは Organization レベルで設定してローテーションしやすくする
プロダクトのセキュリティを担保するためにも、こういうリスクがあることをちゃんと理解しておきたいですね。