214 214
215### `upstreams`215### `upstreams`
216 216
217`upstreams` — это упорядоченный список. Шлюз направляет запросы инференса первому upstream, который разрешает запрошенную модель.217`upstreams` — упорядоченный список. Шлюз перенаправляет инференс на первый вышестоящий сервер, который разрешает запрошенную модель, пропуская любой вышестоящий сервер, [список `groups`](#send-each-team-to-its-own-upstream) которого не включает разработчика.
218 218
219При `5xx`, `429`, `401`, `403`, `404` или таймауте шлюз переключается на следующий upstream; при других `4xx` — нет, потому что такие ошибки связаны с запросом, а не с upstream. `401` или `403` означает, что upstream отклонил учётные данные, которые использовал шлюз, или отказал ему в доступе, например к запрошенной модели. `404` означает, что этот upstream не обслуживает запрошенную модель, поэтому её может обслужить следующий upstream в списке.219При `5xx`, `429`, `401`, `403`, `404` или таймауте шлюз переключается на следующий upstream; при других `4xx` — нет, потому что такие ошибки связаны с запросом, а не с upstream. `401` или `403` означает, что upstream отклонил учётные данные, которые использовал шлюз, или отказал ему в доступе, например к запрошенной модели. `404` означает, что этот upstream не обслуживает запрошенную модель, поэтому её может обслужить следующий upstream в списке.
220 220
231В зависимости от того, как ответили upstream, шлюз возвращает ответ с ошибкой от одного из них или собственный `502`:231В зависимости от того, как ответили upstream, шлюз возвращает ответ с ошибкой от одного из них или собственный `502`:
232 232
233* **Upstream вернул статус, при котором шлюз не [переключается](#multiple-upstreams)**: ответ этого upstream. Другие upstream шлюз больше не пробует.233* **Upstream вернул статус, при котором шлюз не [переключается](#multiple-upstreams)**: ответ этого upstream. Другие upstream шлюз больше не пробует.
234* **Каждый опробованный upstream завершился ошибкой, при которой шлюз [переключается](#multiple-upstreams)**: последний `429`. Если ни один не вернул `429`, шлюз выбирает, в порядке предпочтения, последний `401` или `403`, последний `404` и последний `501`. Если ни один не вернул ничего из этого — собственный `502` шлюза, `all upstreams failed (N attempted)`, где N — число всех записей в [`upstreams`](#upstreams), включая те, которые шлюз пропустил, потому что они не обслуживают запрошенную модель.234* **Все вышестоящие серверы, которые пробовал шлюз, завершились ошибкой, при которой он [переключается](#multiple-upstreams)**: последний `429`. Если ни один не вернул `429`, шлюз предпочитает по порядку последний `401` или `403`, последний `404` и последний `501`. Если ни один не вернул ничего из этого — собственный `502` шлюза, `all upstreams failed (N attempted)`. N — это число ваших записей [`upstreams`](#upstreams), включая пропущенные, за вычетом тех, [список `groups`](#send-each-team-to-its-own-upstream) которых не включает разработчика.
235 235
236Возвращая ответ upstream, шлюз сохраняет его код статуса. Сохраняется ли сообщение upstream, зависит от поставщика. Тело ошибки от upstream Anthropic API доходит до разработчика без изменений.236Возвращая ответ upstream, шлюз сохраняет его код статуса. Сохраняется ли сообщение upstream, зависит от поставщика. Тело ошибки от upstream Anthropic API доходит до разработчика без изменений.
237 237
289 base_url: https://upstream-gateway.internal.example.com289 base_url: https://upstream-gateway.internal.example.com
290 auth:290 auth:
291 api_key: ${PROXY_KEY}291 api_key: ${PROXY_KEY}
292 forward_user_identity: true # по умолчанию false292 forward_user_identity: true # default false
293```293```
294 294
295Шлюз добавляет эти заголовки к каждому запросу, который направляет этому upstream.295Шлюз добавляет эти заголовки к каждому запросу, который направляет этому upstream.
320upstreams:320upstreams:
321 - provider: bedrock321 - provider: bedrock
322 region: us-east-1322 region: us-east-1
323 auth: {} # предпочтительно: цепочка учётных данных AWS по умолчанию323 auth: {} # preferred: AWS default credential chain
324 # ИЛИ явные учётные данные:324 # OR explicit credentials:
325 # auth:325 # auth:
326 # aws_access_key_id: ${AWS_AKID}326 # aws_access_key_id: ${AWS_AKID}
327 # aws_secret_access_key: ${AWS_SK}327 # aws_secret_access_key: ${AWS_SK}
328 # aws_session_token: ${AWS_ST}328 # aws_session_token: ${AWS_ST}
329 # ИЛИ Bearer-токен Bedrock API:329 # OR a Bedrock API bearer token:
330 # auth:330 # auth:
331 # aws_bearer_token: ${AWS_BEARER_TOKEN}331 # aws_bearer_token: ${AWS_BEARER_TOKEN}
332 # Переопределите эндпоинт bedrock-runtime для развёртываний с FIPS или VPC-эндпоинтом:332 # Override the bedrock-runtime endpoint for FIPS or VPC-endpoint deployments:
333 # base_url: https://bedrock-runtime-fips.us-east-1.amazonaws.com333 # base_url: https://bedrock-runtime-fips.us-east-1.amazonaws.com
334```334```
335 335
356 region: us-east-1356 region: us-east-1
357 auth: {}357 auth: {}
358 guardrail:358 guardrail:
359 id: gr-abc123 # ID guardrail или полный ARN359 id: gr-abc123 # guardrail ID or full ARN
360 version: "1" # номер опубликованной версии или DRAFT360 version: "1" # a published version number, or DRAFT
361 # сохраните кавычки: 1 без кавычек вызывает ошибку при загрузке361 # keep the quotes: a bare 1 fails at boot
362```362```
363 363
364> [!WARNING]
365>
366> Шлюз не поддерживает входные теги guardrail. Он не добавляет теги содержимого guard в промпты, поэтому фильтр guardrail, который Amazon Bedrock применяет только к помеченному входу, не срабатывает для трафика через шлюз. Какие фильтры зависят от входных тегов, см. в разделе [input tags](https://docs.aws.amazon.com/bedrock/latest/userguide/guardrails-tagging.html) документации Amazon Bedrock.
367
368Также предоставьте `bedrock:ApplyGuardrail` на этот guardrail принципалу, который подписывает запросы этого upstream: принципалу AWS шлюза или, при использовании [`assume_role`](#bedrock-in-another-aws-account), роли, указанной в `role_arn`.364Также предоставьте `bedrock:ApplyGuardrail` на этот guardrail принципалу, который подписывает запросы этого upstream: принципалу AWS шлюза или, при использовании [`assume_role`](#bedrock-in-another-aws-account), роли, указанной в `role_arn`.
369 365
370Задайте `guardrail` либо для каждого upstream `bedrock`, либо ни для одного. При смешанной конфигурации шлюз отказывается запускаться, потому что иначе [переключение](#multiple-upstreams) могло бы отправить запрос в upstream Bedrock без guardrail.366Задайте `guardrail` либо для каждого upstream `bedrock`, либо ни для одного. При смешанной конфигурации шлюз отказывается запускаться, потому что иначе [переключение](#multiple-upstreams) могло бы отправить запрос в upstream Bedrock без guardrail.
373 369
374Когда запрос `/v1/messages`, тело которого содержит поле `amazon-bedrock-*`, например `amazon-bedrock-guardrailConfig`, попадает в upstream Bedrock с заданным `guardrail`, шлюз отвечает 400 вместо того, чтобы переслать его.370Когда запрос `/v1/messages`, тело которого содержит поле `amazon-bedrock-*`, например `amazon-bedrock-guardrailConfig`, попадает в upstream Bedrock с заданным `guardrail`, шлюз отвечает 400 вместо того, чтобы переслать его.
375 371
372> [!WARNING]
373>
374> По умолчанию шлюз не добавляет к промптам входные теги, поэтому фильтр guardrail, который Amazon Bedrock применяет только к помеченному вводу, не срабатывает на трафике через шлюз. Чтобы добавлять теги, задайте [`input_tagging`](#add-guardrail-input-tags). О том, какие фильтры зависят от входных тегов, см. [входные теги](https://docs.aws.amazon.com/bedrock/latest/userguide/guardrails-tagging.html) в документации Amazon Bedrock.
375
376##### Добавление входных тегов guardrail
377
378Чтобы шлюз добавлял входные теги, которые нужны [фильтру атак на промпты](https://docs.aws.amazon.com/bedrock/latest/userguide/guardrails-prompt-attack.html) guardrail Amazon Bedrock, задайте `input_tagging` в блоке `guardrail` и перезапустите шлюз. Задайте одно и то же значение на каждом вышестоящем сервере `bedrock`, иначе шлюз не запустится. Требуется Claude Code v2.1.316 или новее на сервере шлюза. Шлюз версии, в которой нет этого ключа, завершается при запуске с ошибкой `Unrecognized key(s) in object: 'input_tagging'`.
379
380> [!WARNING]
381>
382> Согласно [документации Amazon Bedrock](https://docs.aws.amazon.com/bedrock/latest/userguide/guardrails-tagging.html), как только запрос содержит входные теги, каждый фильтр в guardrail перестаёт оценивать непомеченное содержимое. Опробуйте `input_tagging` на тестовом шлюзе, прежде чем задавать его на шлюзе, которым пользуются разработчики.
383
384`input_tagging` принимает одно из следующих значений:
385
386| `input_tagging` | Где шлюз помечает текст | После того как guardrail заблокировал промпт |
387| :- | :- | :- |
388| `last_message` | Сообщения `user` после последнего ответа Claude | В Claude Code следующий промпт может пройти, и тогда Claude получит заблокированный промпт как часть диалога |
389| `user_messages` | Сообщения `user` | Последующие промпты в сессии тоже могут блокироваться, пока разработчик не удалит заблокированный промпт |
390| `all_messages` | Сообщения `user` и `assistant` | Так же, как при `user_messages` |
391| `all_messages_and_system` | Системный промпт и каждое сообщение, включая [системные сообщения посреди диалога](https://code.claude.com/docs/ru/llm-gateway-protocol.md#feature-pass-through) | Так же, как при `user_messages` |
392
393При `last_message`, если в сообщениях `user` после последнего ответа Claude нет текста для пометки, шлюз вместо этого помечает системные сообщения посреди диалога, появившиеся после этого ответа. Вызов инструмента считается ответом.
394
395Рекомендация Amazon Bedrock для фильтра атак на промпты — [помечать пользовательский ввод так, чтобы системный промпт был исключён](https://docs.aws.amazon.com/bedrock/latest/userguide/guardrails-prompt-attack.html). Если вы зададите `all_messages_and_system`, фильтр, срабатывающий на собственный системный промпт Claude Code, может блокировать запросы.
396
397В примере ниже помечается текст в каждом сообщении `user`:
398
399```yaml theme={null}
400upstreams:
401 - provider: bedrock
402 region: us-east-1
403 auth: {}
404 guardrail:
405 id: gr-abc123
406 version: "1"
407 input_tagging: user_messages
408```
409
410Сообщения `user` могут также содержать текст, который добавляет Claude Code, например [системные напоминания](https://code.claude.com/docs/ru/glossary.md#system-reminder), поэтому проверьте на тестовом шлюзе, что обычные запросы не блокируются.
411
412В тестах Anthropic помеченная сессия сохраняла чтение из [кэша промптов](https://code.claude.com/docs/ru/prompt-caching.md) от одного промпта к другому, а теги не добавляли входных токенов.
413
414##### Что не покрывают входные теги
415
416Ни одно значение `input_tagging` не остановит разработчика, который намеренно помещает текст туда, куда тег не ставится. Не рассчитывайте, что guardrail будет оценивать следующие части запроса:
417
418* **Содержимое, которое шлюз не помечает**: сообщения, не охваченные вашим значением `input_tagging`, определения инструментов, входные данные вызовов инструментов, изображения и PDF, среди прочего. Если не задано `all_messages_and_system`, системный промпт тоже не помечается.
419* **Результаты инструментов**: они содержат то, что возвращают инструменты Claude, например содержимое файлов и веб-страницы. В тестах Anthropic фильтр слов не оценивал их ни с тегами, ни без них.
420
421Если ваш аккаунт или организация AWS принудительно применяет guardrail, о том, как такой guardrail обрабатывает входные теги, см. [документацию Amazon Bedrock](https://docs.aws.amazon.com/bedrock/latest/userguide/guardrails-enforcements.html).
422
423##### Запись в лог сработавшего фильтра guardrail
424
425Чтобы выяснить, какой фильтр guardrail Amazon Bedrock заблокировал запрос разработчика, задайте `guardrail_trace: true` для вышестоящего сервера Bedrock, перезапустите шлюз и попросите разработчика отправить запрос снова. Затем найдите событие `guardrail.trace` этого запроса в [журнале аудита](https://code.claude.com/docs/ru/claude-apps-gateway-deploy.md#logs). Требует Claude Code v2.1.314 или новее на сервере шлюза. Более ранний шлюз отказывается запускаться, обнаружив `guardrail_trace`.
426
427```yaml theme={null}
428upstreams:
429 - provider: bedrock
430 region: us-east-1
431 auth: {}
432 guardrail:
433 id: gr-abc123
434 version: "1"
435 guardrail_trace: true # default false; beside guardrail, not inside it
436```
437
438Шлюз записывает событие `guardrail.trace` без совпавшего текста, когда сработал фильтр или действие guardrail равно `INTERVENED`. Ищите события разработчика по `email` или `sub`. Один запрос с потоковой передачей может породить несколько событий, и у одного из них список `filters` может быть пустым, поэтому читайте все события с одинаковым `request_id`:
439
440| Поле | Что содержит |
441| - | - |
442| `request_id` | Идентификатор запроса |
443| `sub`, `email` | Идентификатор пользователя и email разработчика |
444| `upstream` | Вышестоящий сервер, от которого пришёл ответ |
445| `action` | Действие guardrail, например `INTERVENED` |
446| `filters` | Сработавшие фильтры. Список пуст, если AWS не присылает подробностей о фильтрах |
447| `filters[].side` | `input` или `output` |
448| `filters[].guardrail` | Идентификатор guardrail |
449| `filters[].policy` | Политика и список Bedrock, например `contentPolicy.filters` или `sensitiveInformationPolicy.piiEntities` |
450| Другие поля `filters[]` | Запись также может содержать такие поля, как `action`, `name`, `type`, `confidence`, `filterStrength`, `score` и `threshold` |
451
452Событие не содержит текста, совпавшего с фильтром, включая поле `match` трассировки Bedrock. Разработчики не получают данные трассировки Bedrock, поскольку шлюз удаляет их из каждого ответа, потокового или нет.
453
454Если клиент отправляет поле `amazon-bedrock-*` в теле запроса `/v1/messages`, шлюз отвечает 400 на вышестоящем сервере, для которого задан `guardrail_trace`.
455
376##### Bedrock в другом аккаунте AWS456##### Bedrock в другом аккаунте AWS
377 457
378Если задать `assume_role` для upstream Bedrock, шлюз использует собственную идентичность AWS только для вызова `sts:AssumeRole` на указанную вами роль, которая может находиться в другом аккаунте AWS, чем шлюз. Каждый запрос Bedrock от этого upstream подписывается одночасовыми учётными данными, которые возвращает STS, поэтому ни один долгоживущий ключ доступа не пересекает границы аккаунтов.458Если задать `assume_role` для upstream Bedrock, шлюз использует собственную идентичность AWS только для вызова `sts:AssumeRole` на указанную вами роль, которая может находиться в другом аккаунте AWS, чем шлюз. Каждый запрос Bedrock от этого upstream подписывается одночасовыми учётными данными, которые возвращает STS, поэтому ни один долгоживущий ключ доступа не пересекает границы аккаунтов.
384 - name: bedrock-isolated464 - name: bedrock-isolated
385 provider: bedrock465 provider: bedrock
386 region: us-east-1466 region: us-east-1
387 auth: {} # собственная роль шлюза: она только вызывает STS467 auth: {} # the gateway's own role: it only calls STS
388 assume_role:468 assume_role:
389 role_arn: arn:aws:iam::222222222222:role/claude-gateway-bedrock469 role_arn: arn:aws:iam::222222222222:role/claude-gateway-bedrock
390 # external_id: ${BEDROCK_ROLE_EXTERNAL_ID} # если политика доверия роли его требует470 # external_id: ${BEDROCK_ROLE_EXTERNAL_ID} # when the role's trust policy requires one
391```471```
392 472
393Блок `assume_role` принимает три ключа:473Блок `assume_role` принимает три ключа:
415* Если STS отклоняет вызов или недоступен, шлюз не отправляет запрос с собственными учётными данными upstream. Он записывает в лог ошибку STS с указанием, что проверить, затем пробует следующий указанный вами upstream. Что получает клиент, если ни один upstream не справился, описано в разделе [Сообщения об ошибках upstream](#upstream-error-messages). Следующий upstream без `assume_role` обслужит запрос со своими учётными данными, поэтому указывайте такой upstream, только если вам нужно именно это.495* Если STS отклоняет вызов или недоступен, шлюз не отправляет запрос с собственными учётными данными upstream. Он записывает в лог ошибку STS с указанием, что проверить, затем пробует следующий указанный вами upstream. Что получает клиент, если ни один upstream не справился, описано в разделе [Сообщения об ошибках upstream](#upstream-error-messages). Следующий upstream без `assume_role` обслужит запрос со своими учётными данными, поэтому указывайте такой upstream, только если вам нужно именно это.
416* Шлюз вызывает региональный эндпоинт STS `sts.<region>.amazonaws.com`, который должен быть доступен из его сети. Для эндпоинта FIPS задайте `AWS_USE_FIPS_ENDPOINT=true` в окружении шлюза, а не `use_fips_endpoint` в файле конфигурации AWS.496* Шлюз вызывает региональный эндпоинт STS `sts.<region>.amazonaws.com`, который должен быть доступен из его сети. Для эндпоинта FIPS задайте `AWS_USE_FIPS_ENDPOINT=true` в окружении шлюза, а не `use_fips_endpoint` в файле конфигурации AWS.
417* `assume_role` применяется только к `provider: bedrock` и требует исходных учётных данных SigV4: шлюз отказывается запускаться, если он задан вместе с `aws_bearer_token`.497* `assume_role` применяется только к `provider: bedrock` и требует исходных учётных данных SigV4: шлюз отказывается запускаться, если он задан вместе с `aws_bearer_token`.
418* Этот upstream может использовать каждый разработчик, допущенный шлюзом; какие разработчики могут использовать какие модели, определяет [`managed`](#managed). Чтобы модель, обслуживаемая через роль, не обслуживалась также из другого аккаунта, дайте ей пользовательский id, карта `upstream_model` которого содержит только имя этого upstream. Для такого id шлюз пропускает все остальные upstream, поэтому ни запрос, ни подсчёт токенов для прерванного запроса не могут переключиться на другой аккаунт. Запрос к встроенному имени модели всё равно может [дойти до этого upstream](#multiple-upstreams), и шлюз подпишет его той же ролью. Указывайте этот upstream последним, если только его аккаунт не должен обслуживать и эти модели.498* Без [списка `groups`](#send-each-team-to-its-own-upstream) этот вышестоящий сервер может использовать каждый разработчик, которого допускает шлюз. Чтобы ограничить, какие модели может использовать разработчик, задайте `availableModels` в политике [`managed`](#managed).
499* Чтобы модель, обслуживаемая через роль, не обслуживалась также из другого аккаунта, дайте ей пользовательский id, карта `upstream_model` которого содержит только имя этого вышестоящего сервера. Для такого id шлюз пропускает все остальные вышестоящие серверы, поэтому ни сам запрос, ни подсчёт токенов для прерванного запроса не могут переключиться на другой аккаунт.
500* Запрос встроенного имени модели всё равно может [дойти до этого вышестоящего сервера](#multiple-upstreams), и шлюз подписывает его той же ролью. Указывайте этот вышестоящий сервер последним, если его аккаунт не должен также обслуживать эти модели.
419 501
420В этом примере одной модели дан пользовательский id, который обслуживает только изолированный upstream:502В этом примере одной модели дан пользовательский id, который обслуживает только изолированный upstream:
421 503
422```yaml theme={null}504```yaml theme={null}
423models:505models:
424 - id: restricted-claude-opus-4-8 # пользовательский id, а не встроенное имя модели506 - id: restricted-claude-opus-4-8 # a custom id, not a built-in model name
425 upstream_model:507 upstream_model:
426 bedrock-isolated: us.anthropic.claude-opus-4-8 # единственный upstream, который её обслуживает508 bedrock-isolated: us.anthropic.claude-opus-4-8 # the only upstream that serves it
427```509```
428 510
429##### Учёт затрат AWS по разработчикам511##### Учёт затрат AWS по разработчикам
436upstreams:518upstreams:
437 - provider: bedrock519 - provider: bedrock
438 region: us-east-1520 region: us-east-1
439 auth: {} # собственная роль шлюза: она только вызывает STS521 auth: {} # the gateway's own role: it only calls STS
440 assume_role:522 assume_role:
441 role_arn: arn:aws:iam::123456789012:role/claude-gateway-bedrock-user523 role_arn: arn:aws:iam::123456789012:role/claude-gateway-bedrock-user
442 session_name: email # или sub524 session_name: email # or sub
443```525```
444 526
445`session_name` выбирает, какой проверенный claim становится AWS `RoleSessionName`: `email` или `sub`. Любой символ, кроме латинских букв ASCII, цифр и `_+,.@-`, шлюз записывает как `=XX` в hex для каждого байта UTF-8, а результат длиннее 64 символов сокращает до префикса и хеша, поэтому имя сессии каждого разработчика остаётся допустимым и уникальным. Запрос от разработчика, токен которого не содержит нужного claim, не отправляется через этот upstream, а в логе оператора появляется совет переключиться на `sub` или задать [`oidc.email_claim`](#oidc).527`session_name` выбирает, какой проверенный claim становится AWS `RoleSessionName`: `email` или `sub`. Любой символ, кроме латинских букв ASCII, цифр и `_+,.@-`, шлюз записывает как `=XX` в hex для каждого байта UTF-8, а результат длиннее 64 символов сокращает до префикса и хеша, поэтому имя сессии каждого разработчика остаётся допустимым и уникальным. Запрос от разработчика, токен которого не содержит нужного claim, не отправляется через этот upstream, а в логе оператора появляется совет переключиться на `sub` или задать [`oidc.email_claim`](#oidc).
460upstreams:542upstreams:
461 - provider: mantle543 - provider: mantle
462 region: us-east-1544 region: us-east-1
463 models: [claude-opus-4-7, claude-haiku-4-5] # обязательно545 models: [claude-opus-4-7, claude-haiku-4-5] # required
464 auth: {} # цепочка учётных данных AWS по умолчанию546 auth: {} # AWS default credential chain
465 - provider: bedrock547 - provider: bedrock
466 region: us-east-1548 region: us-east-1
467 auth: {}549 auth: {}
499 region: us-east-1581 region: us-east-1
500 workspace_id: wrkspc_...582 workspace_id: wrkspc_...
501 auth:583 auth:
502 api_key: ${ANTHROPIC_AWS_API_KEY} # отправляется как x-api-key584 api_key: ${ANTHROPIC_AWS_API_KEY} # sent as x-api-key
503 # ИЛИ SigV4 через цепочку учётных данных AWS по умолчанию:585 # OR SigV4 via the AWS default credential chain:
504 # auth: {}586 # auth: {}
505 # ИЛИ явные учётные данные SigV4:587 # OR explicit SigV4 credentials:
506 # auth:588 # auth:
507 # aws_access_key_id: ${AWS_ACCESS_KEY_ID}589 # aws_access_key_id: ${AWS_ACCESS_KEY_ID}
508 # aws_secret_access_key: ${AWS_SECRET_ACCESS_KEY}590 # aws_secret_access_key: ${AWS_SECRET_ACCESS_KEY}
509 # Переопределите выведенный эндпоинт:591 # Override the derived endpoint:
510 # base_url: https://aws-external-anthropic.us-east-1.api.aws592 # base_url: https://aws-external-anthropic.us-east-1.api.aws
511```593```
512 594
531 - provider: vertex613 - provider: vertex
532 region: us-east5614 region: us-east5
533 project_id: example-prod615 project_id: example-prod
534 auth: {} # предпочтительно: Application Default Credentials616 auth: {} # preferred: Application Default Credentials
535 # ИЛИ файл ключа сервисного аккаунта:617 # OR a service account key file:
536 # auth: { service_account_json: /secrets/sa.json }618 # auth: { service_account_json: /secrets/sa.json }
537 # Переопределите эндпоинт aiplatform для Private Service Connect:619 # Override the aiplatform endpoint for Private Service Connect:
538 # base_url: https://us-east5-aiplatform.p.googleapis.com620 # base_url: https://us-east5-aiplatform.p.googleapis.com
539```621```
540 622
558upstreams:640upstreams:
559 - provider: foundry641 - provider: foundry
560 resource: example-foundry # https://example-foundry.services.ai.azure.com642 resource: example-foundry # https://example-foundry.services.ai.azure.com
561 auth: { use_azure_ad: true } # предпочтительно: DefaultAzureCredential / Managed Identity643 auth: { use_azure_ad: true } # preferred: DefaultAzureCredential / Managed Identity
562 # ИЛИ API-ключ:644 # OR an API key:
563 # auth:645 # auth:
564 # api_key: ${FOUNDRY_API_KEY}646 # api_key: ${FOUNDRY_API_KEY}
565```647```
627 709
628`429` означает нехватку мощности конкретного upstream, поэтому при исчерпании выделенной пропускной способности (PT) запросы переключаются на оплату по запросу. Если вы задали [`forward_user_identity: true`](#per-user-identity-headers-for-a-proxy-you-run) для upstream, `429` на запрос, содержащий email разработчика, считается отказом для отдельного пользователя и не приводит к переключению.710`429` означает нехватку мощности конкретного upstream, поэтому при исчерпании выделенной пропускной способности (PT) запросы переключаются на оплату по запросу. Если вы задали [`forward_user_identity: true`](#per-user-identity-headers-for-a-proxy-you-run) для upstream, `429` на запрос, содержащий email разработчика, считается отказом для отдельного пользователя и не приводит к переключению.
629 711
630Каждый запрос начинается с первого upstream. Запрос доходит до следующего upstream, только если все предыдущие завершились ошибкой или не обслуживают запрошенную модель.712Запрос переходит к следующему вышестоящему провайдеру только в следующих случаях:
713
714* Вышестоящий провайдер вернул ошибку
715* Вышестоящий провайдер не обслуживает запрошенную модель
716* У вышестоящего провайдера есть [список `groups`](#send-each-team-to-its-own-upstream), в который разработчик не входит
631 717
632Шлюз не запоминает неудачные upstream, поэтому, пока upstream недоступен, каждый доходящий до него запрос всё равно пробует его и ждёт ошибки, прежде чем двигаться дальше.718Шлюз не запоминает неудачные upstream, поэтому, пока upstream недоступен, каждый доходящий до него запрос всё равно пробует его и ждёт ошибки, прежде чем двигаться дальше.
633 719
680| - | - |766| - | - |
681| Разные регионы | По одному upstream Amazon Bedrock на регион, каждый со своим `region:`. С [`auto_include_builtin_models: true`](#models) межрегиональные профили инференса маршрутизируются автоматически; для развёртываний, закреплённых за регионом, используйте блок `models:`. |767| Разные регионы | По одному upstream Amazon Bedrock на регион, каждый со своим `region:`. С [`auto_include_builtin_models: true`](#models) межрегиональные профили инференса маршрутизируются автоматически; для развёртываний, закреплённых за регионом, используйте блок `models:`. |
682| Разные аккаунты | По одному upstream Amazon Bedrock на аккаунт. Цепочка по умолчанию (`auth: {}`) использует идентичность пода; для второго аккаунта добавьте [`assume_role`](#bedrock-in-another-aws-account), чтобы обращаться к нему с короткоживущими учётными данными, или задайте в `auth:` явные учётные данные или Bearer-токен. |768| Разные аккаунты | По одному upstream Amazon Bedrock на аккаунт. Цепочка по умолчанию (`auth: {}`) использует идентичность пода; для второго аккаунта добавьте [`assume_role`](#bedrock-in-another-aws-account), чтобы обращаться к нему с короткоживущими учётными данными, или задайте в `auth:` явные учётные данные или Bearer-токен. |
769| Разные команды | Задайте для вышестоящего провайдера каждой команды список `groups`, чтобы к нему обращались только разработчики из этих групп IdP. См. [Направление каждой команды к своему вышестоящему провайдеру](#send-each-team-to-its-own-upstream). |
683| Выделенная пропускная способность | Сопоставьте модель с ARN выделенной пропускной способности в `models:` для имени этого upstream. Остальные upstream сохраняют ID для оплаты по запросу, поэтому мощность PT исчерпывается до переключения. |770| Выделенная пропускная способность | Сопоставьте модель с ARN выделенной пропускной способности в `models:` для имени этого upstream. Остальные upstream сохраняют ID для оплаты по запросу, поэтому мощность PT исчерпывается до переключения. |
684| Эндпоинты VPC / FIPS | Задайте в `base_url:` upstream URL вашего VPC-эндпоинта или эндпоинта FIPS |771| Эндпоинты VPC / FIPS | Задайте в `base_url:` upstream URL вашего VPC-эндпоинта или эндпоинта FIPS |
685| Маршрутизация по моделям | Только пользовательский `id` модели, то есть не встроенной модели Claude, пропускает upstream, отсутствующие в его карте `upstream_model:`. Upstream `mantle` пробуется только для моделей, перечисленных в его [поле `models`](#amazon-bedrock-mantle-endpoint). На всех остальных upstream шлюз пробует встроенные модели по порядку и использует ID поставщика по умолчанию, если в карте нет записи, поэтому для встроенных моделей карта меняет то, какой ID получает upstream, а не то, пробуется ли он; upstream, отклонивший ID, подчиняется тем же [правилам переключения](#upstreams), что и при любой другой ошибке upstream. |772| Маршрутизация по модели | Пользовательский `id` модели, то есть не встроенной модели Claude, пропускает вышестоящих провайдеров, отсутствующих в его карте `upstream_model:`. Вышестоящий провайдер со списком `models`, который обязателен для [провайдера `mantle`](#amazon-bedrock-mantle-endpoint), используется только для этих моделей. |
773| Маршрутизация встроенных моделей | Для вышестоящего провайдера без списков `models` и `groups` шлюз перебирает встроенные модели по порядку и использует ID провайдера по умолчанию, если в карте `upstream_model:` нет записи. Для встроенной модели, у которой у провайдера есть ID по умолчанию, карта определяет, какой ID получит вышестоящий провайдер, а не то, будет ли он использован. Вышестоящий провайдер, отклонивший ID, подчиняется тем же [правилам переключения](#upstreams), что и при любой другой ошибке. |
686 774
687Переключение между облачными поставщиками или на Anthropic API напрямую меняет соглашение, географию и другие условия, которым подчиняется запрос.775Переключение между облачными поставщиками или на Anthropic API напрямую меняет соглашение, географию и другие условия, которым подчиняется запрос.
688 776
689CLI применяет одинаковые ограничения функций к шлюзам независимо от того, какой upstream обслуживает конкретный запрос, поэтому по умолчанию переключение не приводит к отправке поля тела, которое upstream отклонил бы. Если вы задаёте в политике [одночасовой TTL кэша](#one-hour-prompt-cache), он отправляется каждому upstream в списке, поэтому задавайте его, только если все они его принимают.777CLI применяет одинаковые ограничения функций к шлюзам независимо от того, какой upstream обслуживает конкретный запрос, поэтому по умолчанию переключение не приводит к отправке поля тела, которое upstream отклонил бы. Если вы задаёте в политике [одночасовой TTL кэша](#one-hour-prompt-cache), он отправляется каждому upstream в списке, поэтому задавайте его, только если все они его принимают.
690 778
779#### Направление каждой команды к своему вышестоящему провайдеру
780
781Чтобы направлять запросы каждой команды в её собственный аккаунт AWS или проект Google Cloud, укажите по одному вышестоящему провайдеру на команду и задайте каждому список `groups`. К такому провайдеру обращаются только разработчики из перечисленных групп IdP — как при первой попытке, так и при [переключении](#multiple-upstreams). `groups` поддерживается всеми провайдерами. Требуется Claude Code v2.1.314 или новее на сервере шлюза.
782
783В этом примере группы `payments-eng` и `search-eng` получают по аккаунту AWS, а также добавлен вышестоящий провайдер без списка `groups`, доступный всем разработчикам:
784
785```yaml theme={null}
786upstreams:
787 - name: bedrock-payments
788 provider: bedrock
789 region: us-east-1
790 auth: {}
791 assume_role:
792 role_arn: arn:aws:iam::111111111111:role/claude-gateway-bedrock
793 groups: [payments-eng]
794 - name: bedrock-search
795 provider: bedrock
796 region: us-east-1
797 auth: {}
798 assume_role:
799 role_arn: arn:aws:iam::222222222222:role/claude-gateway-bedrock
800 groups: [search-eng]
801 - name: bedrock-shared # no groups: open to everyone, so listed last
802 provider: bedrock
803 region: us-east-1
804 auth: {}
805```
806
807При такой конфигурации запросы каждого разработчика начинаются с первого вышестоящего провайдера в его строке и при переключении переходят к следующему:
808
809| Группы разработчика | Вышестоящие провайдеры по порядку |
810| - | - |
811| `payments-eng` | `bedrock-payments`, затем `bedrock-shared` |
812| `search-eng` | `bedrock-search`, затем `bedrock-shared` |
813| `payments-eng` и `search-eng` | `bedrock-payments`, затем `bedrock-search`, затем `bedrock-shared` |
814| Ни одной | `bedrock-shared` |
815
816Когда вышестоящий провайдер команды отклоняет запрошенную модель с кодом `403`, шлюз пробует следующего провайдера в строке этой команды, который обслуживает модель. Чтобы закрепить команду за одним провайдером, задайте список `groups` каждому вышестоящему провайдеру и убедитесь, что ни один другой провайдер не перечисляет группу, в которую входят разработчики команды. Тогда у этой команды не будет переключения, а запросы разработчиков, не входящих ни в одну из перечисленных групп, [завершатся ошибкой `400`](#what-happens-when-a-developer-is-in-no-listed-group).
817
818Чтобы каждый разработчик попадал к нужному вышестоящему провайдеру, записывайте точно совпадающие значения и размещайте открытых провайдеров последними:
819
820* **Значения**: записывайте каждую группу точно так, как ваш IdP передаёт её в [claim групп](#oidc), который также читает [`match.groups`](#managed). Шлюз отказывается запускаться, если находит пустой список или пустое значение. Он не сверяет значения с вашим IdP, поэтому значение, которому никто не соответствует, не вызывает предупреждения.
821* **Порядок**: размещайте вышестоящего провайдера без списка `groups` последним. Он обслуживает всех, поэтому, если указать его раньше, он будет перехватывать запросы команды до её собственного провайдера.
822
823> [!WARNING]
824>
825> Шлюз версии ниже v2.1.314 отказывается запускаться, если находит `groups`, поэтому обновите все реплики, прежде чем добавлять этот параметр.
826>
827> Перед откатом на предыдущую версию удалите каждого вышестоящего провайдера со списком `groups`, а также все ключи `upstream_model` и переопределения цен, ссылающиеся на него, и оставьте хотя бы одного вышестоящего провайдера. Если удалить только ключ `groups`, этот провайдер станет доступен всем разработчикам. Ключ или переопределение, которые всё ещё ссылаются на удалённого провайдера, не дают шлюзу запуститься с ошибкой `references unknown upstream`.
828
829##### Что происходит, если разработчик не входит ни в одну из перечисленных групп
830
831Если у каждого вышестоящего провайдера есть список `groups`, разработчик, не входящий ни в одну из этих групп, видит следующую ошибку, и шлюз не обращается ни к одному провайдеру:
832
833```text theme={null}
834API Error: 400 you aren't in a group that can use this gateway. Ask your administrator to add you to one
835```
836
837Добавьте разработчика в одну из перечисленных групп в вашем IdP или добавьте вышестоящего провайдера без списка `groups`.
838
839Шлюз заново считывает группы разработчика при каждом обновлении токена. Если ваш IdP не передаёт группы при обновлении, у разработчика их не оказывается:
840
841* **Задан [`oidc.allowed_groups`](#oidc)**: шлюз отклоняет обновление, и сессия завершается
842* **Иначе, если у какого-либо вышестоящего провайдера нет списка `groups`**: запросы разработчика переходят к нему
843* **Иначе, если у каждого вышестоящего провайдера есть список `groups`**: запросы разработчика завершаются этой ошибкой
844
845Если эндпоинт userinfo вашего IdP возвращает claim групп, а `oidc.google_groups` не задан, установите [`oidc.userinfo_fallback`](#oidc) в `true`, чтобы получать группы оттуда.
846
691## Необязательные разделы847## Необязательные разделы
692 848
693### `admin`849### `admin`
782 938
783#### Отправка тарифов клиентам, вошедшим в систему939#### Отправка тарифов клиентам, вошедшим в систему
784 940
785С v2.1.268 или новее на сервере шлюза шлюз также помещает тарифы из `pricing` в обслуживаемые им политики [`managed`](#managed) в виде управляемой настройки [`modelPricing`](https://code.claude.com/docs/ru/settings-reference#modelpricing). Разработчики, подпадающие под политику, видят тарифы `pricing` первого upstream, обслуживающего каждый ID модели, в `/usage`, строке состояния и OpenTelemetry. Разработчик, не подпадающий ни под одну политику, не получает управляемых настроек, поэтому его цифры остаются по прейскуранту. Клиенты применяют эту настройку в Claude Code v2.1.242 или новее.941С v2.1.268 или новее на сервере шлюза шлюз также помещает ставки из `pricing` в обслуживаемые им политики [`managed`](#managed) в виде управляемой настройки [`modelPricing`](https://code.claude.com/docs/ru/settings-reference#modelpricing).
942
943Разработчики, подпадающие под политику, затем видят ставки `pricing` в `/usage`, строке состояния и OpenTelemetry. Разработчик, не подпадающий ни под одну политику, не получает управляемых настроек, поэтому его показатели остаются по прейскурантной цене. Клиенты применяют эту настройку в Claude Code v2.1.242 или новее.
786 944
787* Что добавляет шлюз: если блок `cli` политики ещё не задаёт `modelPricing`, шлюз добавляет `multiplier` и, для каждого ID модели, который может запросить клиент, строку переопределения первого upstream, обслуживающего этот ID. Тариф, который взимает только резервный upstream, остаётся на шлюзе.945* Что добавляет шлюз: если блок `cli` политики ещё не задаёт `modelPricing`, шлюз добавляет `multiplier` и, для каждого ID модели, который может запросить клиент, строку переопределения первого upstream, обслуживающего этот ID. Тариф, который взимает только резервный upstream, остаётся на шлюзе.
946* Upstream со [списком `groups`](#send-each-team-to-its-own-upstream): если такой upstream — первый, обслуживающий ID модели, шлюз не добавляет строку для этого ID. Тогда разработчики видят собственную ставку Claude Code для этого ID — стандартную ставку модели, если Claude Code распознаёт ID, — умноженную на `multiplier`.
788* Исключение отдельной политики: установите `modelPricing` в `{}` в блоке `cli` этой политики, и её разработчики останутся на прейскурантных ценах.947* Исключение отдельной политики: установите `modelPricing` в `{}` в блоке `cli` этой политики, и её разработчики останутся на прейскурантных ценах.
789* Сохранение собственных тарифов политики: политика, блок `cli` которой задаёт `modelPricing` с собственными `multiplier` или `overrides`, сохраняет этот `modelPricing` целиком, и шлюз не добавляет в него свои тарифы.948* Сохранение собственных тарифов политики: политика, блок `cli` которой задаёт `modelPricing` с собственными `multiplier` или `overrides`, сохраняет этот `modelPricing` целиком, и шлюз не добавляет в него свои тарифы.
790 949
808 967
809### `managed`968### `managed`
810 969
811Блок `managed` определяет политики доступа на основе ролей, привязанные к группам IdP или домену email. Политики вычисляются по порядку; выбирается первое совпадение, которое затем объединяется с базовым универсальным `match: {}`. Они отдаются каждому пользователю на `GET /managed/settings` с кэшированием ETag/304.970Блок `managed` определяет политики доступа на основе ролей, привязанные к группам IdP или домену email. Политики оцениваются по порядку; по умолчанию выбирается первое совпадение, которое затем объединяется с базовой политикой `match: {}`, охватывающей всех. Пользователь, подпадающий под две ролевые политики, получает только первую, поэтому правила запрета второй политики не применяются, если вы не [примените все подходящие политики](#apply-every-matching-policy). Политики обслуживаются для каждого пользователя по адресу `GET /managed/settings` с кэшированием ETag/304.
812 971
813```yaml theme={null}972```yaml theme={null}
814managed:973managed:
849 1008
850Аутентифицированный пользователь, не подпадающий ни под одну политику, получает значения шлюза по умолчанию, то есть все модели из каталога и никаких управляемых настроек. Добавьте последней универсальную политику `match: {}`, если вам нужна гарантированная политика по умолчанию.1009Аутентифицированный пользователь, не подпадающий ни под одну политику, получает значения шлюза по умолчанию, то есть все модели из каталога и никаких управляемых настроек. Добавьте последней универсальную политику `match: {}`, если вам нужна гарантированная политика по умолчанию.
851 1010
1011Размещайте правила запрета на уровне организации в политике `match: {}`, потому что правила групповой политики применяются только пока токен пользователя содержит эту группу.
1012
852> [!NOTE]1013> [!NOTE]
853>1014>
854> Шлюз не хранит собственного каталога пользователей. Он авторизует каждый запрос по токену IdP пользователя, считывая членство в группах из claim `groups` токена и вычисляя политики по нему. Нет списка пользователей для перечисления и нет учётных записей для предварительного создания, а значит, нет и эндпоинта SCIM, потому что SCIM нечего синхронизировать.1015> Шлюз не хранит собственного каталога пользователей. Он авторизует каждый запрос по токену IdP пользователя, считывая членство в группах из claim `groups` токена и вычисляя политики по нему. Нет списка пользователей для перечисления и нет учётных записей для предварительного создания, а значит, нет и эндпоинта SCIM, потому что SCIM нечего синхронизировать.
862>1023>
863> Claude Desktop следует [собственному расписанию](#when-a-policy-change-reaches-claude-desktop).1024> Claude Desktop следует [собственному расписанию](#when-a-policy-change-reaches-claude-desktop).
864 1025
1026#### Применение всех подходящих политик
1027
1028Пользователь, подпадающий под несколько ролевых политик, получает только первую, если вы не зададите `policy_mode: layered` рядом с `policies`. С `layered` применяется каждая политика, под которую подпадает пользователь, вплоть до первой политики `match: {}`.
1029
1030`policy_mode` требует Claude Code v2.1.316 или новее на сервере шлюза. Шлюз версии без поддержки этого ключа отказывается запускаться, обнаружив его. Обновите все реплики, прежде чем добавлять ключ, и удалите ключ перед откатом на более раннюю версию. В этом примере одна группа теряет `WebFetch`, а другая получает Opus:
1031
1032```yaml theme={null}
1033managed:
1034 policy_mode: layered
1035 policies:
1036 - match: { groups: [no-web] }
1037 cli:
1038 permissions: { deny: ["WebFetch"] }
1039 - match: { groups: [opus-users] }
1040 cli:
1041 availableModels: [opus, sonnet]
1042 - match: {}
1043 cli:
1044 availableModels: [sonnet]
1045 enforceAvailableModels: true
1046```
1047
1048В таблице показано, что получает пользователь, состоящий и в `no-web`, и в `opus-users`, при режиме по умолчанию, `first_match`, и при `layered`.
1049
1050| Настройка | `first_match` | `layered` |
1051| - | - | - |
1052| `availableModels` | `sonnet` | `opus`, `sonnet` |
1053| `enforceAvailableModels` | `true` | `true` |
1054| `permissions.deny` | `WebFetch` | `WebFetch` |
1055
1056Шлюз объединяет каждую подходящую политику с политиками, указанными ниже неё, по тем же [правилам объединения](#managed), что и для базового слоя:
1057
1058* **Списки разрешённых, одиночные значения и блоки, такие как `sandbox`**: каждый берётся целиком из первой по порядку подходящей политики, которая его задаёт, поэтому списки `availableModels` двух групп не суммируются.
1059* **Списки запрещённых и массивы хуков**: суммируются по всем подходящим политикам, поэтому пользователь в двух группах получает правила запрета обеих групп.
1060* **`env`, `modelOverrides` и `skillOverrides`**: записи объединяются по имени, и значение для имени берётся из первой по порядку подходящей политики, которая его задаёт.
1061* **Ключи `desktop`**: объединяются по [правилам для базового блока `desktop`](#how-a-role-policy-inherits-the-base-desktop-block).
1062
1063> [!WARNING]
1064>
1065> В сумме политики могут дать более мягкие правила, чем любая из них по отдельности. Например, политика `match: {}` задаёт `sandbox.enabled: true`, политика одной группы задаёт `permissions.allow: ["Bash"]`, а политика другой — `sandbox.enabled: false`. Пользователь в обеих группах получает разрешённый `Bash` с выключенной песочницей. В таком случае укажите первой политику, разрешающую `Bash`, и скопируйте в неё весь блок `sandbox` политики `match: {}`.
1066
1067С `layered` шлюз отказывается запускаться при некоторых настройках, в том числе таких:
1068
1069* **Шаблон с `!`**: [отрицание `!`](https://code.claude.com/docs/ru/permissions#special-characters-and-negation) в правиле `Read` или `Edit` в списке `permissions.deny` или `permissions.ask` любой политики, включая политику `match: {}`
1070* **Ограничение хуков вне политики, охватывающей всех**: `disableAllHooks`, `allowedHttpHookUrls` или `httpHookAllowedEnvVars` в любой политике, кроме `match: {}`
1071
865#### Запуск сессий на модели, разрешённой политикой1072#### Запуск сессий на модели, разрешённой политикой
866 1073
867Если `availableModels` не включает модель Claude Code по умолчанию, сессии получают ответы `400`, пока разработчик не выберет модель из списка, например с помощью `/model`. В сессиях через шлюз моделью по умолчанию является модель Opus, на которую указывает псевдоним `opus`, и `availableModels` сам по себе её не меняет.1074Если `availableModels` не включает модель Claude Code по умолчанию, сессии получают ответы `400`, пока разработчик не выберет модель из списка, например с помощью `/model`. В сессиях через шлюз моделью по умолчанию является модель Opus, на которую указывает псевдоним `opus`, и `availableModels` сам по себе её не меняет.