GitHub Actionsセキュリティ強化:Enforce SHA pinning導入とpinact + 必須ワークフローアプローチで見つかった問題

こんにちは!人事・技術・経営推進本部の技術戦略ディビジョンでインフラエンジニアをしている片岡です。

GitHub Actionsのセキュリティ強化施策として、コミットSHA指定強制のためにEnforce SHA pinning機能がリリースされました。

github.blog

Adwaysは現在Enforce SHA pinningを導入する方針に転換しています。

この記事では、導入に至った背景と、以前検討していた「pinact + 必須ワークフロー」アプローチで判明した運用上の課題をまとめます。
pinactアプローチには利点もありますが、実運用で問題となる点がいくつか見つかったため、それらを共有します。

ブログの要点

先に、このブログの要点をまとめると以下の通りです。

Enforce SHA pinningの採用

2025年8月15日にリリースされたGitHub公式機能により、組織(またはリポジトリ)レベルでGitHub ActionsのSHA指定を強制することが可能となりました。
Adwaysでは組織として設定適用する方針としています。

pinact + 必須ワークフローアプローチの限界

pinact + 必須ワークフロー(後に詳細を説明します)による管理では運用面での課題がいくつかあり、現時点では現実的でないことが分かりました。

ただし、Enforce SHA pinningと違って特定のアクションをコミットSHA指定強制から除外できるというメリットもあります。
どうしても全アクションのコミットSHA指定が厳しい場合は採用の余地があるかもしれません。

Enforce SHA pinningの導入に至る背景

そもそも、なぜコミットSHA指定が必要なのか

GitHub Actionsはセキュリティ対策として公式Docsよりアクションを使う際はコミットSHAに固定することが推奨されています。

-      uses: actions/checkout@v4
+      uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2

この推奨の理由は、サプライチェーンセキュリティの観点から次のようなリスクがあるためです。

  • タグの改ざんリスク: タグは削除・再作成が可能で、悪意のあるコードに差し替えられる可能性がある
  • ブランチの書き換えリスク: ブランチ指定では、参照先のコミットが予期せず変更される場合がある
  • 依存関係の脆弱性: アクションが内部で利用する依存関係が変更される可能性がある

Adwaysでの管理方式の変遷

Adwaysでは、以下のように管理方式を変更してきました。

ホワイトリストによる管理方式(〜2025年8月)

Adwaysでは、8月に入るまでは、GitHub Actionsのホワイトリストによる管理方法を採用していました。

この管理方法の詳細は過去のエンジニアブログに記載していますが、概要は以下の通りです。

blog.engineer.adways.net

  • Organization設定での制御: GitHub ActionsをコミットSHA指定単位で使用許可。
  • ホワイトリスト管理: 使用許可されているActionsを管理用リポジトリのYAMLファイルで管理。
  • 公式アクションなどを例外: GitHub公式のアクションやMarketplaceのVerified Creatorのアクションはタグ指定でも利用可能。
  • 申請ベースの運用: 新しいアクションの利用には事前申請が必要。

ホワイトリスト方式の問題点

ホワイトリスト管理には、以下の問題がありました。

開発効率の低下

  • dependabotなどのアクションを自動的にバージョンアップする仕組みとの相性が悪い。
  • 開発者はアクションがバージョンアップされるたびにホワイトリストへの追加PRを作成する必要がある。
  • 特にバージョン更新頻度が高いGitHub Actionsを使用する場合は開発者・管理側双方の負担が増える。

運用上の制約

  • GitHubの仕様上、ホワイトリストへの登録は1,000件という制限がある。
    • アクションの更新が頻繁な環境では、将来的にこの制限に達する可能性がある。

結果として、ホワイトリストでの管理方式の廃止が決定され、別のアプローチを検討することになりました。

検討された代替アプローチ

ホワイトリスト方式の問題を受け、以下のアプローチが検討されました。

1. pinact + 必須ワークフローによるアプローチ

  • pinact(コミットSHA指定でないアクションを検知・修正するCLI)を必須ワークフローで実行。
  • マージ前にコミットSHA指定を強制し、事前検知によりブロック。

