Claude Media
Claude apps gatewayで431が出る原因 — IdPグループが多いときの対処

Claude apps gatewayで431が出る原因 — IdPグループが多いときの対処

Claude apps gatewayでサインイン後に431が続くときの切り分けです。v2.1.284未満の16 KiB上限、max_request_header_bytes、IdPのgroups削減の順に、残すグループも挙げます。

Claude apps gatewayにサインインできたのに、その後のリクエストがすべて 431 で失敗する。ゲートウェイのログにも監査イベントにも何も残らない。この症状は、開発者が多数のIdPグループに所属していて、リクエストヘッダーの合計がゲートウェイの上限を超えたときに起きます。

対処は3段階です。ゲートウェイが古ければアップグレードし、limits.max_request_header_bytes を設定していれば上げるか消し、それでも続くならIdPが出すグループを減らします。グループを減らすときは、アクセス・ポリシー・支出上限の判定に使っているグループを残す必要があります。

なぜグループが多いと431になるのか

ゲートウェイは、サインインした開発者にセッショントークンを発行します。トークンにはIdPから受け取ったグループの一覧が入り、以降のリクエストは Authorization ヘッダーでそれを運びます。所属グループが多い開発者ほどヘッダーが太くなり、合計がゲートウェイの受け付ける量を超えると 431(Request Header Fields Too Large)が返ります。

上限はバージョンによって違います。

数字

431になるヘッダー合計の上限

  • v2.1.284以降の既定

    256 KiB

    limits.max_request_header_bytes で下げられる

  • v2.1.284より前

    16 KiB

    アップグレードで解消

リクエストのヘッダー合計に対する値

16 KiBは 16384 バイトです。トークンはBase64で符号化されるので、グループ名1件あたり引用符と区切りを含めて数十バイトを使います。たとえばEntra IDのグループObject ID(36文字のGUID)なら、1件あたりおよそ50バイト前後です。これで割ると、300件台に乗るあたりから古いバージョンでは危うくなる計算です。ただしこれは筆者の見積もりで、他のヘッダー(Cookieなど)も合計に入るため、実際の境目は環境ごとに違います。

厄介なのは、ゲートウェイ側に痕跡が残らない点です。ゲートウェイは、この 431 についてログ行も監査イベントも書きません。サーバーのログだけを見ていると「リクエストが来ていない」ように見えます。開発者側では、サインインは成功しているのに最初の推論リクエストから失敗する、という形で現れます。

3段階の切り分け

上から順に、最初に当てはまるものだけを実施します。

切り分け

431の切り分け順序

  1. Qゲートウェイはv2.1.284以降か?
    答えがいいえ

    ゲートウェイをアップグレードします。上限が16 KiBから256 KiBに広がります。

    答えがはい
  2. Qgateway.yamlの limits.max_request_header_bytes は未設定か?
    答えがいいえ

    値を上げるか、キーを削除します。256 KiB(262144バイト)を超える値は効果がないため、上限を広げる目的なら削除が確実です。

    答えがはい

それでも431が続くなら

IdPが出すグループを減らします。アクセス・ポリシー・支出上限に使うグループは残します。

バージョンを確かめる

ゲートウェイのバージョンは、トップページ(/)の表示と、/managed/settings への応答の x-cc-gateway-version ヘッダーに出ます。コンテナイメージのバージョンを自分で固定している環境では、Claude Codeの新しいリリースに含まれる修正が自動では届きません。イメージのピン留めを更新して再デプロイしたときに、初めて反映されます。

max_request_header_bytesを見直す

このキーは limits ブロックにあり、既定では未設定です。設定すると256 KiBの上限を下げられます。過去にヘッダーを絞る目的で小さな値を入れていると、グループが多い開発者だけがそれに引っかかります。

次の設定は、キーを残したまま小さな値を入れてしまった例です。

limits:
  max_request_header_bytes: 16384   # 16 KiB。グループが多い開発者で431になる

直す場合は、キーごと消します。

limits: {}   # max_request_header_bytes を書かない。上限は既定の256 KiB

値を256 KiBより大きくしても、上限は256 KiBのままです。「もっと大きく」と考えて数値を盛る必要はなく、効果もありません。

それでも続くなら、グループを減らす

256 KiBまで広げても 431 が出るなら、1人が数千件単位のグループに入っている可能性があります。この場合、設定で受け付ける量を増やす手段はありません。IdP側でゲートウェイ向けに出すグループを減らします。

ゲートウェイのデプロイと運用の手順にあるIdP登録では、Okta、Microsoft Entra ID、Google Workspaceでグループの渡し方が違います。

IdPグループの渡し方削減で見る場所
Oktaグループの渡し方groups スコープを要求し、アプリのgroups claim filterで通す削減で見る場所filterで必要なグループだけに絞る
Microsoft Entra IDグループの渡し方グループのObject IDを出す。roles に出す構成もある削減で見る場所出すグループの範囲、または oidc.groups_claim: roles の構成
Google Workspaceグループの渡し方id_tokenにグループがなく、oidc.google_groups でDirectory APIから引く削減で見る場所引く対象のグループ

