CLAUDE LABEN
CODE — Claude Codeにリモート管理者向けTrusted Devicesが追加。リモートセッション前に端末を検証できますCODE — ストリーミング時のCPU使用が約37%削減され、長時間の自動運用がより安定しますCODE — フルスクリーンのマウスクリック操作と音声入力の修正、Linuxの音声検出改善が入りましたAUTH — 静的APIキーを、短命でスコープ付きのWIF資格情報へ置き換えられるようになりましたTEAM — SlackでClaudeを直接タグ付けし、作業しながらタスクを委譲できるようになりましたWORKFLOW — dynamic workflowsがリサーチプレビューで登場。込み入った作業を自分で手順に分解しますCODE — Claude Codeにリモート管理者向けTrusted Devicesが追加。リモートセッション前に端末を検証できますCODE — ストリーミング時のCPU使用が約37%削減され、長時間の自動運用がより安定しますCODE — フルスクリーンのマウスクリック操作と音声入力の修正、Linuxの音声検出改善が入りましたAUTH — 静的APIキーを、短命でスコープ付きのWIF資格情報へ置き換えられるようになりましたTEAM — SlackでClaudeを直接タグ付けし、作業しながらタスクを委譲できるようになりましたWORKFLOW — dynamic workflowsがリサーチプレビューで登場。込み入った作業を自分で手順に分解します
記事一覧/Claude Code
Claude Code/2026-06-28中級

無人で回す自動処理に、静的 API キーを置きっぱなしにしない — WIF で短命資格情報へ切り替える

Claude Code が静的 API キーを WIF(Workload Identity Federation)の短命・スコープ付き資格情報へ置き換える方向に進んでいます。深夜に無人で回すスケジュール実行で、キー漏れの被害範囲を構造的に小さくする移行手順を、動くコードとつまずきどころ付きで整理します。

Claude Code170WIFセキュリティ7API キー自動化60

深夜2時、誰も見ていない時間帯にスケジュール実行が走り、API を叩いて処理を終える——この「無人で回している時間」が、実はいちばん神経を使う部分です。私自身、複数のサイトの記事更新を時間をずらして自動で回していますが、機能の華やかさよりも「置きっぱなしにしている API キーが、いつか何かの拍子に漏れていないか」という不安のほうが、ずっと頭に残ります。

2026年6月28日のアップデートで、Claude Code は静的な API キーを WIF(Workload Identity Federation) の短命・スコープ付き資格情報へ置き換える方向を示しました。OIDC 準拠の ID プロバイダと連携し、リクエスト時に発行される使い捨ての資格情報を使う仕組みです。ここでは、その発想を個人開発の小さな無人運用に翻訳して、何をどう移すと被害範囲が縮むのかを具体的に書いていきます。

静的キーは「漏れた瞬間」ではなく「漏れていた期間」が怖い

ANTHROPIC_API_KEY を環境変数や .env に置いて、cron やスケジューラから読ませる——これは動きますし、最初はそれで十分です。問題は、このキーがいつまでも有効であることにあります。

静的キーの本当の怖さは、漏れた瞬間そのものではありません。漏れていたことに気づくまでの「期間」です。CI のログにうっかり出力されていた、バックアップに含まれていた、古いマシンのシェル履歴に残っていた——どれも、発覚するのは数週間後だったりします。その間ずっと、フルスコープの有効なキーが外を歩いている状態になります。

無人運用ではこの構造がさらに効いてきます。人が画面を見ていないので、不審なリクエストの急増にすぐ気づけません。気づく頃には、それなりの回数が叩かれた後です。だからこそ「漏れても有効期間が短い」「漏れても使える範囲が狭い」という二つの性質が、運用の安心感を大きく変えます。

WIF は「鍵を配る」のではなく「その都度交換する」

WIF の発想を一言でいうと、長持ちする秘密(静的キー)を配って回るのをやめて、信頼できる身元証明をその都度、短命の資格情報と交換することです。

流れはおおむね三段階になります。まず、実行環境が OIDC 準拠の ID プロバイダから自分の身元を示すトークン(ID トークン)を受け取ります。次に、そのトークンを資格情報の発行元へ提示し、引き換えに有効期間の短い・スコープを絞った資格情報を受け取ります。最後に、その短命資格情報で実際の API を叩きます。処理が終わって資格情報が期限切れになれば、それはもう何の役にも立ちません。

静的キーと短命資格情報の違いを並べると、運用上の意味がはっきりします。

