# Нужны ли статические секреты для аутентификации MCP-агентов?

> Аутентификация MCP-агентов требует короткоживущих токенов, узких прав, шлюзов подтверждения, проверенной ротации и понятных журналов.

MCP-агентам в продакшене нужны короткоживущие токены доступа OAuth, а не статические секреты. Статический ключ упрощает прототип, но в продакшене он дает непредсказуемому процессу долгосрочные полномочия, слабо связывает действия с исполнителем и затрудняет отзыв доступа. Такой компромисс редко можно оправдать, если агент имеет доступ к данным клиентов или состоянию продакшена.

Сам по себе OAuth не делает агента безопасным. Токен на десять минут с правом `production.admin` все равно дает агенту десять минут на опасные действия, а окно подтверждения с одним лишь названием инструмента почти не помогает человеку принять решение. Безопасный доступ появляется, когда вместе работают пять механизмов: идентификация, область прав, срок действия, подтверждение и доказательства.

Я придерживаюсь простого разграничения. Агент может получить временное право для одного ресурса и одной ограниченной задачи. Система вокруг агента хранит долгосрочные учетные данные, применяет политики, обновляет и отзывает доступ. Такая граница не позволяет инъекции в промпт, ошибочному плану или утекшей трассировке превратиться в постоянный доступ к продакшену.

## Статические секреты решают не ту эксплуатационную задачу

Статические секреты упрощают подключение, но не контроль продакшена. Инженер один раз создает ключ, сохраняет его в переменной окружения, и каждый запуск работает до следующей ротации. За удобством скрываются четыре издержки: ключ часто дает широкие права, все экземпляры агента выглядят одним субъектом, срок действия не ограничивает инцидент, а для ротации приходится синхронно обновлять развертывания.

Худший вариант выглядит так: API-ключ поставщика копируют в конфигурацию MCP-сервера, а затем его наследует каждый процесс, который запускает этот сервер. Локальный агент, задача CI и автономный рабочий процесс в продакшене теперь используют одну личность. Когда возникает неожиданная запись, журнал поставщика покажет, какой ключ сработал, но не укажет запуск агента, запрос пользователя, решение политики или подтверждение, которое привело к действию.

Короткоживущий токен меняет характер сбоя. Вместо ситуации «злоумышленник пользуется доступом, пока мы не обнаружим и не заменим ключ» возникает ограничение «злоумышленник пользуется доступом до истечения срока и только в рамках аудитории и прав токена». Риск заметно снижается, но лишь при условии, что эмитент не позволяет без ограничений обновлять токен, а сервер ресурса проверяет все условия. Срок действия без проверки остается декорацией.

Команды обращаются к статическим учетным данным по одной оправданной причине: многие рабочие инструменты пока не предлагают другого способа. Считайте это ограничением совместимости, а не целевой архитектурой. Поставьте перед секретом узкий брокер, пусть он выдает агенту внутреннее ограниченное право, а исходное значение по возможности не попадает в промпты, результаты инструментов, трассировки и память процесса агента.

Не путайте секрет в хранилище с короткоживущими учетными данными. Хранилище улучшает хранение и выдачу, но после чтения статического секрета агент все равно получает долгосрочные полномочия на предъявителя. В безопасной схеме рабочий процесс доказывает свою личность хранилищу или сервису токенов и получает ограниченный токен, не видя корневых учетных данных.

## Личность агента и полномочия пользователя различаются

Агенту нужна собственная идентификация рабочего процесса, даже когда он действует от имени вошедшего пользователя. Идентификация рабочего процесса отвечает на вопрос, какой развернутый процесс выполнил вызов. Делегированные права пользователя показывают, чей запрос его разрешил. Если объединить эти личности, расследования инцидентов и отключение доступа станут ненадежными.

Возьмем инструмент развертывания, который вызывает инженерный помощник. Пользователь может иметь право развернуть платежный сервис, а рабочему процессу агента разрешено запускаться только из производственного оркестратора. Решение о доступе должно учитывать оба факта. Токен или связанное с ним серверное разрешение должны закреплять пользователя, экземпляр агента, окружение, целевой сервис и запрошенную операцию.

