# Каталог действий AI-агента: найдите ненужный доступ

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

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

Я видел, как проверки разрешений проваливались из-за вопроса: «Нужен ли агенту доступ к биллинговой системе?» На него нельзя честно ответить, пока он сформулирован настолько широко. Спросите, нужно ли агенту прочитать один счет, создать черновик, отправить возврат, изменить платежные реквизиты или выгрузить список клиентов. Ответы обычно будут разными. Именно в этих различиях и обнаруживается лишний доступ.

## Список интеграций скрывает важные разрешения

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

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

Та же ошибка встречается с SSH. Фраза «агент может подключаться по SSH к staging» почти ничего не говорит. Ограниченная команда, которая получает статус сервиса, имеет совсем другие последствия, чем доступ к оболочке учетной записи, способной перезапускать сервисы, читать секреты развертывания или менять правила брандмауэра. Каталог должен описывать семейство команд или endpoint, а не только способ подключения.

Это различие важно, потому что команды часто смешивают три измерения риска:

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

Внутренний endpoint может быть труднодостижимым, но предоставлять очень широкие полномочия. У публичного API может быть широкая достижимость, но ограниченные полномочия. Проектирование подтверждений только по признаку «система внутренняя» не учитывает ни первый, ни второй случай.

В специальной публикации NIST 800-53, контроль AC-6, минимальные привилегии описаны как выдача только того доступа, который нужен для выполнения назначенных задач. Это кажется очевидным, пока не применишь принцип к агенту. «Назначенная задача» не может означать «помогать с разработкой». Речь должна идти об операции с целью, методом, границей и ожидаемым результатом. Если вы не можете это записать, вы не можете утверждать, что применили минимальные привилегии.

Начинайте с названий действий, понятных проверяющему без открытия репозитория. «POST /v1/issues» дает полезное техническое свидетельство, но «создать задачу в инженерном трекере» объясняет владельцу, что именно он подтверждает. Храните обе формулировки в записи.

## Одна строка для одной внешне заметной операции

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

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

| Поле | Что записывать | Зачем это нужно |
|---|---|---|
| ID действия | Стабильный идентификатор, например `deploy.production.restart-service` | Сохраняет решение, даже когда названия меняются |
| Система | Система назначения и среда | Отделяет доступ к production от доступа к тестовой среде |
| Операция | Понятный человеку глагол и объект | Делает разрешение пригодным для проверки |
| Технический маршрут | Метод и путь API, шаблон команды или вызов инструмента | Позволяет инженерам установить границу |
| Идентичность | Тип учетных данных, аккаунт, области видимости и модель делегирования | Показывает общие или чрезмерно широкие полномочия |
| Обрабатываемые данные | Отправляемые входные данные и возвращаемые результаты | Помогает обнаружить риск утечки данных |
| Последствия | Категория последствий и обратимость | Определяет выбор способа подтверждения |
| Владелец | Конкретный человек, принимающий бизнес- или техническое решение | Назначает ответственного за доступ |
| Подтверждение | Нет, для сессии или для каждого вызова | Определяет точку человеческого контроля |
| Свидетельства | Тест, ссылка на журнал или место реализации | Подтверждает соответствие строки реальности |
| Дата проверки | Дата и проверяющий | Не дает старым исключениям стать постоянными |

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

Вот компактный пример для агента разработки:

```yaml
action_id: issue-tracker.create-bug
system: issue tracker, production tenant
operation: Create a bug report in the Engineering project
technical_route: POST /api/projects/engineering/issues
identity: service account agent-issues, scope issues:write
inputs: title, body, labels, repository reference
outputs: issue ID and URL
impact: internal write, reversible by project members
owner: Engineering operations manager
approval: per-session
review_date: 2026-09-30
```

Фраза «production tenant» должна быть в этой строке, даже если действие лишь создает задачи. Многие команды используют один production-тенант SaaS-сервиса для реальной информации о клиентах, сотрудниках и инцидентах. Метка среды показывает проверяющим, какую границу они пересекают.

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

## Ищите действия через учетные данные и рабочие процессы

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

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

Затем двигайтесь от каждой учетной записи назад. Проверьте области видимости API, OAuth-разрешения, роли сервисных учетных записей, авторизованные SSH-ключи, оболочки команд, переменные CI и локальные хранилища секретов. Учетные данные часто показывают операции, о которых никто не упомянул во время обсуждения рабочего процесса. API-токен с областью user administration уже является кандидатом на отдельное действие, даже если команда настаивает, что агент только создает задачи.

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

Используйте такую процедуру из пяти проходов:

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