観点静的 API キーWIF の短命資格情報
有効期間失効させるまで無期限数分〜1時間程度で自動失効
保管場所環境変数・.env・シークレットストア原則メモリ上のみ。永続保存しない
漏えい時の被害気づくまでフルスコープで悪用可能期限切れ後は無効。スコープ外も不可
ローテーション手動または定期ジョブで差し替えリクエストのたびに実質ローテーション
身元の証明キーを持っていること=本人OIDC トークンで実行環境を検証

ポイントは右下です。静的キーは「持っていること」が本人証明のすべてなので、コピーされたら終わりです。WIF は「どの実行環境から来たか」を毎回検証するので、キー文字列だけ抜かれても、検証を通る環境がなければ交換が成立しません。

移行の最小単位は「キー直書き」を「取得関数」に変えること

いきなり全部を WIF に寄せる必要はありません。移行のいちばん小さな一歩は、コードの中で API キーを直接読んでいる箇所を、資格情報を取得する関数の呼び出しに差し替えることです。ここを関数の裏側に隠してしまえば、中身を静的キーから短命資格情報へ後から入れ替えても、呼び出し側は変わりません。

次のコードは、その「取得関数」を一つのクラスにまとめた例です。OIDC トークンを短命資格情報と交換し、有効期限が近づくまではメモリ上にキャッシュし、期限の手前で先回りして取り直します。エンドポイントや項目名は環境やプロバイダで変わるため、公式ドキュメントで実際のフィールド名を確認しながら埋めてください。

import os
import time
import threading
import requests
 
class ShortLivedCredentialProvider:
    """OIDC トークンを短命資格情報と交換し、期限手前で先回り更新する。
 
    呼び出し側は get() を呼ぶだけ。中身が静的キーでも WIF でも、
    インターフェースは変わらない。
    """
 
    # 期限の何秒手前で「もう使わない」と判断するか(時計ずれ+処理時間の余白)
    REFRESH_BUFFER_SEC = 120
 
    def __init__(self, token_url: str, exchange_url: str, audience: str):
        self._token_url = token_url        # OIDC ID トークンの取得元
        self._exchange_url = exchange_url  # 短命資格情報との交換先
        self._audience = audience          # 交換先が期待する audience
        self._lock = threading.Lock()
        self._cached_value = None
        self._expires_at = 0.0
 
    def _fetch_id_token(self) -> str:
        # 実行環境のメタデータサービス等から OIDC ID トークンを取得する。
        # クラウドや CI ごとに取得方法が異なるため、ここは環境に合わせる。
        resp = requests.get(
            self._token_url,
            params={"audience": self._audience},
            headers={"Metadata-Flavor": "Google"},  # 例。プロバイダにより異なる
            timeout=10,
        )
        resp.raise_for_status()
        return resp.text.strip()
 
    def _exchange(self, id_token: str) -> tuple[str, float]:
        # ID トークンを提示して、短命・スコープ付きの資格情報を受け取る。
        resp = requests.post(
            self._exchange_url,
            json={
                "grant_type": "urn:ietf:params:oauth:grant-type:token-exchange",
                "subject_token": id_token,
                "subject_token_type": "urn:ietf:params:oauth:token-type:jwt",
                "scope": "messages:write",  # 必要最小限のスコープだけ要求する
            },
            timeout=10,
        )
        resp.raise_for_status()
        data = resp.json()
        # フィールド名はプロバイダの仕様に合わせて読み替える
        value = data["access_token"]
        ttl = float(data.get("expires_in", 900))
        return value, time.time() + ttl
 
    def get(self) -> str:
        now = time.time()
        # 期限の手前を過ぎていたら、ロックを取って更新する
        if now >= self._expires_at - self.REFRESH_BUFFER_SEC:
            with self._lock:
                # ロック待ちの間に別スレッドが更新済みなら再利用
                if now >= self._expires_at - self.REFRESH_BUFFER_SEC:
                    id_token = self._fetch_id_token()
                    self._cached_value, self._expires_at = self._exchange(id_token)
        return self._cached_value
 
 
# 呼び出し側はこれだけ。キーの実体がどこから来るかを知らなくてよい
provider = ShortLivedCredentialProvider(
    token_url=os.environ["OIDC_TOKEN_URL"],
    exchange_url=os.environ["CREDENTIAL_EXCHANGE_URL"],
    audience=os.environ["EXCHANGE_AUDIENCE"],
)
 
# Anthropic クライアントへ毎回「取りたて」の資格情報を渡す
from anthropic import Anthropic
 
def make_client() -> Anthropic:
    return Anthropic(api_key=provider.get())