У полностью автономной задачи может не быть текущего пользователя. Не выдумывайте его и не используйте учетную запись инженера, который создал задачу. Выдайте сервисное разрешение именованному рабочему процессу, зафиксируйте автора конфигурации и ограничьте права рамками запланированной задачи. Ответственность человека хранится в конфигурации и журнале аудита, а полномочия во время выполнения принадлежат сервисной личности.

Такое разделение также управляет отзывом. Если сотрудник уходит, отзовите его разрешения, не отключая несвязанные сервисные задачи. Если скомпрометировано одно развертывание агента, отзовите этот рабочий процесс, не завершая сеансы всех пользователей. Если пользователь отзывает согласие на подключенный сервис, прекратите делегирование, даже если сам агент исправен.

Я использую набор субъектов вместо одного расплывчатого поля `actor`:

```json
{
  "workload": "agent:release-orchestrator:v17",
  "subject": "user:1842",
  "session": "run:01JZ8F4M2K",
  "tenant": "acme-prod"
}
```

Конкретные названия несущественны. Важно хранить эти измерения раздельно. Сервер ресурса должен принимать решение по проверенным утверждениям токена или доверенному состоянию на сервере, а не по строкам с личностями, которые модель передала в аргументах инструмента.

## Области прав должны соответствовать реальным операциям

Область прав должна разрешать операцию, которую сервер ресурса умеет контролировать, а не обозначать расплывчатую должность. Такие права, как `admin`, `agent` и `full_access`, переносят фактическое решение о доступе в текст промпта. Модель могли попросить действовать осторожно, но сервер все равно видит вызывающую сторону, которой разрешено почти все.

Начните с каталога инструментов и классифицируйте каждую операцию по ресурсу, действию, окружению и последствиям. Чтение статуса развертывания отличается от его запуска. Создание резервной копии базы данных отличается от восстановления. Подготовка возврата отличается от его проведения. Если каждая такая пара использует одно право, разделите его или добавьте явную серверную политику между операциями.

Практическая карта прав может выглядеть так:

- Прочитать статус развертывания: `deployments.read`, ограничение на именованный сервис, подтверждение не нужно.
- Запустить развертывание в тестовом окружении: `deployments.start`, ограничение на тестовое окружение, проверка политики.
- Запустить развертывание в продакшене: `deployments.start`, ограничение на идентификатор релиза и продакшен, подтверждение человеком.
- Прочитать очищенные журналы: `logs.read`, ограничение на сервис и диапазон времени, подтверждение не нужно.
- Изменить рабочую конфигурацию: `config.write`, ограничение на одобренные поля, подтверждение человеком.

Одних областей OAuth обычно недостаточно, чтобы описать имена сервисов, владельцев строк, лимиты расходов или разрешенные поля конфигурации. Задайте эти ограничения в политике доступа, которую проверяет MCP-сервер или отдельный сервис политик. Область прав разрешает класс действий, а политика решает, относится ли к нему конкретный вызов.

RFC 9700 рекомендует сокращать права токена до необходимого минимума и по возможности ограничивать аудиторию конкретным сервером ресурса. Для агентов в продакшене я сделал бы оба условия обязательными. Токен доступа для MCP-сервера развертываний должен отклоняться MCP-сервером исходного кода, даже если оба сервера доверяют одному эмитенту.

RFC 8707 определяет параметр `resource` для такого ограничения аудитории. Текущая спецификация авторизации MCP также требует, чтобы MCP-сервер проверял выпуск токена именно для него. Это мешает вредоносному или ошибочно настроенному серверу получить токен для другого производственного ресурса и повторно применить его там.

Не выпускайте единый токен с суммой прав для всего плана, включающего несколько инструментов. Если задача читает обращение, меняет ветку и предлагает развертывание, получайте отдельный токен с заданной аудиторией при обращении к каждому ресурсу. Планировщик может хранить план, но ему не нужны одновременные полномочия во всех системах из этого плана.

## Срок токена ограничивает время, а не намерение

Срок действия токена должен соответствовать полезному времени выполнения операции. Не привязывайте его к продолжительности рабочего дня лишь потому, что восемь часов кажутся привычным числом. Большинство вызовов MCP завершаются за секунды, а ограниченному запуску агента может потребоваться несколько минут. Дайте достаточно времени на ожидаемые повторы и задержку сети, затем потребуйте нового решения политики.

