
こんにちは。よっしーです(^^)
背景
この連載では、Claude Codeの公式ドキュメントを1ページずつ読み解いていきます。公式ドキュメントは情報が網羅されている分、「結局どの機能を、どんな場面で使えばいいのか」は自分で考える必要があり、読むのに意外と時間がかかります。そこで、私が実務で使うために読み込んだ内容を「使う場面→実例コード」の順に整理して残していくことにしました。専門家の解説というより、一次情報を読んだ記録です。推測や動作を確認していない部分には、その都度そう書きます。
1. 一言でいうと何か
このページは、Claude アプリゲートウェイを本番で動かし続けるための運用側リファレンスです。
第49回で立ち上げ方を、第50回で gateway.yaml の全オプションを扱いました。今回は残りの半分——IdP に登録し、コンテナをビルドしてデプロイし、ログとヘルスを監視し、シークレットをローテーションし、セキュリティレビューに答える、という運用の話です。
公式ページは本番デプロイを4ステップに整理しています。この構成が実務にそのまま使えるので、そのまま引き写します。
- ID プロバイダーをセットアップする — OAuth クライアントを登録し、Okta / Entra / Google の固有事情を確認する
- ゲートウェイをデプロイする — ピン留めしたコンテナイメージをビルドし、Kubernetes / Cloud Run / 自前基盤で動かす
- 運用をセットアップする — ログ、ヘルスプローブ、障害時の挙動、シークレットローテーション、アップグレード
- セキュリティ体制を確認する — データフロー、脅威モデル、コンプライアンスの回答
そして重要な位置づけの説明があります。最初の2つは「選択を行う場所」、後の2つは「実行中に参照するリファレンス資料」。1と2は一度決めれば終わり、3と4は監視を配線するときやセキュリティレビューが来たときに開き直すもの、ということです。
もうひとつ、このページには症状ベースのトラブルシューティング表が用意されています。サインインやブートで失敗したら、順に読まずそこへ直行する設計です。
前提として何度でも繰り返される原則:**プライベートネットワークにデプロイすること。**Claude Code はアドレスがプライベートなゲートウェイにしか接続しません。理由も毎回同じ——信頼されたゲートウェイは、開発者マシンでコマンドを実行する設定をプッシュできるからです。
2. どういう場面で役立つか
シーン1:IdP 選定でハマる前に固有事情を知る
「OIDC 準拠なら何でも動く」は本当ですが、メールとグループのクレームの出し方がプロバイダーごとに違うため、事前に知らないと確実に詰まります。Okta の org 認可サーバーは薄い id_token を返す、Entra はグループ名ではなく GUID を出す、Google はそもそもグループを含まない——この3点を知っているかどうかで初日の消耗が変わります。
シーン2:Postgres が落ちたときに何が起きるか設計しておく
このページの白眉は障害時の挙動の節です。「Postgres が落ちたらどうなるか」に対する答えが、オーケストレーターの readiness 設定次第で真逆になるという話が明確に書かれています(後述)。事前に決めておかないと、障害時に「動くはずの推論まで止まった」という事態になります。
シーン3:セキュリティレビューに答える
データフロー表、脅威モデル、コンプライアンス体制の節は、そのまま社内レビューの回答素材になります。特に**「何がスコープ外か」を明示している**点が誠実で、実務上も価値があります。
シーン4:エラーメッセージから原因を逆引きする
トラブルシューティング表は症状(表示されるエラー文言)でキー付けされています。デュアルスタック DNS、企業プロキシ、Chrome の CSP、IMDSv2 のホップリミット——実際に踏みそうな罠が具体的に並んでいます。
不要・向かないケース
- Lambda や Cloud Functions で動かしたい。動きません。ゲートウェイは長時間実行される HTTP サーバーです。サーバーレスなら Cloud Run を使い、
min-instances: 1を設定します。 - Alpine などの musl ベースイメージをそのまま使いたい。glibc ビルドの唯一の動的依存は glibc なので、musl 環境では
linux-x64-musl/linux-arm64-muslビルドと追加パッケージが必要です。 - ゲートウェイでモデルアクセスを「完全に」封じたい。**ゲートウェイは、モデルへの唯一の経路が自分であることを強制しません。**自前の認証情報を持つ開発者は直接プロバイダーを叩けます。塞ぐならネットワークポリシーの仕事です(後述の副作用に注意)。
- セッション単位で強制ログアウトしたい。**セッションごとの取り消しはありません。**ベアラートークンは JWT シークレットでローカル検証されるためです。個別のオフボーディングは IdP でのプロビジョニング解除、緊急の全セッション無効化は JWT シークレットの完全置き換えになります。
- 複数の OIDC 発行者を1台で扱いたい。個別インスタンスを立てます。
3. 手順と設定の実例
このページにはまとまったコード例(設定ファイルやマニフェスト)は含まれていません。示されるのは判断材料と、いくつかの単発コマンドです。以下ではその方針に沿って、手順と仕組みの解説を中心に構成し、原文にあるコマンドはそのまま引用します。
ステップ1:ID プロバイダーのセットアップ
やることは1つ。リダイレクト URI https://<gateway>/oauth/callback を1つだけ持つ、機密 OAuth/OIDC ウェブアプリケーションを登録し、アクセスを与えるユーザーまたはグループに割り当てる。
IdP に求められる要件は3つです。
/.well-known/openid-configurationを提供する(本番では HTTPS)。ゲートウェイはhttp://発行者も受け付けますが、ループバック発行者は追加でCLAUDE_GATEWAY_ALLOW_LOOPBACK=1が必要です。- 認可コードフローをサポートする。PKCE はデフォルト有効で、対応していない IdP では
oidc.use_pkce: falseにします。 id_tokenでemail(必要ならgroups)を返すか、oidc.userinfo_fallback: trueで userinfo から補う。
プライベート PKI なら oidc.ca_cert_pem を設定します。
プロバイダー固有の落とし穴が3つ。
Okta:https://example.okta.com の org 認可サーバーは email と groups を省いた薄い id_token を返すので、これを発行者に使うなら userinfo_fallback: true を常に設定します。https://example.okta.com/oauth2/default のようなカスタム認可サーバーなら直接クレームを含むのでフォールバック不要。そして重要な但し書き——Okta は oidc.scopes で groups スコープを要求し、かつアプリのグループクレームフィルターが許可した場合にのみ groups を発行します。**userinfo_fallback は「要求されなかったクレーム」を埋めることはできません。**フォールバックさえ設定すれば何とかなる、という誤解を先回りして潰しています。
Microsoft Entra ID:発行者は https://login.microsoftonline.com/<tenant-id>/v2.0。Entra はグループ名ではなくグループのオブジェクト ID(GUID)を発行するので、managed.policies.match.groups に GUID を書くか、人間が読める名前が欲しければアプリロールを使うことになります。テナントが groups ではなく roles の下でロールを出すなら oidc.groups_claim: roles。
Google Workspace:発行者は https://accounts.google.com。**Google の id_token はグループを含みません。**グループベースの制御をしたければ oidc.google_groups(Admin SDK Directory API を叩く)を設定します。使わない場合は、メンバーシップの門番に oidc.allowed_email_domains、ポリシー割り当てに managed.policies.match.email_domain を使います。さらに Google は標準の offline_access スコープを無視するので、リフレッシュトークンを得るには oidc.scopes: [openid, profile, email] と oidc.extra_auth_params: { access_type: offline, prompt: consent } を設定します。
リフレッシュトークンの重要性は独立した警告になっています。リフレッシュトークンは2つの役割を持ちます——セッションを無言で更新して開発者をブラウザに戻さないこと、そしてプロビジョニング解除を駆動すること(IdP でユーザーを無効化すると次のリフレッシュが失敗し、ttl_hours 以内にセッションが終わる)。ゲートウェイはデフォルトで offline_access を要求します。IdP がリフレッシュトークンをまったく出せない場合、ゲートウェイは動きますが無言更新がないので、開発者は期限切れのたびにブラウザログインをやり直します。1時間ごとを避けるには session.ttl_hours を 8 や 12 に上げますが、トレードオフはプロビジョニング解除の遅延——無効化されたユーザーが長い TTL の分だけアクセスを保持します。
ステップ2:デプロイ
ゲートウェイは単一の Linux バイナリで、レプリカはステートレス。Postgres が共有調整層です。だから水平スケールは素直で、「環境内でステートレスサービスを動かすやり方」でそのまま動かせます。
デプロイ場所以外に、先に決めておくべき4つの論点があります。
コスト:ゲートウェイに個別ライセンスもシート課金もありません。claude バイナリの一部だからです。支払うのは、既存のクラウド/Anthropic コミットメント経由の推論費用と、コンテナのコンピュート、テレメトリコレクターの費用。
バイパス:前述のとおり、ゲートウェイは自分が唯一の経路であることを強制しません。塞ぐならエグレス制御(例:ゲートウェイ以外から api.anthropic.com への通信をブロック)ですが、副作用が明記されています——そのエグレスを塞ぐと、各開発者マシンから api.anthropic.com を呼ぶ WebFetch ドメインセーフティチェックも壊れます。管理ポリシーで skipWebFetchPreflight: true を設定して無効化する必要があります。この手の「Aを塞ぐとBが壊れる」情報は、実際に踏むまで気づきにくいので価値が高い。
複数ゲートウェイ:各ゲートウェイは独立したデプロイです。CLI はゲートウェイのホスト名ごとに信頼フィンガープリントと認証情報を保存するので、チームごとに別ゲートウェイへ接続しても衝突しません。
サーバーレス:Cloud Run は可、min-instances: 1 でコールド OIDC ディスカバリーを回避。Lambda / Cloud Functions は不可。
プロキシの扱いも共通事項です。本番トポロジーはどれもプレーン HTTP のレプリカの前に L7 プロキシ(Ingress、Cloud Run フロントエンド、ALB)を置きます。そこで listen.trusted_proxies をプロキシのソース範囲に設定します。ゲートウェイは TCP ピアが信頼されている場合にのみ X-Forwarded-For を尊重するからです。設定しないとどうなるかも書かれています——全リクエストがプロキシの IP から来ているように見え、IP ごとのレート制限が1つの共有バケットに潰れ、監査イベントにプロキシの IP が記録される。
コンテナイメージの作り方
標準リリースのネイティブ claude バイナリを包む自前イメージをビルドします。
- ピン留めしたリリースから、イメージアーキテクチャ向けの Linux ビルドをダウンロードする
- リリースの GPG 署名付き
manifest.jsonに対して検証する - ビルドコンテキストにコピーする
ビルド環境がリリースホストに届かないなら、内部レジストリにミラーして、実行するバージョンをピン留めします。
バイナリ以外にイメージが満たすべき条件が3つ。
- glibc ベースのイメージであること(musl なら専用ビルドと追加パッケージ)
- 書き込み可能な状態ディレクトリ。ゲートウェイは任意のユーザーで動きますが、最小イメージには書き込み可能なホームがないので、
CLAUDE_CONFIG_DIRを/tmp/.claudeなどに設定します - コンテナコマンドは次のとおり。設定ファイルは読み取り専用でマウントし、シークレットは環境変数で渡します
claude gateway --config /etc/claude/gateway.yaml
Kubernetes と Cloud Run
Kubernetes は他のステートレスサービスと同じで、要点は3つ。ConfigMap から設定、Secret からシークレットをマウントし(YAML では ${file:/path/to/secret} か環境変数で参照)、Ingress で TLS を終端して listen.public_url を Ingress のホスト名にし、readiness プローブを GET /readyz、liveness プローブを GET /healthz に向ける。
認証情報は静的キーよりプラットフォームのワークロードアイデンティティを優先します——EKS 上の Bedrock なら IRSA、GKE 上の Agent Platform なら Workload Identity、AKS 上の Foundry ならワークロードアイデンティティ。アップストリームで auth: {}(Foundry は use_azure_ad: true)にすれば、そのプロバイダーのデフォルト認証情報チェーン経由で Pod のアイデンティティを拾います。GKE 上で Bedrock を使うようなクロスクラウドの組み合わせでは、明示的な認証情報が必要です。
Cloud Run の設定要点は4つ。listen.port はデフォルト 8080 のまま(Cloud Run の PORT と一致)か port: ${PORT}。設定はシークレットボリュームでマウント。min-instances: 1。そして public_url に注意——/login はパブリックアドレスを拒否し、*.run.app URL はパブリックに解決するので、Cloud Run URL は curl やブラウザのスモークテストにしか使えません。例外は、Private Service Connect と Cloud DNS プライベートゾーンで *.run.app がプライベート解決されるネットワーク構成で、その場合は有効な public_url になります。
デプロイが済んだら、MDM か OS ごとの managed-settings.json で forceLoginMethod と forceLoginGatewayUrl を開発者マシンにプッシュします。これがないと /login はゲートウェイの選択肢がない標準アカウントピッカーを出すだけです。
ステップ3:運用
ログは stderr に2ストリーム流れます。どちらも JSON フレンドリーです。
監査イベントはセキュリティ関連イベントごとの単一行 JSON で、stderr をログアグリゲーターにパイプします。発行されるイベントは config.load、session.mint、session.refresh、device.authorize、device.verify、auth.denied、access.denied、inference、managed.serve、spend.blocked、admin.denied。フィールドはイベントによって異なり、成功した mint / refresh は sub・email・client_ip・結果を、拒否イベントは理由・パス・クライアント IPを含みます(拒否時にはアイデンティティが存在しないため、という理由付きです)。inference はどのアップストリームが処理したかと応答ステータスを記録し、admin.denied は理由(invalid_key / no_credentials)とメソッド・パスを記録します——提示されたキーマテリアルは記録しません。
運用ログは [gateway] プレフィックス付きの人間可読な行で、CLAUDE_GATEWAY_LOG_LEVEL(info / warn / error、デフォルト info)で詳細度を制御します。監査イベントには影響せず、常に発行されます。
ヘルスは GET /healthz(liveness)と GET /readyz(readiness、ストア到達性を検証)。両方とも access_control.allow_cidrs から除外されるので、リスナーをロックダウンしてもプローブは動き続けます。さらに、/.well-known/oauth-authorization-server は設定ロード・OIDC ディスカバリー・アップストリームクライアント構築・Postgres マイグレーションがすべて成功した後にのみ 200 を返すので、エンドツーエンドのブートチェックとしても使えます。
障害時の挙動 — ここが設計判断のポイント
Postgres がダウンしたとき、ゲートウェイ自体はサインイン済みの開発者にサービスを提供し続け、新しいサインインは失敗します。
- 既存セッション:ベアラートークンは JWT シークレットでローカル検証され、セッション更新はストアに触れないので、推論は提供できる
- 新しいサインイン:デバイスフローとレート制限カウンターが Postgres にあるので失敗する
- 支出制限:デフォルトはフェイルオープン(推論は流れ続ける)。ブロックしたければフェイルクローズに切り替える
そして肝心なのが readiness です。/readyz は障害中に not-ready を報告するので、readiness でトラフィックをゲートするオーケストレーターは全レプリカを一斉にローテーションから外します。結果、ゲートウェイが本来提供できたはずの推論を含め、すべてのトラフィックがロードバランサーで失敗します(/healthz の liveness は通るのでレプリカ自体は再起動されません)。
これを避けたいなら、readiness プローブを /healthz に向けるという選択肢が明示されています。**コストは、新しいサインインが「ready と報告し続けるレプリカ」に対して失敗すること。**どちらが自組織にとって望ましいかは事前に決めておくべき判断です。
IdP がダウンした場合は、既存セッションが ttl_hours まで機能し、新規ログインと更新が失敗します。IdP に頻繁なメンテナンスウィンドウがあるなら ttl_hours を長めに。
JWT シークレットのローテーション
既存セッションを生かしたまま回すには3ステップ。
- 新しいシークレットを生成し、
session.jwt_secret配列の先頭に付加する - デプロイメントをロールする(新トークンは新シークレットで署名、旧トークンも引き続き検証される)
ttl_hours+マージンの後、古いシークレットを削除してもう一度ロールする
ここで重要な副次的事実。ローテーションは、有効期限前にセッションを強制的に消す唯一の方法でもあります。セッションごとの取り消しがないからです。配列に古いものを残さず完全に置き換えれば、未処理の全セッションが一度に無効化されます。個別のオフボーディングは IdP でのプロビジョニング解除(ttl_hours 以内に終了)を使います。
Postgres が保持するもの
ブート時マイグレーションで5テーブルが作られます。
| テーブル | 内容 | 保持期間 |
|---|---|---|
kv | デバイスグラント(10分 TTL)とレート制限カウンター | 行ごとの TTL |
spend | プリンシパルごとの期間から現在までの支出カウンター(セント単位) | admin.spend_retention_months(デフォルト13) |
spend_limits | 設定された支出キャップ | API 経由で削除されるまで |
admin_audit | Admin API ミューテーションのトレイル | admin.audit_retention_days(デフォルト365) |
principal_emails | 各プリンシパルの最後に見たメール・表示名・IdP グループ(PII を含む) | admin.identity_retention_days(最終アクティビティから、デフォルト90) |
30秒ループが TTL 超過の kv 行を期限切れにし、1時間のスイープが支出テーブルの保持ウィンドウを実装するので、無制限に成長するものはありません。支出制限を設定していなければ kv しか書かれません。
バックアップの要否も明快です。支出制限を使っているなら、DB の喪失は「支出追跡とキャップの喪失」であって「開発者の再ログイン」だけでは済まないので、定期バックアップを実行します。
そして GDPR 的な要求に効く一文。退職した開発者を保持期間を待たずに直ちに削除するには、次を直接実行します。
DELETE FROM principal_emails WHERE principal = '<sub>'
メール・名前・グループを保持するテーブルはこれだけで、spend と admin_audit の行は疑似匿名の OIDC sub しか参照していません。
アップグレードとロールバック
レプリカがステートレスなのでローリング再起動はいつでも安全。ゲートウェイはブート時にマイグレーションを走らせるため、新バイナリをデプロイすれば DB は自動的にマイグレートされます。DDL を実行できないロールなら、スキーマを事前作成し、_migrations テーブルを現在のバージョンにシードします(しないと CREATE TABLE を試みるブートが失敗します)。
マイグレーションは追加のみなので、より少ないマイグレーションしか知らない旧バイナリへのロールバックは安全です(余分な行は無視されます)。ただしロールバックは YAML を旧バイナリのスキーマで再検証するので、新リリースで導入されたキーを使っている設定は旧バイナリで起動に失敗します。ロールバック前に新キーを削除してください。
最後に運用ポリシーの話。**イメージでバージョンをピン留めしている以上、新リリースのセキュリティ修正は、ピンを更新して再デプロイするまで届きません。**ゲートウェイを「本番認証情報を保持する他のサービス」と同じパッチング頻度に組み込むべき、と明記されています。
ステップ4:セキュリティ
データフローは5行の表に整理されています。
| データ | パス | ゲートウェイが Anthropic に送るか |
|---|---|---|
| 推論(プロンプト、完了) | CLI → ゲートウェイ → アップストリーム | Anthropic API がアップストリームに設定されている場合のみ |
| テレメトリ(OTLP メトリクス+オプトインのログ/トレース) | CLI → ゲートウェイ → コレクター | なし |
| アイデンティティ(メール、グループ、sub) | IdP → ゲートウェイ → JWT → CLI(CLI が OTLP エクスポートにスタンプ) | なし |
| 管理設定 | ゲートウェイ YAML → CLI | なし |
| 監査ログ | ゲートウェイ stderr → アグリゲーター | なし |
脅威モデルの前提が明快です。**ゲートウェイはネットワーク境界の内側にあるが、個々の開発者ラップトップは信頼されていないと見なす。**対策は3つ。
- 開発者が持つのは生のアップストリームキーではなく短命の JWT。CLI→ゲートウェイは RFC 8628 デバイスグラント、ゲートウェイ→IdP はデフォルトで PKCE を実行するので、傍受された IdP 認可コードは無用。
- デバイス検証ページは同一オリジン POST と RFC 8628 §5.1 に基づく IP ごとのレート制限を実装。
- アウトバウンドは SSRF ガードを通る——DNS を解決し、リンクローカルとクラウドメタデータアドレスをブロックし、デフォルトでループバックをブロックし、接続を解決済み IP にピン留めする。したがって IdP や OTLP 宛先のようなオペレーターが影響を与える URL がクラウドメタデータエンドポイントにリダイレクトされることはありません。RFC 1918 のプライベート範囲は意図的に許可されます(IdP や OTLP コレクターは普通プライベート IP にいるため)。
注意点として、ワークロードアイデンティティなどインスタンスメタデータ認証情報を使う場合、ゲートウェイはメタデータサーバーに到達できる必要があるので、独自のエグレス制御を足すときは塞がないこと。
スコープ外の脅威が2つ、はっきり書かれています。侵害されたゲートウェイホスト——ホストはアップストリーム認証情報を保持し、全接続開発者に管理設定を配るので、ゲートウェイ設定の制御は MDM の制御に匹敵します。CLI の一度きりの承認ダイアログはシェル対応設定の無言変更を制限しますが、ホストセキュリティの代わりにはなりません。もうひとつは悪意のある OIDC プロバイダー——プロバイダーはゲートウェイが信頼する id_token に署名するので、任意のアイデンティティを主張できます。IdP の検証と保護は利用側の責任です。
ユーザーコードのブルートフォース耐性も定量的に説明されています。/device に入力する user_code は 20文字のアルファベットから8文字、つまり 20⁸ ≈ 2.56×10¹⁰ 通りで、10分で期限切れ。加えて IP ごとのレート制限。多くの開発者が単一の共有 NAT アドレスからサインインする組織では制限を上げる必要があります(レート制限はサインインフローのみで、推論には適用されません)。
コンプライアンス体制では、Anthropic への通信を絞りたい組織向けの具体策が並びます。ゲートウェイのデータプレーンは Anthropic API がアップストリームの場合を除き Anthropic に何も送りません。ただしホストプロセス(Claude Code CLI)はスタートアップ分析と更新チェックを送りうるので、厳格なエグレス環境ではゲートウェイのコンテナ環境で CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=1 を設定します。
クライアント側については、CLI はゲートウェイにサインインしている間、自身の使用分析を無効化し、エラー報告もサードパーティ API サーフェスではデフォルトでオフ。ただし開発者マシンは、CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=1 と skipWebFetchPreflight: true を設定しない限り、WebFetch のホスト名チェックとバージョンチェックを Anthropic に送り続けます。
細かいが有用な事実が2つ。ゲートウェイ認証情報は Anthropic 向けの評価シンクを無効化するので評価は送信されません。そしてサーベイのトランスクリプト共有で「はい」を選ぶと、Anthropic にアップロードする代わりに ~/.claude/feedback-bundles/ 配下にローカルファイルが書かれます。
更新の制御は DISABLE_UPDATES(フェッチ自体を止める)と DISABLE_AUTOUPDATER(バックグラウンド更新のみ止め、claude update は動く)の使い分け。TLS については、ゲートウェイはプレーン HTTP を拒否しませんが本番では HTTPS で提供し、Postgres は ?sslmode=require に対応、Ingress で Strict-Transport-Security を設定します。
トラブルシューティング(要点)
表は16行あるので、特に踏みやすい5つだけ挙げます。全体は公式を参照してください。
/loginが標準アカウントピッカーを出す → 管理設定にforceLoginMethod/forceLoginGatewayUrlが未設定。<host> resolves to the public (or unrecognized) address <ip>→ ホスト名が1つでもパブリック IP に解決している。よくある原因はデュアルスタック名で、AWS の内部デュアルスタックロードバランサーがパブリック範囲の AAAA を返すケースが名指しされています。パブリック範囲のレコードを落とすか、内部専用の DNS 名を別に用意します。Gateway login requires a direct connection and does not support connecting through an HTTP proxy→HTTPS_PROXY/HTTP_PROXYがゲートウェイホストに適用され、プロキシのホスト名がパブリックに解決している。ゲートウェイホストをNO_PROXYに追加します(プロキシ名がプライベート解決なら許可されます)。- Bedrock リクエストが全部 502 で
Could not load credentials from any providers→ EC2 の IMDSv2 デフォルトホップリミット 1 がコンテナからのメタデータ取得をブロック。しかもブートと/readyzは通ってしまう(AWS SDK が認証情報を解決するのは最初のリクエスト時だから)ので発見が遅れます。修正は次のコマンド、または起動テンプレートでの設定。変更はそのインスタンス上の全コンテナに効くので、可能なら ECS タスクロールを優先するか、専用ゲートウェイインスタンスに限定して露出を抑えます。
aws ec2 modify-instance-metadata-options --instance-id <id> --http-put-response-hop-limit 2
- Chrome だけ Approve ボタンがブロックされ、Safari / Firefox では動く → Chrome はリダイレクトチェーン全体に
form-actionCSP を適用する。IdP が許可リストにない2つ目のホストへリダイレクトしている。oidc.form_action_originsに各オリジンを追加します。Approve ページで DevTools → Console を開けばどのオリジンがブロックされたか分かります。
ローカル開発用の使い捨て Postgres も原文にあるので引用しておきます。
docker run --rm -p 5432:5432 -e POSTGRES_HOST_AUTH_METHOD=trust postgres
問題を報告するときに添えるものも指定されています。ゲートウェイの問題なら stderr・シークレットを消した gateway.yaml・ゲートウェイバージョン(/ のランディングページ、または /managed/settings の x-cc-gateway-version レスポンスヘッダー)・直近の変更。ログイン問題なら開発者に次を実行してもらい、そのファイルと同時刻のゲートウェイ監査ログを送ります。
claude --debug-file ./claude-debug.txt
公開 issue に投稿する前の注意が添えられています。ゲートウェイの stderr には監査イベントが、監査ログには開発者の ID が、デバッグファイルには開発者マシンの hook と MCP サーバーの出力が含まれるので、必ず確認して秘密情報を削除すること。
4. まとめ + 次回予告
- 本番デプロイは4ステップ:IdP セットアップ → デプロイ → 運用 → セキュリティ確認。前半2つは判断、後半2つはリファレンス。
- IdP は OIDC 準拠なら何でも動くが、Okta は
userinfo_fallback(ただし未要求クレームは埋まらない)、Entra は GUID かアプリロール、Google はgoogle_groupsとaccess_type: offlineが要る。 - **リフレッシュトークンがプロビジョニング解除を駆動する。**出せない IdP では
ttl_hoursを上げる代わりに失効が遅れる。 - ゲートウェイはステートレスな単一 Linux バイナリ。ライセンス費用なし。Cloud Run は可、Lambda は不可。
- バイパスは塞げるがネットワークポリシーの仕事で、
api.anthropic.comを塞ぐと WebFetch のセーフティチェックが壊れる(skipWebFetchPreflight: trueが必要)。 - イメージは glibc ベース+書き込み可能な
CLAUDE_CONFIG_DIR、バイナリは署名検証してピン留め。 trusted_proxiesを設定しないと、レート制限が1バケットに潰れ、監査ログにプロキシ IP が載る。- Postgres 障害時、既存セッションは動き続けるが
/readyzが not-ready を返すため、readiness ゲートで全レプリカが外れて全滅しうる。/healthzを readiness に使うという選択肢がある。事前に決めておく判断事項。 - **セッション単位の取り消しはない。**JWT シークレットの完全置換が唯一の一括無効化手段。個別は IdP でのプロビジョニング解除。
- **PII を持つのは
principal_emailsだけ。**即時削除は 1 行のDELETE。 - マイグレーションは追加のみでロールバック可能だが、新キーを使った YAML は旧バイナリで起動に失敗する。
- 脅威モデルは開発者ラップトップを信頼しない前提。スコープ外はゲートウェイホストの侵害と悪意ある IdP——どちらも利用側の責任。
- **バージョンをピン留めしている=セキュリティ修正も自分で取り込む必要がある。**パッチング体制に組み込む。
第49〜51回でゲートウェイの3部作(概要/設定/運用)が揃いました。残るのは支出制限と、Google Cloud での実装例です。
次回予告(暫定):**支出制限(claude-apps-gateway-spend-limits)**を取り上げ、開発者ごと・グループごとのキャップの設定方法、Admin API、強制の仕組みを扱う予定です。
※連載の実際の次テーマは未確定です。

何か質問や相談があれば、コメントをお願いします。また、エンジニア案件の相談にも随時対応していますので、お気軽にお問い合わせください。
それでは、また明日お会いしましょう(^^)


コメント