このコードで効いているのは REFRESH_BUFFER_SEC の存在です。資格情報を「期限ちょうどまで使う」のではなく、期限の少し手前で使うのをやめる。長時間バッチでは、取得してから実際に API へ届くまでに時間差があり、サーバーとの時計のずれもあります。期限ぴったりまで粘ると、稀に「自分の時計では有効、相手から見ると失効」という事故が起きます。手前で切り上げる設計は、その境界事故を構造的に防ぐためのものです。

つまずきやすいのは、時計・スコープ・フォールバックの三つ

実際に移すと、つまずく場所はだいたい決まっています。

一つ目は時計のずれです。短命資格情報は有効期間が短いぶん、サーバーとのわずかな時刻差が顕在化しやすくなります。先ほどの余白に加えて、実行環境の NTP 同期が効いているかを一度確認しておくと、原因不明の 401 を未然に減らせます。

二つ目はスコープの取りすぎです。せっかく短命にしても、毎回フルスコープの資格情報を発行していたら、被害範囲を絞るという狙いが半分になります。自動処理が本当に必要とする操作だけを scope に書く。記事を投稿するだけのジョブに、課金や管理系の権限まで含めない。短命であることと、狭いことは別の防御で、両方そろって初めて効きます。

三つ目はフォールバックの方向です。資格情報の取得に失敗したとき、「とりあえず古い静的キーで動かす」という逃げ道を残すと、それは結局フルスコープの長命キーを生かし続けることになります。ここは深く考えずに失敗で止める——いわゆる deny by default に倒すほうが、無人運用では安全です。動き続けることより、被害を広げないことを優先します。秘密の露出面そのものを絞る考え方は、サンドボックスはコードを動かせても、認証ファイルは読ませない でも触れています。

まず一本のジョブから、取得関数の裏に隠す

全面移行をいきなり狙わず、いちばん事故っても傷が浅いジョブを一本選んで、そこだけ取得関数の裏に資格情報を隠してみてください。呼び出し側のコードが変わらないことを確認できれば、残りのジョブは同じ関数を共有させるだけで順に寄せていけます。

そのうえで、もし過去にキーを履歴へ載せてしまった経験があるなら、移行と並行して APIキーを誤って git commit してしまった時の緊急対応手順 で棚卸ししておくと、古い静的キーを安心して無効化できます。短命資格情報への移行は、その「古い鍵を捨てる」決断を、ずっと軽くしてくれます。

同じように無人で何かを回している方の参考になれば嬉しいです。お読みいただきありがとうございました。

シェア

お読みいただきありがとうございます

Claude Lab は広告なしで運営しており、サーバー費用などの運営コストはメンバーシップのご支援で賄っています。実装コード・ベンチマーク・本番設計パターンなど、実務でお役立ていただける記事を毎日更新しています。もし読んでよかったと感じていただけましたら、ぜひご覧ください。

  • コピー&ペーストで使える実装コード付き
  • 毎日新しい上級ガイドを追加
  • ¥580/月 または ¥1,480 の永久アクセス
メンバーシップを見る →

もしこの記事がお役に立ちましたら、チップ(¥150)で応援いただけると大変励みになります。広告なしでの運営を続けるため、皆さまのご支援が大きな力になっています。

関連記事

Claude Code2026-06-27
無人で回し続けても重くならないか — Claude Code 長時間セッションのメモリ使用量を観測して頭打ちにする
長時間の無人セッションで Claude Code が徐々に重くなる問題を、ps による RSS 定点観測・ローリング基準値のウォッチドッグ・セグメント分割の3点で頭打ちにする運用設計を、観測スクリプトと before/after で具体的にまとめます。
Claude Code2026-06-24
修正済みのファイルを、もう一度直そうとしました — 浅い永続クローンの陳腐化と「読む前に取り直す」判断
無人で動くエージェントが、すでに直したファイルをもう一度直そうとした原因は、数日前の浅いクローンを読み続けていたことでした。陳腐化を数値で検知し、判断の前にだけ取り直す設計を整理します。
Claude Code2026-06-19
弾いたはずの記事が公開された — 品質ゲートと git push を同じ呼び出しにまとめた代償
無人運用の投稿パイプラインで、品質ゲートで弾いたはずの記事がそのまま公開されました。原因はゲートと git push を一つのシェル呼び出しに連結したことでした。終了コードが握りつぶされる仕組みと、公開マーカー方式で「通過を確認してからしか push しない」二段構えの実装を記録します。
📚RECOMMENDED BOOKS
大規模言語モデル入門
山田育矢
LLM開発
生成AIプロンプトエンジニアリング入門
我妻幸長
プロンプト
Claude CodeによるAI駆動開発入門
平川知秀
AI駆動開発
※ アフィリエイトリンクを含みます
もっと見る →