Claude Codeの自動化にgh CLIを使うとき、アカウント全体ではなく特定リポジトリだけに権限を絞る方法

概要

今回はClaude Codeにghコマンド経由でIssue作成やPR作成を任せるときに、アクセス範囲を特定のリポジトリだけに絞る方法について紹介していきます。

自動化を組んでいて改めて気付いたのですが、gh auth login(ブラウザ認証)で発行される通常のトークンは、そのGitHubアカウントが権限を持つ全リポジトリにアクセスできてしまうんですよね。

Claude Codeにこの環境でghを使わせる以上、意図せず他のリポジトリまで操作してしまうリスクは避けたいところです。
そこでFine-grained PAT(きめ細かい個人アクセストークン)を使って、対象リポジトリだけに閉じたセットアップに切り替えました。

それではやっていきましょう!

本記事の手順はあくまで個人開発環境での設定例です。
組織やチームで運用する場合は、各社のセキュリティポリシーに沿って権限設計を確認してください。

目次

全体の流れ

まずは全体像から。
広すぎる認証から、リポジトリ限定のPATに切り替えるまでの流れを整理すると、こんな感じです。

ghの認証をリポジトリ限定に絞る手順(ブラウザ認証→Fine-grained PAT発行→切替→旧OAuth Appのrevoke)
gh CLIの認証をリポジトリ限定に絞る手順のフロー図。gh auth loginのブラウザ認証は全リポジトリにアクセス可能な問題があり、Fine-grained PATを発行してgh auth login --with-tokenで切り替え、最後に旧OAuth Appをrevokeする4ステップ

なぜアクセス範囲を絞りたかったか

Claude CodeにIssue作成・PR作成・GitHub Actionsのワークフロー起動をghコマンド経由でやらせる自動化を組んでいます。

このときghの認証がアカウント全体に効くトークンのままだと、Claude Codeが意図せず他のリポジトリまで操作できてしまう状態になります。
実際に誤操作が起きたわけではないのですが、自動化に渡す権限は必要最小限に絞っておきたいですよね。

ちなみに、この環境ではsudoが使えなかったので、gh CLI自体も公式リリースのtar.gzをユーザーローカルに展開する形でインストールしています。

gh

1
2
3
4
5
6
curl -fsSL -o /tmp/gh.tar.gz "https://github.com/cli/cli/releases/download/v2.63.2/gh_2.63.2_linux_amd64.tar.gz"
mkdir -p "$HOME/.local/bin"
tar -xzf /tmp/gh.tar.gz -C /tmp
cp /tmp/gh_2.63.2_linux_amd64/bin/gh "$HOME/.local/bin/gh"
chmod +x "$HOME/.local/bin/gh"
export PATH="$HOME/.local/bin:$PATH"

新しいシェルでも使いたい場合は、最後のexport PATH~/.bashrc等に追記しておくと楽です。

最初にブラウザ認証したら広すぎた

インストール直後は、素直に対話的なgh auth login(ブラウザでログイン)を行いました。

コマンド

1
gh auth login

ただこれは前述の通り、GitHub公式の「GitHub CLI」というOAuth App経由でトークンが発行される方式です。
このトークンはそのアカウントが権限を持つ全リポジトリにアクセスできてしまうため、特定リポジトリだけに閉じたかった今回の目的には合いませんでした。

リポジトリ限定のFine-grained PATを発行する

そこでFine-grained personal access tokensgithub.comのページから、対象リポジトリだけに絞ったトークンを発行し直しました。

設定したのは主に以下の項目です。

  • Repository access
    • 「Only select repositories」を選び、対象リポジトリ1つだけにチェック
  • Permissions(Contents)
    • Read and write(ブランチのpush用)
  • Permissions(Issues)
    • Read and write(Issue自動作成用)
  • Permissions(Pull requests)
    • Read and write(PR作成・コメント用)
  • Permissions(Actions)
    • Read and write(workflow_dispatch起動用)
  • Permissions(Metadata)
    • Read-only(自動付与される必須項目)
  • 有効期限
    • 短め(90日程度)を設定し、切れたら再発行してやり直す運用にした

必要な権限だけをチェックボックスで個別に選べるので、ブラウザ認証よりも設計がだいぶ細かく決められる印象でした。

gh側の認証をこのPATに切り替える

発行したPATに、ghの認証を切り替えます。

コマンド

1
gh auth login --with-token

実行するとプロンプトは出ないので、そのままトークンを貼り付けてCtrl+D →Enterで確定します。

同じアカウント(同じGitHubユーザー名)での再ログインになるため、
~/.config/gh/hosts.yml内のトークンがこの新しいPATで上書きされます。
ローカルには広範なトークンは残りません。

最初のOAuth Appも明示的にrevokeする

ここで一つ注意点があって、ローカルの上書きだけでは、GitHub側に残っている最初の認可自体は無効化されません

トークンを差し替えても、サーバー側では「GitHub CLIというOAuth Appにアクセスを許可した」という記録がそのまま残っているんですよね。
そのためAuthorized OAuth Appsgithub.comのページから、「GitHub CLI」を明示的にRevokeしました。

ローカルのトークン上書きとサーバー側のrevoke、両方やって初めて完全に切り替わるという点は、見落としやすいので気を付けたいところです(^^;

最終的な状態

今回の作業を終えた時点で、認証周りは次のような感じです。

  • gh(Issue作成・PR作成・ワークフロー起動など)
    • Fine-grained PAT。対象リポジトリのみ、Contents/Issues/Pull requests/Actions(読み書き)+Metadata(読み取り)のみ
  • git push / git fetchなど
    • Windows Git Credential Manager経由(ghとは別経路のため、今回の見直し対象外)
    • gh auth setup-gitghのPATに一本化することもできるが、マシン全体のgit設定に影響するため今回は見送った

gh auth statusで確認したときに、トークンがgithub_pat_...から始まっていればFine-grained PATが使われている状態です。
ブラウザ認証のトークンはgho_...形式なので、この接頭辞の違いで見分けられます。

コマンド

1
gh auth status

トークン更新時の手順(有効期限切れ時)

90日程度の短い有効期限にしたので、切れたときの手順もメモしておきます。

  • STEP 1
  • STEP 2
    • 「Regenerate token」または新規発行時と同じ設定で再発行する
  • STEP 3
    • gh auth login --with-tokenで再度貼り付けて上書きする

有効期限を短くしておくと、万一トークンが漏れたときの被害期間を抑えられる一方で、この更新作業が定期的に発生します。
そこはセキュリティと運用の手間のトレードオフとして、自分は短め運用を選びました。

使ってみた所感

メリット

  • 意図しないリポジトリへの操作を防げる
    • Claude Codeにghを使わせても、権限が対象リポジトリだけに閉じている
  • 権限をチェックボックス単位で細かく選べる
    • Contents/Issues/Pull requests/Actionsをそれぞれ個別にRead-only/Read and writeで指定できる
  • github_pat_...の接頭辞で一目で見分けられる
    • gh auth statusで今どちらの認証方式かすぐ確認できる

デメリット

  • 有効期限が来るたびに再発行の手間がかかる
    • 90日程度に設定すると、定期的にトークンを更新する作業が発生する
  • ローカル上書きとサーバー側revokeの2箇所を意識する必要がある
    • 片方だけだと広範な認可がGitHub側に残ったままになる

締め

デメリット面は初回セットアップとその後の定期更新だけなので、一度仕組みを覚えてしまえば楽ですよね!

自動で安全にAiを使いたいので、やった方がいいとは思います(^^

以上となります。
権限はマジで大事(^^
それではお疲れさまでした。