ssrf.dev

個人的にGitHub Actionsまわりで気をつけていること

目次
  1. ghalint / actionlintに頼る
  2. 3rd party actionをできるだけ使わない
  3. SecretsにKeyを置かない
  4. やろうと思っているけど徹底できていないこと
  5. Require actions to be pinned to a full-length commit SHAの有効化
  6. branch ruleset / push ruleset
  7. ghalint / actionlintを全リポジトリで回す
  8. さいごに

2026年も引き続きGitHub Actionsまわりのセキュリティ(と、それに起因するサプライチェーン攻撃界隈)は盛り上がっていて、気が抜けない。仕事とは別にして、趣味の開発で気をつけていることをさらっと共有してもいいかもな、と思い立ちこの記事を書いている。

正直この手の話題は出尽くしている感もあるし、別に何か目新しいTipsがあるわけではないのだが、仕事は別として個人としてもこの程度はやってもいいかもねーくらいの話として読んでくれれば幸いである。

ghalint / actionlintに頼る

散々出尽くしているので今更感があるが、とりあえずlinterを回すというのはかなりオススメで、何も考えずに回してエラーを消していくだけで90点くらいは取れるんじゃないかと思っている。個人的にはsuzuki-shunsuke/ghalintrhysd/actionlintを使っていて、リポジトリによってはGitHub ActionsでPRに対して回していたりもする。

最近は自分ではほぼコードを書かないので、Claude Codeのスキルを作って、GitHub ActionsのワークフローファイルやComposite actionを作成・編集した直後に自動でセキュリティチェックを実行し問題を修正するスキル。 のようなdescriptionを書いて置いてある。disable-model-invocation: trueにしなければClaude CodeがGitHub Actionsのワークフローを触った後に勝手にスキルを呼び出して回してくれる。

中身はghalintとactionlintを含む4つのチェック。

  1. pinact run -u
  2. ghalint run
  3. actionlint
  4. シェルスクリプト内の ${{ }} の直接展開チェック

pinact run -uは特にClaude Codeに最初からworkflowを書かせるなら事実上必須で、めちゃくちゃ古いバージョンの外部actionとかを指定してくることがよくある(actions/checkout@v4はもう見飽きるほど見た)ので、一発目にアップデートをかけてしまっている。これは正直なところ諸説あると思っていて、このタイミングで侵害されたバージョンを踏む可能性もあるので一旦は古いやつのままpinして、minimumReleaseAge付きのRenovateで後でアップデートするとかの方がベターかもしれない。

pinactに直近n日のアップデートは無視するオプションがあったらな…と思ったら、あった。

pinact run -u --min-age 7

export PINACT_MIN_AGE=7
pinact run -u

これは知らなかったので取り込んでおく。この記事書いてよかった。

「シェルスクリプト内の ${{ }} の直接展開チェック」はactionlintの補完のためにやっていて、だいたいactionlintが指摘してくれるが、フォーマットの制約が厳しいプロパティとかは指摘しないようになっていたりするので、原則的にすべてenvを介して渡すことにしている。

3rd party actionをできるだけ使わない

限界はあるが、Git操作をするだけ、とか、PRを立てるだけ、みたいなのはGitHub CLIでけっこう代替できてしまうというのを知ってからは特にこの2つについては3rd party actionは使っていない。

例えばこんな感じ。ぱっと見で何書いてるかわかりにくいよねーみたいな問題はあるかもしれないが、それなら自分でひとつactionを作ってしまえばいいと思う。個人的には動き始めてしまえば全然気にならない。

name: Sample

on:
  workflow_dispatch:

jobs:
  sync:
    runs-on: ubuntu-slim
    timeout-minutes: 15
    permissions:
      contents: write
      pull-requests: write

    steps:
      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
        with:
          persist-credentials: false

      - name: Some git operation
        run: |
          git xxxxxxxxxxxx

      - name: Setup git
        env:
          GH_TOKEN: ${{ github.token }}
        run: |
          gh auth setup-git

      - name: Create Pull Request with GitHub CLI
        env:
          GH_TOKEN: ${{ steps.token.outputs.token }}
        run: |
          BRANCH_NAME="feature/some-changes"
          git config user.name "github-actions[bot]"
          git config user.email "41898282+github-actions[bot]@users.noreply.github.com"

          if [[ -n $(git status --porcelain action.yml) ]]; then
            git checkout -b "$BRANCH_NAME"
            git add --all
            git commit -m "chore: some changes"
            git push origin "$BRANCH_NAME" --force

            PR_URL=$(gh pr create \
              --title "Some changes" \
              --body "This PR updates something" \
              --base main \
              --head "$BRANCH_NAME" 2>&1 || gh pr view "$BRANCH_NAME" --json url --jq '.url')

            {
              echo "## Update something"
              echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
            } >> "$GITHUB_STEP_SUMMARY"
          else
            echo "No changes detected"

            {
              echo "## Sample"
              echo ""
              echo "☑️ **No changes detected.**"
            } >> "$GITHUB_STEP_SUMMARY"
          fi

SecretsにKeyを置かない

これは使っているサービスにもよるかもしれない。思いつく限りで、個人で管理しているリポジトリでOrganization secrets, Environment secrets, Repository secretsにKey自体はまったく置いていないはず。ここでいうKeyとは、例えばGitHub AppのPrivate keyとか、Google CloudのSA Keyとか。

Google Cloudの接続はCloud BuildのAppかWIF(Workload Identity Federation)で、GitHub AppのPrivate keyはGoogle CloudのKMSに入れてある。(ちなみにPATはこの記事を書いている時点ではひとつもない。)

個人的に使う範囲のサービスがだいたいKey-lessで済んでしまうからこそ言えることではあるが、永続アクセスを持っていかれるものをそもそも置いておかないことで心の安寧を手に入れているというのはあると思う。何かしらKeyを置かないといけなくなったらできる限りEnvironment secretsに入れてprotected branchでしかアクセスできないようにするなど、何らかの保護をするとは思う。あとは極力Keyの方の権限を絞ったり、Key自体を細かく分離したい。Environmentを使うと強いKeyを使えるブランチとそうでないブランチを分けることができたりするのでユースケースによってはオススメ。


やろうと思っているけど徹底できていないこと

いろいろ書いたがまだやれていないこともあって、最近ちょっとずつ改善しているところ。

Require actions to be pinned to a full-length commit SHAの有効化

リポジトリのSettings > Actions > Generalにある。まだ全リポジトリでは有効にできていない。最近よく触るところでは有効にしている。そもそもGitHubのリポジトリもIaC化してこの辺の設定もぱっと見で一覧化できるようにしたいので、セットでやってしまうつもり。

branch ruleset / push ruleset

default branchの保護をもっと徹底したいが、やりきれていない。正直やってられないリポジトリもあるので現状はかなりグラデーションがある。これも先のIaC化と合わせてもう少しよくできそうなので考えておく。Signed commitの必須化もしたい。

ghalint / actionlintを全リポジトリで回す

そもそもPRが必須になってないリポジトリもある中で回す意味あるのかという問題もあり、そこまではやっていない。グループ分けしていくつかのリポジトリでは共通設定として同じチェックが回るようにしたいなーとは思っていて、これもIaC化とあわせて…。


さいごに

絶対これやってね、みたいな性質のものではないと思うし、各々が各々の感度で好きにやればいいと思うんだけれど、あまりにも気をつけるポイントが多すぎて「これ普通の人が個人開発で安全に扱うの無理じゃね?」と思っている。GitHub Actionsの話じゃないしな、ということで載せていない話もあるし、なんというか各位ご安全に。以上。