2. 定期監査アプローチ

  • 定期的に全リポジトリのワークフローファイルを監査。
    • 全リポジトリにpinactなどのツールを使用してmainブランチのワークフローファイル内のコミットSHA指定でないアクションの存在を確かめる。
    • CIの定期実行などで行う。
  • コミットSHA指定でないアクションを検知した場合、リポジトリ所有者にSlack通知。

最終的に事前検知の利点や特定アクションを検知から除外する設定ができる点を評価し、「1. pinact + 必須ワークフローアプローチ」が採用されました。

「2. 定期監査アプローチ」は以下の点が懸念されたため不採用となりました。

  • デフォルトブランチにマージした後に検知されてしまった場合に修正で手戻りが発生する
  • Slackの通知は強制力が弱い

pinact + 必須ワークフローアプローチの実装内容

pinact + 必須ワークフローアプローチでは、以下のような仕組みを構築しました。

pinactとは

pinactは、GitHub Actionsのワークフローファイルにおいて、コミットSHA指定でないアクションを検知・修正してくれる便利なCLIツールです。

主な機能は以下の通りです。

検知機能: タグやブランチ指定のアクションを自動検知。

修正機能: タグ指定を対応するコミットSHAに自動変換。

バリデーション機能: ワークフローファイルの妥当性をチェック。

必須ワークフローとの組み合わせ

必須ワークフローとは、デフォルトブランチへのマージ前に指定のワークフローの実行を必須とするGitHubのリポジトリルールセットの機能です。

この機能とpinactを組み合わせることで、以下のようにコミットSHA指定を強制する仕組みを実現しようとしました。

  • PRマージ前にpinactが自動実行される。
  • コミットSHA指定でないアクションが検知された場合、マージがブロックされる。
  • 開発者はSHA指定に修正してからマージする必要がある。

pinact + 必須ワークフローのアプローチで発生したトラブルや問題点について

実際に運用を開始すると、理論上は良いアプローチに見えたものの、実用性において多くの課題が浮き彫りになりました。

1. 設定適用時の既存PRに対する影響

発生した問題 : 必須ワークフローの設定適用前に作成されたPRでは、必須ワークフローがトリガーされない。

必須ワークフローはデフォルトのトリガーイベントのみ実行されます。(参考:公式ドキュメント)
このケースではPRのopenやreopenに該当せず、ブランチのHEADが更新もされていないのでトリガーされない状態になりました。

以下はデフォルトのトリガーイベント(公式ドキュメントより)です。

イベント デフォルトのアクティビティタイプ
pull_request opened, synchronize, reopened
pull_request_target opened, synchronize, reopened
merge_group checks_requested

リポジトリによっては数十〜数百のPRが同時に開かれており、これらすべてでマージがブロックされる状態になることが分かりました。

対処方法

PRのreopen(一度クローズして再度オープン)により必須ワークフローを再実行できました。
しかし、PR数が多いリポジトリでは開発者・レビューワー双方に大きな負担が発生しました。

2. ブランチ構造に起因する問題

問題の概要

デフォルトブランチから2重でブランチを作成した場合(孫ブランチ)において

子ブランチがマージされた後に孫ブランチの必須ワークフローが自動実行されない問題が発生しました。

具体的なシナリオ

main
├── feature/parent-branch (子ブランチ)
│   └── feature/child-branch (孫ブランチ)
  1. feature/parent-branchmainにマージ。
  2. feature/parent-branchが削除される。
  3. feature/child-branchのターゲットが自動的にmainに変更される。
  4. この時点で必須ワークフローが自動実行されない。
  5. 開発者が手動でPRをreopenする必要が発生。

上記の問題について、GitHub Supportに問い合わせしました。

前節と同様に、必須ワークフローのトリガーは open / reopen / synchronize に限られており、仕様上解決できませんでした。

今回のケースだと、feature/child-branchのHEADが更新されていないので

synchronizeトリガーが反応せず、PRのベースブランチの変更をトリガータイプとするeditedが必要でした。
参考 : https://frontside.com/blog/2020-05-26-github-actions-pull_request/

今後、トリガーの追加がいつ実装されるのかも明言できないそうです。

3. pinactの仕様理解における課題