Oktaについては、groups スコープを oidc.scopes に含め、アプリ側のgroups claim filterが許可したものだけが出ます。filterを絞れば、その分だけ出力が減ります。Entra IDでは、グループObject IDではなくアプリロールを roles で出す構成が公式に紹介されています。ただし、ロールで何件が出るかはEntra側の割り当て次第で、削減効果は構成ごとに変わります。Google Workspaceは、グループを取りに行く経路をゲートウェイが持つため、取得対象の範囲を調べる必要があります。

絞るときに残すグループ

グループを減らす作業で最も危ないのは、判定に使っているグループまで消してしまうことです。ゲートウェイは、リクエストを受けるたびにトークンの groups を読んで認可します。ユーザーの一覧を自前で持たないため、トークンから消えたグループは、ゲートウェイから見るとそもそも所属していないことになります。

残すべき対象は、gateway.yaml で名前を挙げているグループです。

設定何を決めるか消えたときに起きること
oidc.allowed_groups何を決めるかサインインできる人消えたときに起きることサインイン自体が拒否される
admin.admin_groups何を決めるかgatewayセッションで管理APIを呼べる人消えたときに起きること管理APIの権限を失う
managed.policies の match.groups何を決めるかどのポリシーが適用されるか消えたときに起きること意図しないポリシー、または共通設定に落ちる
rbac_group の支出上限何を決めるかどのグループ上限が効くか消えたときに起きることグループ単位の上限が効かなくなる

名前の一致は大文字小文字を区別します。IdPが返す綴りをそのまま match.groups や allowed_groups に書いてあるはずなので、絞り込みの後も綴りが変わらないことを確かめます。ネストしたグループは展開されません。サブグループのメンバーを許可したいなら、サブグループ自体を allowed_groups に書くか、IdP側でメンバーシップを平坦化して出します。

支出上限の仕組みはstatuslineでspend_limitを表示するの記事が詳しく、rbac_group は上限の対象にIdPのグループ名を指定します。支出上限だけのために作ったグループは、他の用途がなく一見「減らせるグループ」に見えます。これも減らす対象には入れず、残すグループに含めます。

絞る作業の手順は次の通りです。

手順

グループを絞って431を解消する流れ

  1. 1

    残すグループを洗い出す

    gateway.yaml から、allowed_groups、admin_groups、managed.policies の match.groups、支出上限で使う rbac_group を書き出します。

  2. 2

    IdP側で出力を絞る

    それ以外のグループが、ゲートウェイ向けのアプリのトークンに載らないようにします。IdPの全体のグループは消さず、アプリへの出力だけを絞ります。

  3. 3

    再サインインして確かめる

    グループの変更は、次のサイレントリフレッシュで反映されます。反映の上限は session.ttl_hours です。すぐ確かめたいときは /login でサインインし直します。

IdP全体のグループを消すと、他のシステムの権限に影響します。出力を絞る対象は、あくまでゲートウェイ向けのアプリです。

切り分けでつまずきやすい点

落とし穴

ゲートウェイのログを見ても431が見つからない

431 はログにも監査イベントにも残りません。ログに何もないことは、リクエストが届いていない証拠にはなりません。サインインは成功し、その後の全リクエストが失敗する、という開発者側の症状で判断します。

サインインそのものが失敗する場合は別の問題です。Cloud gateway session expired など、ログインで出るエラーの切り分けはgatewayログインエラー3種にまとめています。431 はサインインが通ったあとに出る点が違います。

同じ人だけが失敗し、他の開発者は問題ない場合も、この症状の特徴と合います。グループの数は人によって違うので、一部の人だけが所属数の多い部署や兼務の担当で超過します。

設定項目の全体を確かめたいときは、gateway.yamlの設定リファレンスで limits ブロックの他のキー(max_request_bytes など、リクエスト本体の上限)を併せて見ます。431 はヘッダーの合計、413 は本文の大きさです。

グループが多いことの副作用は431だけではない

グループの一覧が長いと、テレメトリーにも影響が出ます。ゲートウェイを通してサインインしたセッションは、user.groups にカンマ区切りのIdPグループ一覧を載せて送ります。Claude DesktopとCoworkのテレメトリーでは、パーセントエンコード後に255文字を超える一覧や、カンマ・イコールを含むグループ名がある場合、切り詰めずに user.groups を付けません。ターミナルのセッションには全件が残ります。

グループを絞ると、431 が消えるだけでなく、この属性も欠けにくくなります。部署別のコスト集計を user.groups で行っている環境では、絞った後の集計の粒度が変わることも意識しておく点です。

まとめ

431 の原因は、トークンに載るグループの量です。ゲートウェイの設定側で直せる余地は、アップグレードとキーの見直しで尽きます。

IdPの出力を絞る段階で事故になりやすいのは、支出上限だけに使っているグループです。ほかの用途がなく、名前から「減らせるグループ」に見えるうえ、消えても 431 のようにエラーが出ず、グループ単位の上限が静かに効かなくなります。絞る前に allowed_groups、admin_groups、match.groups、rbac_group のグループ名を洗い出しておくのが、この対処でいちばん効く準備です。

この記事を共有:XはてブLinkedIn