DependabotとpinactでGitHub Actionsのサプライチェーン攻撃対策
はじめに
Hacobuでは、開発ワークフローの効率化と迅速なデリバリーを実現するために、CI/CDツールとしてGitHub Actionsを積極的に活用しています。GitHub Actionsは非常に強力なツールですが、その利用においては、依存する外部action(third-party action)のセキュリティリスク、いわゆる「サプライチェーン攻撃」への対策が重要となります。
HacobuでのGitHub Actions運用において、当初以下の2点に課題を感じていました。
- 利用しているactionのバージョン指定がタグ(例:
@v4
)のみであり、特定のcommit hashで指定していないこと。 - GitHub Actionsで利用しているthird-party actionを、セキュリティリスク低減や機能改善のために定期的にアップデートできる仕組みがないこと。
これらの課題に対し、解決策としてDependabotとpinactの導入を進めました。本記事では、その導入の背景、具体的な手法、そして導入効果についてご紹介します。
なぜcommit hash指定が推奨されるのか
GitHub Actionsで外部Actionを利用する際、バージョン指定の方法としてタグ(例: actions/checkout@v4
)が一般的に使われます。しかし、セキュリティと再現性の観点から、特定のcommit hash(例: actions/checkout@8f4b9b2
)での指定が強く推奨されています。その理由を改めて整理します。
-
意図しないActionの更新を防止
バージョンタグ(例:@v4
)は、そのタグが指すcommitを後から変更(上書き)することが技術的に可能です。また、マイナーバージョンやパッチバージョンの更新がタグに対して行われた場合、意図せず新しい、変更されたコードが使用されてしまいます。特定のcommit hashであれば、そのhashが示すコードは不変であり、実行されるコードが確実に保証されます。 -
リポジトリ乗っ取りなどへの対策
万が一、利用しているactionのリポジトリが攻撃者に乗っ取られたり、削除後に悪意のあるコードで作り直されたりしても、既存のworkflowで指定されているcommit hashのコードは改変されるリスクがありません。これにより、不正なコードの実行を防ぐことが可能です。 -
ビルドの再現性向上
どの時点のどのコードが実行されたかを正確に特定できるため、過去に実行されたworkflowを高い精度で再現できます。特定のactionが意図した通りに動作しない場合でも、同じcommit hashを指定していれば、以前の環境をそのまま再現し、問題の切り分けやデバッグが容易になります。
GitHub Actionsを取り巻くサプライチェーン攻撃とそのリスク
近年、GitHub Actionsを悪用したサプライチェーン攻撃が増加傾向にあり、そのリスクに対する認識が高まっています。
特に、2025年3月に発生した tj-actions/changed-files
のサプライチェーン攻撃は、広く注目を集めました。このactionはPRやcommitで変更されたファイルを特定するため、多くのリポジトリで利用されており、その影響範囲は23,000を超えるリポジトリに及んだと報告されています。幸いにも、攻撃の影響でSecret情報などが実際に漏洩したケースは限定的(218件)だったようですが、その潜在的なリスクの大きさが浮き彫りとなりました。
Hacobuでは幸い tj-actions/changed-files
を直接使用していませんでしたが、この攻撃手法は悪意のあるcommitによって全タグが上書きされるというものであり、タグ指定でactionを利用している限り、同様の攻撃を受ける可能性があったことを再認識させられました。commit hashで指定していれば、この特定の攻撃手法は回避可能でした。
commit hash指定への移行を自動化する:pinact
既存のGitHub Actions workflowにおいて、手動で一つ一つのactionのバージョンをcommit hashに置き換える作業は非常に手間がかかります。そこで活用したのが、suzuki-shunsuke/pinact
というツールです。
pinactは、すでにワークフローファイルに記述されているGitHub Actionsの指定バージョン(タグやブランチ)から、対応する最新のコミットハッシュを取得し、コメントとして元のタグ情報を残しつつ、自動でコミットハッシュ指定の形式に変換してくれるツールです。
使い方は非常にシンプルで、対象のリポジトリで以下のコマンドを実行するだけです。
pinact run
このコマンドを実行すると、workflowファイルをスキャンし、必要な変更を加えてくれます。変更内容はPull Requestとして提示されるため、レビューが可能です。
実際のPR差分
actionの定期的なアップデート:Dependabotの活用
pinactによってActionのバージョン指定をコミットハッシュに固定することで、ワークフローの実行コードは不変となりセキュリティが向上します。しかし、これだけではAction側にセキュリティフィックスや機能改善が行われても、ワークフローには自動的に反映されません。そこで、コミットハッシュで固定したactionを最新の状態に保つために、Dependabotを利用します。
Dependabotは、プロジェクトの依存関係に更新があった場合に自動でPull Requestを作成してくれるGitHub標準機能です。GitHub Actionsについても、特別な設定ファイルをリポジトリに配置することで、利用しているactionの新しいバージョンがリリースされた際に通知を受け取り、commit hashを更新するPull Requestを作成させることができます。
設定ファイル(通常 .github/dependabot.yml
)は以下のように記述します。
version: 2
updates:
- package-ecosystem: 'github-actions'
directory: '/'
schedule:
interval: 'weekly'
この設定により、利用しているthird-party action側で新しいバージョン(タグ)がリリースされると、Dependabotが検知し、該当する最新のコミットハッシュに更新するPull Requestを自動で作成してくれます。
DependabotによるPR
作成されるPRには、新しいactionのバージョン情報はもちろん、リリースノートや関連commitへのリンクも記載されており、レビューに必要な情報が揃っています。これにより、セキュリティリスクのチェックや変更内容の確認が効率的に行えます。
この運用を開始して約2ヶ月が経過しましたが、利用するthird-party actionのセキュリティや安全性の向上、およびメンテナンス効率の向上を実感しています。更新が自動で提案されるため、個々のthird-party actionの更新状況を常に気にかける必要がなくなり、導入効果を感じています。
最後に
本記事では、GitHub Actionsにおけるサプライチェーン攻撃への対策として、commit hash指定の重要性、そしてその実現・維持のために導入したpinactとDependabotの活用方法についてご紹介しました。
Dependabotとpinactを活用することで、GitHub Actionsのサプライチェーン攻撃リスクを低減し、より安全かつ効率的なCI/CD環境を構築できます。pinactによる既存workflowのcommit hash化も、Dependabotによる定期的なアップデート提案も、導入は比較的容易です。
まだcommit hash指定でのaction運用や、actionの自動更新の仕組みを導入していない場合は、ぜひ本記事を参考に導入を検討してみてください。
参考
Discussion