ブランチ名指定アクションの制限

pinactはブランチ名で指定されたアクションをコミットSHAに自動変換できませんでした。

参考:Q. Why doesn't pinact pin some actions? - pinact

pinact doesn't change versions which aren't semver. For instance, pinact doesn't change the version main.

# 変換できない例
- uses: owner/repo@main  # ブランチ指定
- uses: owner/repo@develop  # ブランチ指定

# 手動修正が必要
- uses: owner/repo@abc123...  # コミットSHA指定

この制限により、開発者はブランチ指定のアクションを手動でタグまたはコミットSHAに修正する必要がありました。

Enterprise内の再利用ワークフローが検知される

pinactはEnterprise・Organization内のアクションも検知対象としてしまい、除外設定が必要でした。

# .pinact.ymlで除外するアクションを設定
ignore_actions:
  - name: adways-adtech/.*
    ref: "^.*$"
  - name: adways-martech/.*
    ref: "^.*$"
  - name: adways-migration/.*
    ref: "^.*$"

依存アクションへの検知

pinactは検知対象が内部で別のアクションを呼び出している場合に検知ができない仕様となっています。

pinact + 必須ワークフローのアプローチの利点

後に紹介するEnforce SHA pinningと違って、pinactはコミットSHA指定の検知から除外するアクションを設定できます。
なので、組織として特定のアクションを除外したい場合、このアプローチが有効です。

Enforce SHA pinningのリリースによる既存問題の解決

2025年8月15日、GitHubからEnforce SHA pinning機能がリリースされました。主な仕様は以下の通りです。

Enforce SHA pinningの仕様

この設定は主に以下の仕様となります。

全アクション対象: 公式アクションや再利用ワークフロー含む全アクションにコミットSHA指定を強制。

実行時検証: コミットSHA指定されていないアクションを利用した場合、ワークフローのSet up jobステップで失敗。

依存関係チェック: アクションが内部で呼び出す別のアクション(依存アクション)がSHA指定でない場合も同様に失敗。

pinact + 必須ワークフローのアプローチの問題解決へ

ここまで記述したpinact + 必須ワークフローのアプローチの問題点をまとめると以下のようになり

  • 特定の条件において必須ワークフローが動かなくなり、PRのreopenをしないとマージがブロックされ開発の阻害となる。
  • mainブランチのみでコミットSHA指定が強制され、他のブランチにおいてはコミットSHA指定以外でアクションが使えてしまう。

Enforce SHA pinningは以下の点からpinact + 必須ワークフローのアプローチが抱える問題の解決策となりました。

  • すべてのブランチで実行されるワークフローのアクションのコミットSHA指定が強制される。
  • 必須ワークフローをそもそも使わない。

今後とまとめ

Enforce SHA pinning設定適用への移行

pinact + 必須ワークフローで発生した問題が解消できることや

Enforce SHA pinningによって全アクションのSHA指定が強制されることから

AdwaysではEnforce SHA pinningを利用する方針となっています。

まとめ

Adwaysでは、GitHub Actionsのセキュリティ強化を目的として、まずホワイトリストによる管理方式から始まりました。
ホワイトリスト管理は、組織として利用を許可するアクションを厳密に制御できます。
一方で、以下のように開発効率や運用負荷の面で多くの課題がありました。

  • 申請やPR作成の手間
  • 許可Actions登録数の上限
  • 頻繁なバージョン更新への対応など

これらの課題を解決するため、pinact + 必須ワークフローによる事前検知・強制の仕組みを構築しました。
しかし、既存PRへの影響やブランチ構造によるワークフロー未実行、pinactの仕様制約など運用上のトラブルも発生しました。
特に必須ワークフローのトリガー仕様は、PRの状態によってはマージがブロックされるなど、事前の調査や運用設計が重要だと痛感しました。

結果的に、GitHub公式のEnforce SHA pinningを適用することになりました。
適用することで以下の仕様から、さらに高いセキュリティと運用負荷の軽減が可能となります。

  • 全アクションに対してコミットSHA指定を強制
  • 依存関係も含めて実行時に検証される

本記事が、同様の課題に直面している組織やエンジニアの参考になれば幸いです。