Единой правильной продолжительности не существует. Токен только для чтения при долгом анализе журналов может жить дольше токена, способного менять рабочий трафик. Одноразовый токен для подтверждения конкретного развертывания может иметь короткий срок и привязку к идентификатору развертывания. Чем серьезнее последствия и проще повторное применение права, тем короче и точнее должна быть возможность.

Короткий срок не исправляет слишком широкие права. Если агент может удалить все проекты, пяти минут вполне достаточно. Короткий срок также не останавливает немедленное злоупотребление после кражи. Ограничение аудитории, политика ресурса, привязка токена к отправителю там, где она поддерживается, сетевые ограничения и шлюзы подтверждения все еще обеспечивают основную защиту.

Считайте истечение срока частью обычной работы, а не исключительной ошибкой. Получив HTTP 401, MCP-клиент должен отбросить просроченный токен, вернуться к доверенному пути получения и запросить новое разрешение только в том случае, если запуск все еще одобрен. Нельзя переключаться на статический ключ, спрятанный в конфигурации.

Сведите расхождение часов к небольшому и наблюдаемому значению. Серверы должны отклонять просроченные токены и токены со временем активации неправдоподобно далеко в будущем, допуская лишь документированный небольшой сдвиг для распределенных систем. Записывайте эмитента, идентификатор токена или безопасный отпечаток, время выпуска и истечения, аудиторию и области прав, но никогда не записывайте само значение токена.

Полезная политика начинается с категорий риска, а не с одного общего числа:

- Очищенные данные только для чтения могут использовать токен на всю продолжительность задачи.
- Обратимые записи требуют более короткого токена и ограничения ресурса.
- Необратимые действия или записи с серьезными последствиями требуют привязки к транзакции и подтверждения.
- Фоновым задачам нужны обновляемые разрешения рабочего процесса с максимальной длительностью сеанса.

Перед настройкой измерьте реальную длительность задач и частоту обновления. Если агенты обновляют токен почти при каждом вызове, срок может быть слишком коротким или клиент неверно кеширует его. Если токены регулярно живут намного дольше завершившихся запусков, отзывайте их при завершении или сокращайте срок.

## Подтверждение ставят на границе побочного эффекта

Шлюз подтверждения работает только тогда, когда показывает точный эффект, который сервер готов произвести. Вопрос «Разрешить инструмент развертывания?» до начала планирования означает слабое согласие. Человек еще не видит цель, версию, окружение или исключения из политик, а повторяющиеся общие запросы приучают подтверждать автоматически.

Показывайте подтверждение после того, как агент подготовил типизированный запрос и автоматическая политика его проверила, но до побочного эффекта. Для развертывания в продакшене покажите сервис, идентификатор релиза, окружение, краткое описание изменения, ожидаемую проверку состояния и точку отката. Для платежа покажите получателя, сумму, валюту, счет и результат проверки дубликата. MCP-сервер должен формировать это представление из доверенных данных, а не принимать текстовый пересказ модели.

Привяжите подтверждение к дайджесту нормализованного запроса. При изменении любого существенного поля после подтверждения дайджест изменится, и сервер запросит согласие снова. Это закрывает частый пробел, когда человек одобряет одно представление, а во время повторной попытки агент меняет аргументы.

```json
{
  "action": "deployments.start",
  "resource": "service:billing-api",
  "environment": "production",
  "release_id": "rel_8421",
  "request_digest": "sha256:7c1d...9a20",
  "expires_in_seconds": 120
}
```

Запись подтверждения должна разрешать именно это действие, а не повышать права всего сеанса. Одноразовая возможность, которую погашает сервер, чище добавления `production.write` в общий токен. Отклоняйте ее после использования, по истечении срока или при несовпадении дайджеста запроса.

Не каждая запись требует участия человека. Агент может создать изолированную ветку или открыть черновик изменения по правилам политики, поскольку действие ограничено и доступно для проверки. Требуйте участия человека при пересечении границы доверия: изменение продакшена, внешняя коммуникация, экспорт конфиденциальных данных, политика безопасности, деньги, удаление или расширение прав.

