Сначала спланируйте сеть для шлюза. При входе Claude Code отказывается подключаться к шлюзу Claude apps, имя хоста которого разрешается в публичный IP-адрес, даже если этот адрес недоступен из интернета.Шлюз Claude apps может отправлять настройки на машины пользователей, включая хуки, которые запускают shell-команды. Эта проверка помогает не допустить, чтобы пользователи случайно вошли в вредоносный шлюз в публичном интернете. Держите и свой собственный шлюз вне интернета.Выберите адрес шлюза до того, как выбирать, где он будет работать. Обычно это частный адрес, к которому пользователи обращаются во внутренней сети или через VPN. Если ваша внутренняя сеть использует публичные диапазоны IPv4, вы можете указать один диапазон, в который входят и шлюз, и машины ваших пользователей. Claude Code воспринимает такое совпадение как признак того, что шлюз находится в вашей внутренней сети. См. Выбор адреса для шлюза. Если ни один из вариантов не подходит для вашей сети, обратитесь к вашей команде по работе с клиентами Anthropic.
gateway.yaml, который шлюз читает при загрузке, см. Справочник по конфигурации.
Развертывание в производстве следует четырем этапам по порядку, и разделы ниже соответствуют им. Первые два — это места, где вы делаете выбор; вторые два — справочный материал, который следует консультировать после запуска.
- Настройка вашего поставщика идентификации: зарегистрируйте клиента OAuth и проверьте примечания для каждого IdP для Okta, Entra и Google
- Развертывание шлюза: создайте образ контейнера с закрепленной версией и запустите его на Kubernetes, Cloud Run или вашей собственной платформе. Этот раздел также охватывает решения по стоимости, обходу, нескольким шлюзам и бессерверным вычислениям
- Настройка операций: журналы, зонды здоровья, поведение при сбое, ротация секретов и обновления. Справочник для подключения мониторинга и runbooks
- Проверка позиции безопасности: какие данные куда передаются, модель угроз и ответы на вопросы соответствия. Справочник для проверки безопасности
Настройка поставщика удостоверений
Зарегистрируйте конфиденциальное веб-приложение OAuth/OpenID Connect (OIDC) с одним URI перенаправления,https://<gateway>/oauth/callback, и назначьте его пользователям или группам, которые должны иметь доступ к шлюзу. Шлюз аутентифицируется в IdP с помощью секрета клиента из регистрации или с помощью сертификата, который вы загружаете в регистрацию, если ваш IdP вместо этого использует учётные данные на основе сертификата.
Работает любой OIDC-совместимый IdP: Okta, Microsoft Entra ID, Google Workspace, Keycloak, Dex, PingFederate и другие. IdP должен соответствовать трем требованиям:
- Обслуживает
/.well-known/openid-configurationпо HTTPS в production; шлюз принимаетhttp://издателя, и издатель loopback дополнительно требуетCLAUDE_GATEWAY_ALLOW_LOOPBACK=1 - Поддерживает поток authorization-code. PKCE (Proof Key for Code Exchange) включен по умолчанию; отключите его с помощью
oidc.use_pkce: falseдля IdP, которые его не поддерживают - Возвращает
emailи опциональноgroupsв id_token или обслуживает их из конечной точки userinfo сoidc.userinfo_fallback: true
oidc.ca_cert_pem.
Несколько поставщиков обрабатывают утверждения email и group по-разному:
- Okta: сервер авторизации организации в
https://example.okta.comвозвращает тонкий id_token, который опускаетemailиgroups, поэтому установитеoidc.userinfo_fallback: trueвсякий раз, когда вы используете его какissuer. Пользовательский сервер авторизации, такой какhttps://example.okta.com/oauth2/default, который включаетemailи опциональноgroupsв id_token, выдает их напрямую и не требует fallback. Okta выдаетgroupsтолько когда областьgroupsзапрашивается вoidc.scopesи фильтр утверждения groups приложения это позволяет;userinfo_fallbackне может заполнить утверждение, которое IdP не был попрошен выдать. - Microsoft Entra ID:
issuer=https://login.microsoftonline.com/<tenant-id>/v2.0. Entra выдает Object ID групп, а не имена, поэтому используйте GUID вmanaged.policies.match.groupsили используйте App Roles для читаемых имен. Если ваш tenant выдает роли подrolesвместоgroups, установитеoidc.groups_claim: roles. - Google Workspace:
issuer=https://accounts.google.com. id_token Google не содержит groups. Чтобы использовать основанные на группахallowed_groupsилиmanaged.policiesс Google в качестве IdP, настройтеoidc.google_groups, которая ищет группы каждого пользователя через Admin SDK Directory API, используя сервисный аккаунт с делегированием на уровне домена. Без этого используйтеoidc.allowed_email_domainsдля проверки членства иmanaged.policies.match.email_domainдля назначения политики. Google также игнорирует стандартную областьoffline_access. Для refresh tokens установитеoidc.scopes: [openid, profile, email]иoidc.extra_auth_params: { access_type: offline, prompt: consent }.
Развертывание
Шлюз — это один stateless бинарный файл Linux, который координирует работу через Postgres, поэтому развёртывайте его так же, как вы развёртываете любой другой stateless сервис в вашей среде. Держите его внутри вашей сети, где ваши разработчики могут обращаться к нему по HTTPS, а он может обращаться к вашему IdP, и относитесь к нему как к любому сервису, содержащему production учётные данные. Несколько решений формируют развертывание помимо того, где оно работает:- Стоимость: нет отдельной лицензии или платы за место. Шлюз является частью бинарного файла
claude, поэтому вы платите за inference через ваше существующее обязательство, плюс вычисления, на которых он работает. - Обход: шлюз не требует, чтобы единственный маршрут к модели проходил через него. Разработчик со своими собственными учетными данными все еще может вызвать поставщика напрямую, поэтому закрытие этого пути — это решение политики сети, например блокировка выхода на
api.anthropic.comкроме как от шлюза. Блокировка этого выхода также нарушает проверку безопасности домена WebFetch, которая вызываетapi.anthropic.comс каждой машины разработчика. УстановитеskipWebFetchPreflight: trueв управляемой политике, чтобы отключить это. - Несколько шлюзов: каждый — это отдельное развертывание со своей конфигурацией, и CLI хранит доверие и учетные данные для каждого имени хоста шлюза, поэтому команды могут использовать разные шлюзы без конфликтов. Чтобы обслуживать несколько издателей OIDC, запустите отдельные экземпляры.
- Бессерверная архитектура: Cloud Run работает, если вы установите
min-instances: 1, чтобы избежать холодного обнаружения OIDC. Lambda и Cloud Functions не работают, потому что шлюз — это долгоживущий HTTP сервер.
listen.trusted_proxies на диапазоны источников прокси, чтобы шлюз читал IP клиентов из X-Forwarded-For. Шлюз соблюдает заголовок только когда TCP peer доверен. Пример Google Cloud и пример AWS содержат конкретные значения для каждой топологии. Без доверенных прокси каждый запрос выглядит как исходящий с IP прокси, что сворачивает ограничения скорости для каждого IP в один общий bucket и записывает IP прокси в события аудита.
Не перенаправляйте запросы на конечные точки авторизации устройства и токена шлюза, например с переписыванием HTTP-в-HTTPS или канонизацией хоста на ingress. Claude Code не следует перенаправлениям на эти запросы, поэтому правило ingress, которое их перенаправляет, нарушает вход и обновление токена.
Дайте прокси любой timeout неактивности, превышающий интервал keepalive шлюза, который зависит от upstream:
- На каждом upstream кроме
provider: anthropic, шлюз записывает SSEpingодин раз, когда поток был молчалив около 15 секунд. - На
provider: anthropic, шлюз пропускает ответ без изменений, включая собственные ping’и API Anthropic.
Выберите адрес для шлюза
Claude Code принимает адрес шлюза одним из двух способов:- Частный адрес: разместите шлюз за внутренним балансировщиком нагрузки или VPN с именем хоста, которое разрешается только в частные адреса, такие как RFC 1918 или CGNAT
100.64.0.0/10. Машины пользователей могут иметь любой адрес. Предварительное требование о частной сети перечисляет допустимые диапазоны. - Объявленный блок: если ваша внутренняя сеть использует публичное пространство IPv4, принадлежащее вашей организации, укажите этот блок в управляемой настройке
gatewayInternalNetworks. И шлюз, и машина пользователя должны находиться в этом блоке. См. Разрешение шлюза в публичном адресном пространстве, которым вы владеете.
Образ контейнера
Создайте свой собственный образ вокруг нативного бинарного файлаclaude из стандартного выпуска Claude Code:
- Загрузите сборку Linux для архитектуры вашего образа из закрепленного выпуска; см. Установка конкретной версии для URL загрузки.
- Проверьте его против подписанного GPG
manifest.jsonвыпуска, как описано в Целостность бинарного файла и подпись кода. - Скопируйте его в контекст сборки.
- Образ на основе glibc: единственные динамические зависимости сборки glibc — это библиотеки glibc. Образам на основе Musl нужна сборка
linux-x64-muslилиlinux-arm64-musl, единственной динамической зависимостью которой является musl. - Записываемый каталог состояния: шлюз работает как любой пользователь, но минимальные образы не имеют записываемого home. Установите
CLAUDE_CONFIG_DIRна записываемый путь, такой как/tmp/.claude. - Команда контейнера:
claude gateway --config /etc/claude/gateway.yaml, с файлом конфигурации, смонтированным только для чтения, и секретами, предоставленными как переменные окружения; шлюз слушает наlisten.port, по умолчанию8080.
Kubernetes
Запустите шлюз как Deployment, как любой stateless сервис:- Смонтируйте конфигурацию из ConfigMap и секреты из Secret; ссылайтесь на секреты в YAML через
${file:/path/to/secret}или как переменные окружения - Завершите TLS на Ingress и установите
listen.public_urlна имя хоста Ingress - Укажите зонд готовности на
GET /readyzи зонд живучести наGET /healthz
upstreams содержит детали настройки для каждой платформы. Для кросс-облачного сопряжения, такого как upstream Bedrock на GKE, установите явные учетные данные в блоке auth upstream вместо этого.
Cloud Run
Настройте сервис следующим образом:- Оставьте
listen.portна его значении по умолчанию8080, которое соответствуетPORTCloud Run по умолчанию, или установитеport: ${PORT} - Установите
public_urlна внешне доступное происхождение. Для production это обычно имя хоста внутреннего балансировщика нагрузки, потому что/loginотклоняет публичные адреса и URL*.run.appразрешается на один, поэтому URL Cloud Run один работает только дляcurlили дымового теста браузера. Исключение — сеть, где*.run.appразрешается приватно через Private Service Connect и приватную зону Cloud DNS; в этой топологии URL Cloud Run — это действительныйpublic_url. Пример Google Cloud охватывает оба. - Смонтируйте конфигурацию как том секрета
- Установите
min-instances: 1, чтобы избежать холодного обнаружения OIDC при первом запросе
Отправьте URL шлюза на машины разработчиков
Как только шлюз начнёт обслуживать, отправьтеforceLoginMethod, forceLoginGatewayUrl и parentSettingsBehavior: "merge" на каждую машину разработчика через управляемые настройки, через MDM или путём прямой записи файла managed-settings.json для каждой ОС.
Как только вы развернете ключи, Claude Code перестанет использовать оставшийся API ключ или вход claude.ai на машине, поэтому спланируйте отправку вместе с вашими инструкциями по входу. Политика администратора требует вход через Cloud шлюз описывает сообщения, которые видят разработчики.
См. где каждый механизм хранит политику для путей файлов и Управляемые параметры на стороне клиента для эквивалента Claude Desktop bootstrapUrl.
Крупные развертывания
Вход ограничен по скорости для каждого IP адреса клиента, и значения по умолчанию подходят для небольшой команды. Каждый адрес получает 30 начал входа и 10 отправок кода каждые 10 минут. Развертывание для тысяч разработчиков может достичь этих ограничений в первое утро по одной из двух причин:- Шлюз не может видеть за вашим балансировщиком нагрузки. Без
listen.trusted_proxiesкаждый разработчик выглядит как исходящий с адреса балансировщика нагрузки и делит один лимит. Шлюз логирует предупреждение в первый раз, когда он игнорирует заголовокX-Forwarded-For. Если балансировщик нагрузки должен быть указан вlisten.trusted_proxies, укажите его, прежде чем менять что-либо ещё. Если разработчики всё ещё делят один адрес, поднимитеrate_limits. - Много разработчиков делят несколько NAT или VPN адресов выхода. Они делят лимиты этих адресов даже когда
trusted_proxiesправильно установлен. Поднимитеrate_limits, чтобы соответствовать.
max, разделите разработчиков на адреса выхода, которые они делят. Оцените, сколько из них входят в один период window_seconds, который по умолчанию составляет 10 минут. Затем удвойте это, чтобы охватить повторные попытки и разработчиков, которые входят как в Claude Code, так и в Claude Desktop.
Например, 10 000 разработчиков за 4 адресами выхода входят равномерно в течение часа. Это 2 500 разработчиков на адрес и около 420 из них в каждые 10 минут, которые вы удваиваете и округляете до 1 000. Пример ниже устанавливает оба лимита на 1 000:
device_verify — это то, что останавливает кого-то от угадывания кода входа другого разработчика, поэтому поднимайте его только настолько, насколько нужна ваша оценка. Даже при этих лимитах код состоит из 8 символов из 20-символного алфавита и истекает через 10 минут, поэтому угадывание остается непрактичным; см. Устойчивость к перебору кода пользователя.
Когда ваш IdP выдает refresh токены, Claude Code молча обновляет сеансы, поэтому вы можете вернуть лимит после развертывания. Без refresh токенов разработчики входят снова каждые session.ttl_hours. Определите размер обоих лимитов и для этой стабильной скорости и оставьте их повышенными.
Когда лимит достигнут, Claude Code v2.1.274 или позже показывает The gateway is limiting sign-in attempts right now. Шлюз на v2.1.274 или позже показывает Too many attempts came from your network address на странице проверки, с параметрами для проверки. Он также записывает строку логирования sign-in refused, которая называет параметр для изменения.
Эксплуатация
Когда шлюз начинает обслуживать трафик, повседневная эксплуатация сводится к чтению его логов, проверке его работоспособности и ротации его секретов по вашему графику. В подразделах описано каждое из этих действий, а также то, что хранится в Postgres и как ведут себя обновления и откаты.Логи
Шлюз пишет два потока в stderr, оба удобны для обработки в формате JSON:-
События аудита: однострочный JSON для каждого события, значимого для безопасности. Направьте stderr в ваш агрегатор логов.
Генерируемые события включают
config.load,session.mint,session.refresh,device.authorize,device.verify,device.callback,auth.denied,access.denied,access.public_client,inference,managed.serve,desktop_bootstrap.serve,desktop_bootstrap.denied,spend.blocked,admin.denied,admin.limit.upsertиadmin.limit.delete. Поля зависят от события:- Успешные события выпуска и обновления содержат
sub,email,client_ipи результат auth.deniedиaccess.deniedсодержат причину и IP-адрес клиента, а дляauth.deniedещё и путь запроса, поскольку при этих отказах идентификатор пользователя отсутствует. Две причиныaccess.deniedменяют содержимое события:xff_unparseable: событие также содержит записьX-Forwarded-For, которую не удалось прочитатьclient_ip_unknown: событие не содержит IP-адреса клиента, поскольку у соединения не было адреса пира, а списокaccess_controlбыл задан
access.public_clientсодержит IP-адрес клиента первого запроса в рамках процесса, пришедшего с публичного адреса, когдаaccess_control.allow_cidrsпуст. Шлюз обслуживает запрос как обычно; событие сигнализирует о том, что шлюз может быть доступен из публичного интернета. Что считается публичным адресом и какой список разрешённых адресов рекомендуется, см. в справочнике поaccess_control.inferenceфиксирует, какой вышестоящий сервер обслужил запрос, и статус ответаdesktop_bootstrap.deniedфиксирует отклонённый запрос начальной загрузки Claude Desktop с указанием причины (not_configured,policy_not_opted_inилиno_policy_matched) и идентификатора пользователяguardrail.traceфиксирует, какой фильтр сработал, без совпавшего текстаadmin.deniedфиксирует отклонённую попытку аутентификации в API администратора с IP-адресом клиента, методом, путём и причиной, без предъявленного ключевого материала:invalid_key, если был предъявленx-api-key, не совпавший ни с одним настроенным ключом;bearer_rejected, если был предъявлен только заголовокAuthorizationи он не прошёл проверку как сессия шлюза вadmin.admin_groups; илиno_credentials, если не был предъявлен ни один из заголовков
- Успешные события выпуска и обновления содержат
-
Операционные логи: удобочитаемые строки с префиксом
[gateway]о запуске, предупреждениях и ошибках вышестоящих серверов. Переменная окруженияCLAUDE_GATEWAY_LOG_LEVELуправляет уровнем детализации и принимает значенияdebug,info,warnилиerror; по умолчанию используетсяinfo. На уровнеdebugпри каждом входе и обновлении также записываются в лог имена (но не значения) claims в id_token, а также имена claims userinfo, еслиuserinfo_fallbackих предоставил, что позволяет диагностировать настройкиemail_claimиgroups_claimбез записи персональных данных в лог. На события аудита эта переменная не влияет — они генерируются всегда.
Запись операционных логов в формате JSON
Если ваш сборщик логов считывает уровень каждой строки из поля JSON, задайтеCLAUDE_GATEWAY_LOG_FORMAT=json в окружении шлюза. Требуется Claude Code v2.1.319 или новее на сервере шлюза.
Тогда каждая строка операционного лога представляет собой один объект с полями severity, time и message:
severity — это уровень лога заглавными буквами, причём warn записывается как WARNING. Неудачный запуск отображается строкой ERROR.
События аудита, которые также направляются в stderr, не меняются. Они содержат ts и evt, но не содержат severity.
Работоспособность
Шлюз обслуживаетGET /healthz как проверку жизнеспособности (liveness probe) и GET /readyz как проверку готовности (readiness probe). /readyz проверяет доступность хранилища. Если вы задали store.readiness_grace_seconds, /readyz продолжает сообщать о готовности в течение указанного числа секунд после того, как хранилище перестало отвечать.
Оба эндпоинта исключены из действия access_control.allow_cidrs, поэтому проверки продолжают работать на слушателе с ограниченным доступом.
Документ обнаружения OAuth по адресу /.well-known/oauth-authorization-server также возвращает 200 только после успешной загрузки конфигурации, обнаружения OIDC, создания клиентов вышестоящих серверов и миграции Postgres, поэтому он одновременно служит сквозной проверкой запуска.
Одновременные запросы к вышестоящим серверам
По умолчанию каждая реплика шлюза одновременно отправляет вышестоящим серверам не более 256 запросов. Потоковый ответ учитывается в этом лимите до завершения потока. Запрос, пришедший в момент, когда реплика достигла лимита, ожидает внутри шлюза освобождения слота. Разработчик видит ответ, который долго не начинается или кажется зависшим. Для вышестоящего сервераprovider: anthropic запрос, ожидающий дольше timeouts.upstream_ttfb_ms, отказывается от этого вышестоящего сервера и завершается ошибкой 502, если ни один из последующих вышестоящих серверов его не обслужит.
Строка лога при запуске, содержащая upstream requests:, показывает действующий лимит. Пока у реплики открыто больше запросов, чем позволяет лимит, она также записывает в лог предупреждение, содержащее client requests are open, не чаще одного раза в минуту.
Чтобы обслуживать больше запросов одновременно, у вас есть два варианта:
- Добавить реплики.
- Повысить лимит на каждой реплике. Задайте переменную окружения
BUN_CONFIG_MAX_HTTP_REQUESTSв контейнере шлюза целым числом от 1 до 65535, затем перезапустите контейнер.
client requests are open.
При нагрузочном тестировании с load_test_mode запросы не ожидают на этом лимите, но реплика всё равно записывает в лог предупреждение client requests are open.
Держите API_TIMEOUT_MS выше времени до первого байта шлюза
Если вы уменьшаете API_TIMEOUT_MS, чтобы быстрее повторять попытку для запроса без ответа, держите его значение выше времени, которое требуется шлюзу для отправки первых байтов потокового ответа. Запрос, ожидающий дольше, завершается по таймауту, как и каждая повторная попытка, ожидающая столько же, пока ход не завершится с Request timed out, если его раньше не завершит крайний срок первого байта.
provider: anthropic: задайтеAPI_TIMEOUT_MSвыше максимального времени, за которое ваш вышестоящий сервер отправляет первое событие.- Любой другой вышестоящий сервер: задайте значение более чем на 20 секунд выше максимального времени, за которое ваш вышестоящий сервер возвращает заголовки ответа. Шлюз отправляет свой первый keepalive
pingпримерно через 15 секунд после этих заголовков, если первое событие вышестоящего сервера не придёт раньше. Шлюз версии старше v2.1.229 не отправляет ping, поэтому для него используйте правило дляprovider: anthropic.
Более быстрая повторная попытка для запроса без ответа с помощью крайнего срока первого байта
Чтобы Claude Code быстрее повторял попытку для потокового запроса без ответа, задайте для него крайний срок первого байта с помощьюCLAUDE_STREAM_FIRST_BYTE_TIMEOUT_MS на машинах ваших разработчиков. Крайний срок ограничивает время, в течение которого первая попытка ожидает заголовки ответа. Без него эта попытка может ждать от 5 до 6 минут. Требуется Claude Code v2.1.307 или новее на машине разработчика.
Задайте переменной положительное целое число миллисекунд в блоке env политики шлюза или в оболочке разработчика. Держите значение выше максимального времени до первого байта вашего шлюза, иначе Claude Code может прерывать и повторно отправлять исправные запросы, заголовки которых приходят дольше. В этом примере в оболочке разработчика задаётся 60 секунд:
API_TIMEOUT_MS только ради более быстрых повторных попыток, удалите это значение, иначе одна повторная отправка без ответа может завершить ход с No response from API.
Чтобы убедиться, что крайний срок сработал, попросите разработчика запустить Claude Code с отладочным логированием, затем найдите в логе [first-byte] no response headers.
Поведение при сбоях
Если Postgres становится недоступен, сам шлюз продолжает обслуживать разработчиков, уже выполнивших вход, а новые входы завершаются ошибкой. Смогут ли разработчики действительно продолжать работу, зависит от того, как ваш оркестратор обрабатывает готовность:- Существующие сессии: Bearer-токены проверяются локально с помощью секрета JWT, обновления сессий не обращаются к хранилищу, и процесс шлюза по-прежнему может обслуживать запросы инференса
- Новые входы: завершаются ошибкой до восстановления Postgres, поскольку поток авторизации устройства и его счётчики ограничения частоты запросов хранятся в Postgres
- Применение лимитов расходов: по умолчанию во время сбоя работает в открытом режиме (fail open), то есть запросы пропускаются и инференс продолжает работать; переключите его в закрытый режим (fail closed), если предпочитаете блокировать запросы, а не пропускать их без учёта расходов
- Готовность: по умолчанию
/readyzсообщает о неготовности, как только Postgres становится недоступен, поэтому все реплики одновременно не проходят проверку готовности. Если трафик направляется только на реплики, прошедшие проверку, весь трафик, включая инференс, который шлюз ещё мог бы обслужить, отклоняется до восстановления Postgres. Проверка жизнеспособности на/healthzвсё это время продолжает проходить успешно.
ttl_hours, а новые входы завершаются ошибкой. Обновление сессии получает ответ с предложением повторить попытку и завершается успешно, как только IdP снова станет доступен. Задайте более длительный ttl_hours, если у вашего IdP часто бывают окна обслуживания.
Льготный период готовности
Чтобы разработчики, уже выполнившие вход, продолжали работать во время кратковременного сбоя Postgres, например при переключении базы данных на резервный узел, задайтеstore.readiness_grace_seconds больше длительности такого переключения, например 300. Если лимиты расходов включены и используется поведение по умолчанию (fail open), запросы через реплику, остающуюся в состоянии готовности, не учитываются до восстановления Postgres, поэтому держите значение минимальным, достаточным для покрытия переключения. Если вы задали enforcement.fail_closed_on_error: true, шлюз отклоняет запросы инференса от разработчиков, выполнивших вход, с сообщением 429 spend limit unavailable до восстановления Postgres, даже пока реплики продолжают проходить проверку готовности.
Эта настройка требует Claude Code v2.1.282 или новее на сервере шлюза. Более ранняя версия шлюза отказывается запускаться, обнаружив этот ключ, поэтому обновите все реплики, прежде чем добавлять его. Об откате см. в разделе Обновления.
Если вместо этого направить проверку готовности на /healthz, реплики также продолжат проходить её во время сбоя, но /healthz никогда не сообщает о неготовности, поэтому реплика, чьё соединение с Postgres не восстанавливается, тоже продолжит её проходить.
Ротация секрета JWT
Выполняйте ротацию секрета подписи поэтапно, чтобы существующие сессии оставались действительными:- Сгенерируйте новый секрет. Добавьте его в начало массива
session.jwt_secret. - Выполните повторное развёртывание. Новые токены подписываются новым секретом; старые токены по-прежнему проходят проверку.
- По истечении
ttl_hoursс запасом удалите старый секрет и снова выполните развёртывание.
ttl_hours.
Postgres
Шлюз хранит своё состояние в базе данных PostgreSQL:- База данных: сам PostgreSQL, самостоятельно размещённый или управляемый, минимальной версии или новее. Базы данных, которые лишь реализуют протокол Postgres, например распределённые SQL-базы данных, не поддерживаются.
- Адрес:
store.postgres_urlпринимает один хост. Если база данных состоит из нескольких узлов, используйте адрес перед ними, например эндпоинт вашего управляемого сервиса, балансировщик нагрузки или виртуальный IP-адрес. Задайте льготный период готовности дольше, чем длится переключение на резервный узел.
_migrations; все они создаются миграциями при запуске:
Цикл с интервалом 30 секунд удаляет строки
kv с истёкшим TTL, а ежечасная очистка применяет сроки хранения к таблицам расходов, поэтому ничто не растёт неограниченно. Если лимиты расходов не настроены, запись ведётся только в kv. Шлюз сам применяет миграции своей схемы при запуске и при каждом обновлении, поэтому его роли в базе данных нужны права на создание и изменение таблиц. Выделите для шлюза отдельную базу данных или схему, чтобы сузить эти права.
При использовании лимитов расходов потеря базы данных означает потерю учёта расходов и лимитов, а не только повторный вход разработчиков, поэтому регулярно делайте резервные копии. Чтобы немедленно удалить данные ушедшего разработчика, не дожидаясь истечения срока хранения, выполните напрямую DELETE FROM principal_emails WHERE principal = '<sub>'; это удаляет единственную таблицу, содержащую его адрес электронной почты, имя и группы. Строки spend и admin_audit ссылаются только на псевдонимный OIDC sub.
Определение размера пула соединений
Каждая реплика открывает доstore.max_connections соединений с Postgres, по умолчанию пять. Следите, чтобы произведение числа реплик на store.max_connections не превышало число соединений, оставшихся в базе данных для шлюза:
- Реплики: учитывайте максимальное число одновременно работающих. Начните с максимума автомасштабирования или с числа реплик, если автомасштабирование не используется, и добавьте дополнительные реплики, которые поэтапное обновление запускает до остановки старых. В Amazon ECS с настройками по умолчанию и в Cloud Run их может быть столько же.
- Оставшиеся соединения: возьмите значение
max_connectionsбазы данных, затем вычтите то, что резервирует база данных, и то, что удерживают другие клиенты. PostgreSQL резервируетsuperuser_reserved_connections, по умолчанию три. Управляемый сервис может резервировать больше, поэтому сверьтесь с его документацией.
max_connections равным 50 и двумя соединениями, удерживаемыми другими клиентами, остаётся 50 − 3 − 2 = 45, поэтому итоговое число укладывается.
Если итоговое число не укладывается, измените одно из следующего:
- База данных: увеличьте её
max_connections - Реплики: запускайте меньше реплик или настройте оркестратор на запуск меньшего числа дополнительных реплик при поэтапном обновлении
- Пул: уменьшите
store.max_connections, но при включённых лимитах расходов сохраняйте его достаточным для нагрузки каждой реплики. Иначе проверки расходов могут завершаться по таймауту в ожидании соединения, а шлюз будет записывать в логspend check failed: spend precheck timed out.
Обновления
Реплики не хранят состояния, поэтому поэтапный перезапуск не приводит к потере состояния шлюза. Шлюз выполняет миграции схемы при запуске, а значит, развёртывание нового бинарного файла само мигрирует базу данных. Одновременно работающие реплики упорядочиваются с помощью рекомендательной блокировки Postgres, поэтому каждую миграцию применяет только одна из них. Когда ваш оркестратор останавливает реплику сигналомSIGTERM, например при поэтапном перезапуске или уменьшении масштаба, шлюз перестаёт принимать новые соединения и позволяет уже выполняющимся запросам и потокам завершиться перед выходом. Он ждёт до 25 секунд — это называется окном завершения (drain window), — а затем закрывает всё, что ещё открыто. Сигнал SIGINT, например Ctrl+C в терминале, запускает такое же завершение, а второй сигнал во время завершения закрывает открытые запросы и немедленно завершает работу. Завершение с ожиданием требует шлюза v2.1.274 или новее.
Длинная генерация может передаваться потоком в течение нескольких минут. В Kubernetes и Amazon ECS увеличьте одновременно оба параметра, чтобы дать таким потокам больше времени:
- Окно завершения: задайте переменную окружения
CLAUDE_GATEWAY_DRAIN_TIMEOUT_MSв контейнере шлюза положительным целым числом миллисекунд, например120000. Шлюз игнорирует значение в любой другой форме, например120s, и сохраняет значение по умолчанию 25 секунд - Льготный период вашего оркестратора:
terminationGracePeriodSecondsв Kubernetes илиstopTimeoutв Amazon ECS
preStop, поскольку отсчёт льготного периода начинается до запуска хука, а не в момент получения шлюзом SIGTERM.
Ваша платформа также может ограничивать длительность завершения:
- Amazon ECS на Fargate:
stopTimeoutдопускает не более 120 секунд - Cloud Run: останавливает экземпляр через 10 секунд после
SIGTERM, поэтому открытые потоки получают там не более 10 секунд независимо от окна завершения
drain window over after, подсчитывает прерванные запросы и называет обе настройки, которые следует увеличить.
Миграции только добавляются, поэтому откат к предыдущему бинарному файлу, знающему меньше миграций, безопасен; он игнорирует лишние строки. При откате YAML также повторно проверяется по схеме более старого бинарного файла, поэтому конфигурация, использующая ключ, появившийся в более новом выпуске, не позволит запуститься старой версии. Удалите новый ключ перед откатом.
Поскольку вы закрепляете версию шлюза в собственном образе, исправления из новых выпусков Claude Code, включая исправления безопасности, попадают в ваше развёртывание только после того, как вы обновите закреплённую версию и выполните повторное развёртывание. Включите шлюз в тот же график установки обновлений, который вы используете для других сервисов, хранящих производственные учётные данные.
Безопасность
Этот раздел отвечает на вопросы, которые задает проверка безопасности: какие данные проходят через шлюз и куда они идут, какие атаки защищает дизайн и какие ответы принадлежат в опроснике соответствия.Поток данных
Краткое резюме модели угроз
Шлюз находится внутри периметра вашей сети, но отдельные ноутбуки разработчиков не рассматриваются как доверенные. Дизайн учитывает это тремя способами:- Разработчики держат краткосрочные JWT вместо сырых ключей upstream. Ветвь CLI-к-шлюзу использует грант устройства RFC 8628, и обмен авторизацией шлюза с IdP запускает PKCE в конфигурации по умолчанию, поэтому перехваченный код авторизации IdP бесполезен.
- Страница проверки устройства применяет same-origin POST и ограничение скорости для каждого IP согласно RFC 8628 §5.1. См. Сопротивление brute-force пользовательского кода.
-
Исходящие запросы шлюза к вашему IdP, вашим сборщикам OTLP и
provider: anthropicupstreams проходят через защиту от подделки запроса на стороне сервера (SSRF), которая разрешает DNS, блокирует link-local и адреса облачных метаданных плюс loopback по умолчанию и закрепляет соединение на разрешенный IP, поэтому управляемые оператором URL не могут быть перенаправлены на конечные точки облачных метаданных. Диапазоны приватных RFC 1918 намеренно разрешены, потому что IdP и сборщики OTLP обычно живут на приватных IP. Для других поставщиков шлюз отказывает вbase_url, который называет один из этих адресов или имя хоста метаданных при загрузке конфигурации, и SDK поставщика затем подключается без проверки DNS. Если вы включите только прокси выход, эта проверка адреса переходит к вашему forward proxy: шлюз передает ему имена хостов и список разрешений прокси должен отказать этим назначениям. УстановитеCLAUDE_GATEWAY_ALLOW_LOOPBACK=1в окружении шлюза только когда что-то, что шлюз должен достичь, легитимно живет на loopback, такое как локальная разработка IdP или сборщик OTLP sidecar наlocalhost. Переменная ослабляет блокировку loopback для каждого настроенного оператором URL и также пропускает предупреждение при загрузке, которое проверяет, может ли pod достичь конечной точки облачных метаданных, поэтому предпочитайте давать сборщику его собственный внутренний адрес.
- Скомпрометированный хост шлюза: хост как содержит upstream учетные данные, так и распределяет управляемые параметры каждому подключенному разработчику, поэтому контроль над конфигурацией шлюза сравним с контролем над вашим MDM. Диалог одобрения CLI для параметров, способных к shell, ограничивает молчаливые изменения, но не заменяет безопасность хоста.
- Вредоносный поставщик OIDC: поставщик подписывает id_tokens, которым шлюз доверяет, поэтому он может утверждать любую идентификацию. Проверка и защита вашего IdP — это ваша ответственность.
Сопротивление brute-force пользовательского кода
user_code, который разработчик вводит на странице проверки /device, — это 8 символов, взятых из алфавита из 20 символов, что дает 20⁸ или около 2,56×10¹⁰ комбинаций, и он истекает через 10 минут.
Шлюз применяет ограничения скорости для каждого IP на конечных точках грантов устройства, настраиваемые через rate_limits. Поднимите лимиты, если много разработчиков входят с одного общего корпоративного NAT адреса. Крупные развертывания показывает, как их размер. Лимиты применяются только к потоку входа, а не к inference.
Позиция соответствия
- Резидентность данных: собственная плоскость данных шлюза не отправляет ничего Anthropic, если только API Anthropic не является настроенным upstream; когда это так, ваше существующее соглашение об обработке данных применяется к пути inference. Телеметрия, аудит, идентификация и параметры идут только к назначениям, которые вы настраиваете.
- Трафик хост-процесса: хост-процесс — это Claude Code CLI.
claude gatewayработает под теми же правилами третьих сторон, что и развертывания Amazon Bedrock и Google Cloud’s Agent Platform, и не отправляет ничего Anthropic. До v2.1.227 хост-процесс отправлял телеметрию запуска, такую как версия продукта и платформа, которую установкаCLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=1в окружении контейнера отключала. Эти выпуски также отправляли один запросHEADпри загрузке, без тела или учетных данных, на/api/helloнаhttps://api.anthropic.com, или наANTHROPIC_BASE_URLкогда окружение установило его, если только окружение также не установило переменную прокси, такую какHTTPS_PROXYили сертификат клиента mTLS. Они игнорировали ответ, поэтому блокировка этого запроса на брандмауэре выхода не влияла на шлюз. - Аналитика клиента: CLI отключает свою собственную аналитику использования и отчеты об ошибках при входе в шлюз. До первого входа CLI все еще отправляет события запуска Anthropic, включая на машинах, чьи управляемые параметры принуждают вход в шлюз. Чтобы отключить и их, доставьте
DISABLE_TELEMETRYв тех же управляемых параметрах на стороне клиента, которые принуждают вход в шлюз. - Отчеты об ошибках: CLI отключает отчеты об ошибках всякий раз, когда его запросы модели идут на любую конечную точку, отличную от первоклассного API Anthropic, такую как Amazon Bedrock или пользовательский
ANTHROPIC_BASE_URL. - Машины клиентов: CLI разработчиков все еще отправляют проверки имени хоста WebFetch и проверки версии Anthropic, если не установлены
CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=1иskipWebFetchPreflight: true. У запросов к маркетплейсам плагинов есть собственные способы отключения. См. использование данных. - Рейтинги опроса: при входе в шлюз CLI отключает загрузку рейтингов, привязанную к Anthropic, вместе с потоками аналитики, поэтому он не отправляет рейтинги Anthropic.
- Обмен транскриптом: выбор Yes на подсказке обмена транскриптом опроса записывает локальный файл в
~/.claude/feedback-bundles/вместо загрузки Anthropic. - Обновления клиента: проверки обновлений отделены от трафика шлюза. Закрепите версии через вашу собственную дистрибуцию и установите
DISABLE_UPDATES, если ноутбуки не должны получать выпуски.DISABLE_AUTOUPDATERостанавливает только фоновые обновления, в то время какclaude updateвсе еще работает. - TLS: обслуживайте
public_urlпо HTTPS в production, либо из собственного слушателя шлюза черезlisten.tls, либо из TLS-завершающего ingress перед простыми HTTP репликами, с установленнымlisten.public_urlв обоих случаях. Шлюз не отказывает простой HTTP. IdP должен обслуживать HTTPS в production, и Postgres поддерживает?sslmode=require. УстановитеStrict-Transport-Securityна вашем ingress. - Раскрытие уязвимостей: следуйте Отчету о проблемах безопасности
Запросы к маркетплейсам плагинов
Claude Code загружает маркетплейсы плагинов напрямую с машины каждого разработчика, а не через шлюз. Список хостов приведён в разделе Требования к сетевому доступу. Когда разработчик впервые запускает интерактивную сессию в терминале, Claude Code регистрирует официальный маркетплейсclaude-plugins-official. Он загружает каталог с downloads.claude.ai, а если это не удаётся, клонирует его с github.com. Последующие обновления описаны в разделе Какие маркетплейсы и плагины обновляются автоматически.
CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=1 не останавливает первую регистрацию. Её останавливает любая из этих управляемых настроек:
- Список маркетплейсов: список разрешённых маркетплейсов
strictKnownMarketplaces, в который этот маркетплейс не входит, или записьblockedMarketplaces, которая его называет - Переменная окружения:
CLAUDE_CODE_DISABLE_OFFICIAL_MARKETPLACE_AUTOINSTALLсо значением"1"в управляемом блокеenv
cli или code политики шлюза.
Устранение неполадок
Для вопросов и обратной связи используйте поддержку Claude Code или откройте issue в репозитории Claude Code на GitHub. Вы также можете связаться с командой, обслуживающей ваш аккаунт в Anthropic. При сообщении о проблеме включите:- Проблема шлюза: stderr шлюза для соответствующего окна, ваш
gateway.yamlс редактированными секретами, версию шлюза, показанную на целевой странице в/и в заголовке ответаx-cc-gateway-versionна/managed/settings, и что недавно изменилось - Проблема входа: разработчик запускает
claude --debug-file ./claude-debug.txt, воспроизводит и отправляет этот файл плюс журнал аудита шлюза для того же окна - Проблема inference: запрошенная модель, настроенные upstreams и журнал аудита шлюза для запроса, который записывает, какой upstream обслужил его и статус ответа
Сообщение
Cloud gateway sign-in was not completed называет имя хоста шлюза. Когда у Claude Code есть и закреплённый отпечаток, и представленный, сообщение также показывает первые 16 символов каждого.
Если Claude Code сообщает couldn't load your organization's managed settings после входа в шлюз, Claude Code называет причину, перезапускается на месте и возобновляет диалог. Если Claude Code не может перезапуститься, например в фоновой сессии, Claude Code завершает сессию и сохраняет вход.
Слишком большие заголовки запросов после входа
Запросы разработчика могут завершаться ошибкой431 после входа, если разработчик состоит во многих группах IdP.
Шлюз отвечает 431, когда заголовки запроса в сумме превышают 256 KiB или значение limits.max_request_header_bytes, если вы его задали. Для таких запросов он не записывает ни строки в лог, ни события аудита. Версии шлюза до v2.1.284 отвечают 431 при превышении 16 KiB.
Начните с первого из следующих пунктов, который применим к вашему шлюзу:
- Шлюз старше v2.1.284: обновите шлюз
- Задан
limits.max_request_header_bytes: увеличьте значение или удалите ключ - Ни то, ни другое не применимо, или
431продолжает возникать после этого: сделайте так, чтобы ваш IdP выдавал меньше групп. В разделе Identity provider setup описано, как Okta, Microsoft Entra ID и Google Workspace передают группы
oidc.allowed_groups: определяет, кто может войтиadmin.admin_groups: определяет, кто может вызывать admin API со своей сессией шлюзаmatch.groupsвmanaged.policies: определяет, какая политика применяется к разработчикуgroupsу upstream: определяет, какие upstream обслуживают разработчикаrbac_groupлимиты расходов: определяют, какие групповые лимиты применяются к разработчику
Долгое мышление заканчивается таймаутами прокси
Если ваш upstream —provider: anthropic, вместо этого используйте раздел Долгое мышление на upstream Anthropic API: там вы тоже увеличиваете CLAUDE_STREAM_IDLE_TIMEOUT_MS, но время и ошибки отличаются.
Если ходы завершаются сбоем после долгого мышления, а ваш прокси записывает в лог один запрос, открытый около 12,5 минуты, затем серию ошибок 504, увеличьте CLAUDE_STREAM_IDLE_TIMEOUT_MS в политике шлюза. Например, при таймауте простоя 240 секунд на прокси серия состоит из 10 запросов, каждый из которых обрывается через 240 секунд.
- Первый запрос: поток, который доставляет первое событие ответа,
message_start, а затем только пинги, пока Claude думает. С настройками по умолчанию Claude Code завершает этот поток примерно через 12,5 минуты. - Остальные 10: тот же запрос, отправленный без потоковой передачи, а затем повторно, всего 10 отправок по умолчанию. Они не получают пингов, поэтому медленный ответ упирается в таймаут прокси.
Подтвердите причину
Попросите разработчика воспроизвести сбой сclaude --debug-file ./claude-debug.txt, затем найдите в этом файле следующую строку:
CLAUDE_CODE_DISABLE_NONSTREAMING_FALLBACK в 1, вы не увидите запросов без потоковой передачи, а ход завершится с API Error: Stream idle timeout - no chunks received. Применяется то же исправление.
Выберите значение
Выберите значениеCLAUDE_STREAM_IDLE_TIMEOUT_MS, у которого второй столбец покрывает вашу самую долгую паузу на мышление, или начните с 1800000, если вы её не знаете. Поток может держаться только на пингах примерно на 7,5 минуты дольше, чем это значение:
Если upstream зависает, а шлюз продолжает отправлять пинги, ваши разработчики тоже ждут столько же, прежде чем Claude Code откажется от потока. Соединение, которое полностью замолкает, по-прежнему завершается через 5–6 минут, потому что таймаут простоя тела не зависит от этой переменной.
Передайте значение в политике
Добавьте записьenv в каждую политику в gateway.yaml, которая уже передаёт настройки Claude Code разработчикам, которых вы хотите охватить. Поместите её под ключ code, cli или settings, который уже есть в этой политике. Чтобы сначала опробовать значение, начните с политики, соответствующей одной группе. О том, как политики сопоставляются и наследуются, см. managed. В этом примере запись добавляется в политику match: {} с ключом cli:
cli вы охватываете сессии в терминале, расширении IDE и Agent SDK. Для вкладки Code в Claude Desktop см. Выбор cli или code.
Перезапустите шлюз, чтобы он прочитал изменённый файл. Затем попросите разработчиков перезапустить Claude Code, чтобы получить CLAUDE_STREAM_IDLE_TIMEOUT_MS.
Долгое мышление на upstream Anthropic API
Еслиprovider: anthropic — единственный upstream модели, а ваш прокси записывает в лог один запрос, открытый около 20 минут, затем ошибки 502 или 504, увеличьте CLAUDE_STREAM_IDLE_TIMEOUT_MS в политике шлюза.
- Долгий запрос: поток, который доставляет
message_start, а затем только пинги, пока Claude думает. С настройками по умолчанию Claude Code завершает его примерно через 20 минут, а после увеличения переменной — позже. - Ошибки: запросы, которые Claude Code затем отправляет без потоковой передачи. Каждый из них завершается ошибкой
502от шлюза или ошибкой504от вашего прокси, если таймаут прокси короче времени ожидания шлюза. Это время ожидания —timeouts.upstream_ttfb_ms, и для этого исправления увеличивать его не нужно.
900000 и 45 при 1800000. Затем выполните шаги из раздела Передайте значение в политике.
Связанное
- Обзор шлюза Claude apps: быстрый старт и подключение разработчика
- Справочник по конфигурации: каждый параметр файла
gateway.yaml