Именно на четвертом проходе появляются неприятные находки. Вы можете обнаружить старый токен с широкими правами администратора репозиториев, SSH-ключ staging, принимаемый production-хостами, или webhook, который считается «внутренним», но способен запускать релиз. Не уменьшайте запись молча, чтобы она соответствовала первоначальному плану. Добавьте фактически доступную операцию в каталог и попросите кого-то решить, должна ли она остаться.

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

## Последствия важнее общего балла риска

Классифицируйте последствия по тому, что ошибочное действие изменяет, раскрывает, тратит или закрепляет. Единая оценка «высокий, средний, низкий» не работает, потому что скрывает причину, по которой действие требует внимания человека.

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

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

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

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

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

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

## Владельцем должен быть человек, способный сказать «нет»

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

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

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

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

Владелец должен ответить на четыре вопроса:

- Нужен ли агенту этот результат, или рабочему процессу просто так удобнее?
- Можно ли получить результат через более узкий endpoint, роль, аккаунт, цель или команду?
- Какая ошибка создаст неприемлемые последствия?
- Кто должен подтверждать использование и когда это решение должно истечь?

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

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

## Подтверждение должно соответствовать моменту принятия обязательства

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

Используйте в каталоге три состояния подтверждения. «Нет» означает, что действие может выполняться после получения агентом полномочий сессии. «Для сессии» означает, что человек подтверждает конкретный процесс агента до того, как тот начнет вызывать разрешенные действия. «Для каждого вызова» означает, что человек проверяет каждое использование действия.

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

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

В записи подтверждения нужен контекст. Как минимум покажите идентичность вызывающего процесса, операцию, назначение, целевую среду и существенные параметры. Формулировка «агент запрашивает POST» вынуждает человека восстанавливать детали под давлением. «Перезапустить платежный сервис в production, запрос подписанным процессом X» дает информацию, на основании которой можно принять решение.

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

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

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

## Каталог показывает путь к сбою до выхода в production

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

Инженер выдает ему сервисный токен, потому что токен умеет читать журналы. Тот же токен может запрашивать API заказов. Агент находит поврежденный заказ, и ему говорят «почистить тестовые данные». Он вызывает endpoint удаления для production-тенанта, потому что интеграция не различала названия сред. Endpoint принимает запрос. Позже человек понимает, что заказ был настоящим, но его восстановление требует сверки платежной, складской систем и службы поддержки.

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

| Операция | Скрытая проблема | Лучшее решение |
|---|---|---|
| Читать журналы рабочего процесса заказа | В журналах есть идентификаторы клиентов | Ограничить возвращаемые поля и зафиксировать последствия раскрытия |
| Запросить заказ по ID | У токена широкий доступ к заказам | Использовать идентичность только для чтения с ограничением нужным тенантом |
| Удалить тестовый заказ | Production и тест используют одно семейство endpoint | Разделить целевые среды и требовать подтверждение для каждого вызова |
| Исправить заказ клиента | Это не очистка данных | Передать владение операционной команде и убрать действие из области агента |

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

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

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

## Сделайте каталог применимым на практике и проверьте его соответствие реальности

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

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

Для HTTP-вызовов проверяйте метод, хост, шаблон пути, целевую среду и область видимости учетных данных. Для SSH проверяйте аккаунт, группу хостов, ограничения команд и возможность передачи произвольных аргументов вспомогательному процессу. Формулировка «SSH-доступ одобрен» не задает исполнимую границу.

Например, эта запись каталога утверждает, что агент может только получать статус развертывания:

```text
Action ID: deploy.status.read
Host: deploy.internal.example
Command: deployment-status --service <approved-service>
Identity: agent-deploy-read
Approval: per-session
```

Эта реализация опровергает утверждение:

```sh
command="/usr/local/bin/deployment-status $SSH_ORIGINAL_COMMAND" ssh-ed25519 AAAA... agent
```

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

```sh
case "$1" in
  checkout) exec /usr/local/bin/deployment-status --service checkout ;;
  search) exec /usr/local/bin/deployment-status --service search ;;
  *) echo "service not permitted" >&2; exit 1 ;;
esac
```

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

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

Sallyport записывает сессии агентов и отдельные вызовы в единый зашифрованный журнал аудита, связанный хешами. Команда `sp audit verify` может проверять эту цепочку офлайн по шифротексту, без доступа к ключу хранилища. Такие свидетельства помогают сопоставить каталог с фактическим поведением, но не заменяют решение удалить ненужное действие.

## Проверяйте доступ при изменении работы, а не после квартального сюрприза

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

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

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

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