Не позволяйте агенту решать, нужно ли подтверждение. Это правило принадлежит серверу ресурса или независимому сервису политик. Модель может классифицировать намерение для выбора маршрута, но детерминированная политика должна блокировать выполнение, если нет обязательных фактов или подтверждения.

Пакетные подтверждения требуют осторожности. Разрешение «всех оставшихся шагов» допустимо лишь для явного неизменяемого набора операций, который пользователь может просмотреть. Открытое разрешение на все, что модель решит позднее, остается долгосрочным широким правом с более дружелюбным интерфейсом.

## Право обновления требует более строгого хранения

Короткоживущий токен доступа почти не защищает, если тот же агент хранит токен обновления и может бесконечно выпускать новые. Считайте право обновления долгосрочными учетными данными. Храните его в защищенном брокере, по возможности привязывайте к клиенту, меняйте по ротации и никогда не передавайте через параметры MCP-инструментов или контекст модели.

RFC 9700 требует, чтобы публичные клиенты с токенами обновления применяли привязку токена к отправителю или ротацию токенов обновления. При ротации каждое успешное обновление возвращает новый токен обновления и делает предыдущий недействительным. Если злоумышленник и настоящий клиент попытаются использовать одну цепочку токенов, обнаружение повтора позволит отозвать активную цепочку и потребовать новое разрешение.

Этот механизм обнаруживает повторное использование, но не обезвреживает кражу. Злоумышленник, который применил токен первым, может выглядеть легитимно до следующего обновления настоящего клиента. Задайте срок бездействия и максимальный возраст разрешения, отзывайте доступ после событий безопасности и подавайте сигнал о повторе. Для автономного агента с серьезными полномочиями лучше использовать идентификацию рабочего процесса и обмен токенов, а не пользовательский токен обновления, который живет месяцами.

Стоит разделить три уровня учетных данных:

- Доказательство рабочего процесса идентифицирует разрешенную среду агента перед брокером токенов.
- Токен обновления или сервисное разрешение хранит долгосрочные делегированные полномочия.
- Токен доступа дает короткоживущую возможность, которую предъявляют одному MCP-серверу.

Рядом с процессом агента место есть только последнему уровню. Даже его не помещайте в промпт, а передавайте через транспорт или поставщика учетных данных. Описания инструментов, аргументы и результаты не должны содержать токены, поскольку эти поверхности часто попадают в трассировки и отладочные записи.

Для взаимодействия MCP между машинами поток клиентских учетных данных OAuth позволяет обойтись без интерактивного согласия, но клиентский секрет в каждом контейнере агента снова создает проблему статического секрета. Используйте идентификацию рабочего процесса средствами платформы, закрытый ключ в управляемом сервисе подписи или другой механизм с привязкой к отправителю, если инфраструктура его поддерживает. Сервер авторизации все равно должен выдавать ограниченный токен доступа, а не раскрывать исходные учетные данные MCP-серверу.

Не передавайте напрямую токен, полученный для другого API. MCP-сервер работает как самостоятельный сервер ресурса и должен принимать лишь токены для своего канонического идентификатора ресурса. Обмен токена или брокер может получить нижестоящий токен и сохранить цепочку пользователя и рабочего процесса в доверенных утверждениях.

## Ротацию нужно проверить до инцидента

Процедура ротации, которую никто не запускал, остается документацией, а не средством контроля. Команды часто меняют статический ключ так: добавляют второй, повторно развертывают клиенты, наблюдают за ошибками и удаляют первый. Самая ненадежная часть состоит в поиске всех скрытых потребителей до удаления, поэтому общие статические ключи и живут годами.

Если без статических секретов вышестоящего сервиса не обойтись, спрячьте ротацию за брокером и регулярно проверяйте следующую последовательность:

1. Создайте замену с правами не шире прежних.
2. Настройте брокер на распознавание обеих версий, сохранив выпуск тех же узких внутренних возможностей.
3. Переведите новые обращения к вышестоящему сервису на замену и следите за ошибками аутентификации по версии учетных данных.
4. Отзовите старый секрет, затем убедитесь, что синтетический вызов с его отпечатком завершается отказом.
5. Удалите конфигурацию периода перекрытия и запишите, кто завершил ротацию.

Агент не должен замечать эту ротацию. Если контейнеры агентов нужно перезапускать или менять их конфигурацию, долгосрочный секрет пересек нужную границу. Исправьте путь распространения до того, как считать быструю ротацию успехом.

Проведите второе учение для отзыва токена. Запустите задачу агента, выпустите токен, отзовите рабочий процесс или разрешение и проверьте, что следующий вызов отклоняется, даже если срок JWT еще не истек. Самостоятельная проверка JWT может задерживать отзыв, если сервер не использует короткий срок, интроспекцию, список запретов или другой сигнал. Осознанно выберите компромисс для каждой категории риска.

Знакомый сбой выглядит так. Агент поддержки получает ключ поставщика с правом читать и менять все учетные записи. Отладочная трассировка записывает HTTP-заголовок. Трассировка попадает в доступное для поиска хранилище журналов, а ротацию откладывают, потому что этот же ключ используют еще три несвязанные задачи. Редактирование заголовка помогает, но инцидент создала архитектура: общие долгосрочные полномочия попали в процесс с подробной наблюдаемостью.

В исправленной схеме рабочий процесс поддержки доказывает свою личность, получает токен для одного MCP-сервера и одного арендатора, читает по правилам политики и запрашивает привязанное подтверждение для изменения учетной записи. В утекшей трассировке нет токена; украденный токен доступа скоро истекает и не работает вне своей аудитории. Ротация затрагивает подключение брокера к вышестоящему сервису, а не каждого агента.

Проверьте и поведение при сбое. Если выпуск недоступен, агент должен остановиться или продолжить только уже разрешенные операции чтения. Он не должен выбирать более мощные резервные учетные данные, пропускать подтверждение или повторять побочный эффект с неизвестным результатом. Сбой аутентификации должен сокращать полномочия, а не расширять их.

## Журнал аудита должен восстанавливать решение

Полезный журнал аудита отвечает, кто запросил действие, какой рабочий процесс его выполнил, что предложил агент, что разрешила политика, что подтвердил человек, какие учетные данные разрешили вызов и что изменил ресурс. Журнал поставщика с отметкой времени и общим API-ключом отвечает только на самую простую часть.

Передавайте один идентификатор корреляции через запрос пользователя, запуск агента, выпуск токена, подтверждение, вызов MCP-инструмента и результат нижестоящей системы. Храните исходное указание пользователя или защищенную ссылку на него, выбранный инструмент, нормализованные аргументы с удаленными чувствительными значениями, версию политики, дайджест подтверждения, аудиторию и права токена, решение сервера и идентификатор результата.

Структурированное событие может выглядеть так:

```json
{
  "event": "mcp.tool.completed",
  "correlation_id": "corr_01JZ8EYKQ9",
  "run_id": "run_01JZ8F4M2K",
  "workload": "agent:release-orchestrator:v17",
  "subject": "user:1842",
  "tool": "deployments.start",
  "resource": "service:billing-api",
  "decision": "allow",
  "policy_version": "prod-deploy-12",
  "approval_id": "apr_771",
  "request_digest": "sha256:7c1d...9a20",
  "token_audience": "mcp://deployments.prod",
  "token_scopes": ["deployments.start"],
  "result": "deployment:dep_9914"
}
```

Не записывайте токены доступа, токены обновления, коды авторизации, клиентские утверждения, сеансовые cookie или исходные секреты. Хеширование API-ключа с низкой энтропией не делает его безопасным, поскольку злоумышленник может проверять варианты. Используйте выданный эмитентом идентификатор токена, случайную версию учетных данных или отпечаток с ключом, рассчитанный внутри доверенной границы.

Журналам также нужны целостность и контроль доступа. Если скомпрометированный агент может изменить свою историю, журнал не поможет расследованию. Отправляйте события безопасности в хранилище с добавлением записей, ограничьте удаление, фиксируйте административный доступ и задавайте срок хранения по потребностям расследований и требованиям системы, а не сохраняйте все навсегда.

Настройте сигналы на поведение, связывающее механизмы контроля: повтор токена обновления, несовпадение аудитории, серия ответов 403 с последующим запросом более широких прав, подтверждения у границы срока, изменение дайджеста запроса, вызовы после завершения запуска и необычно большое число арендаторов для одного рабочего процесса. Один неудачный вызов может быть шумом. Последовательность часто объясняет намерение.

Проверяйте отказы, а не одни успешные записи. Отказы показывают прощупывание системы, ошибки в картах прав, устаревшие клиенты и попытки агента выполнить операции, которых не требовал план. Они также доказывают работу шлюза, когда нижестоящая система вообще не получила вызов.

## Архитектура продакшена держит долгосрочные полномочия вне агента

Архитектура продакшена должна пропускать каждый вызов с серьезными последствиями через несколько проверяемых переходов. Пользователь или планировщик начинает запуск. Среда выполнения доказывает личность рабочего процесса. Брокер проверяет разрешение и выдает токен доступа с ограниченной аудиторией. MCP-сервер проверяет токен и политику ресурса, при необходимости запрашивает привязанное подтверждение, вызывает нижестоящий инструмент и записывает связанное событие аудита.

Модель участвует в планировании и формировании аргументов. Она не выпускает себе области прав, не помечает собственный вызов безопасным, не обрабатывает учетные данные обновления и не пишет окончательное решение аудита. Эти механизмы находятся в детерминированных сервисах с тестами и ответственными владельцами.

Используйте этот список при проверке каждого рабочего инструмента:

- Может ли сервер различить рабочий процесс, пользователя, арендатора и запуск?
- Предназначен ли токен одному ресурсу и выдает ли он минимально необходимые права?
- Может ли политика ограничить конкретный объект, окружение, сумму или поле?
- Привязано ли подтверждение к итоговому нормализованному запросу и истекает ли после одного применения?
- Позволяет ли один идентификатор корреляции восстановить выпуск, решение, вызов и результат?

Реализуйте пути чтения раньше путей записи, но не считайте чтение безвредным. Исходный код, записи клиентов, журналы и метаданные инфраструктуры могут содержать секреты. Очищайте ответы, ограничивайте диапазоны запросов, следите за границами арендаторов и не давайте агенту запрашивать произвольные адреса через удобный универсальный инструмент.

Публикуйте метаданные авторизации и соблюдайте стандарты. Спецификация авторизации MCP использует метаданные защищенного ресурса и обнаружение сервера авторизации, чтобы клиенты находили правильного эмитента. Обнаружение сокращает объем ручной настройки, но клиенты должны проверять связь с эмитентом, а серверы должны отклонять токены для другого ресурса.

Если нижестоящий поставщик не предлагает альтернативы, статические секреты могут оставаться за брокером. У каждого секрета должны быть один владелец, одно назначение, минимальные права у поставщика, версия, срок ротации и телеметрия использования. Исключение заканчивается на брокере. Оно не оправдывает размещение секрета в переменной окружения агента.

## У статических учетных данных есть узкое исключение

Статические учетные данные допустимы для изолированной локальной интеграции, когда цель не поддерживает OAuth, права невелики, окружение живет недолго и чувствительные данные продакшена недоступны. Даже там создавайте отдельный ключ для каждого рабочего процесса, храните его вне промптов, удаляйте транспортные заголовки из журналов и автоматически уничтожайте ключ вместе с окружением.

В продакшене это исключение быстро перестает работать. Ключ чтения может открыть исходный код, журналы или данные клиентов. Тестовое окружение может использовать общий с продакшеном поставщик идентификации, хранилище артефактов или сетевой путь. Временный агент часто превращается в запланированную задачу. Оценивайте возможные последствия, а не доверяйте ярлыкам «только чтение» и «тестовое окружение».

Не стройте полноценный сервис OAuth только для оболочки вокруг безобидного внутреннего скрипта. Случайная возможность с коротким сроком, которую выдает брокер и проверяет серверная политика, может дать нужные свойства. Цель не в чистоте протокола. Нужно исключить долгосрочные повторно используемые полномочия продакшена из вероятностной среды выполнения, действия которой подробно записываются.

Выбирая между OAuth и статическим секретом, спросите, где происходят отзыв, проверка прав и связывание с исполнителем. Если ответ звучит как «в промпте» или «при следующем развертывании», архитектура не закончена. Уберите долгосрочные полномочия за доверенную границу, выдавайте агенту минимальную возможность для текущего действия и записывайте решение так, чтобы его можно было восстановить без попытки угадать ход мысли модели.
