Permission model для AI-tools: least privilege на практике
Каждый вызов привязан к задаче и пользователю
Объект и эффект проверяются сервером
Авторская схема PERMIT-7 и синтетический тикет
Ошибки, тесты и production-контроль

$ permit --contract PERMIT-7
> bind: actor / tenant / task
> gate: tool / target / effect
> route: allow / review / denyМодель может предложить вызов инструмента, но не должна назначать себе права. Permissions для AI agents — это проверка каждого вызова по подтверждённому пользователю, tenant, задаче, объекту и разрешённому действию. Материал разбирает именно эту границу. Общий запрос на AI-специалиста в Армении ведёт на отдельную страницу.
Ниже — авторская схема PERMIT-7 и синтетический пример поддержки: агент читает один разрешённый тикет и готовит черновик ответа. Это проектная схема, не описание внедрения клиента и не измеренный результат. Смежные материалы: схемы инструментов, безопасность MCP-сервера и sandbox агента.
Проблема и требования
Каталог может содержать read_ticket, update_ticket и send_reply. Общий сервисный токен превращает ошибку prompt в потенциальное чтение чужого tenant или отправку сообщения. Запрет в prompt не заменяет проверку в целевой системе. Сервер обязан авторизовать каждый вызов, включая повторные попытки.
Разделите эффекты: чтение тикета, создание черновика, изменение статуса и отправка ответа требуют разных прав. Для каждого укажите объект, поля, цель, срок действия и необходимость ручного согласования. При неизвестной личности, устаревшей политике или невозможности подтвердить владельца объекта — отказ.
Архитектура PERMIT-7
| Шлюз | Контракт | Проверка |
|---|---|---|
| 1. Пользователь | подтверждённый actor и tenant | сессия или делегированная личность |
| 2. Задача | цель и срок действия | ID задачи и scope |
| 3. Инструмент | точное имя и версия | запись каталога |
| 4. Объект | ID разрешается сервером | владелец и ACL |
| 5. Эффект | read, draft, update или send | отдельное полномочие |
| 6. Согласование | человек для значимой записи | receipt для точного действия |
| 7. Результат | проверка в целевой системе | receipt или неизвестный исход |
Оркестратор передаёт проверенную личность policy engine. Модель передаёт только предлагаемые аргументы. Доверенный адаптер разрешает ID тикета, проверяет доступ и выполняет действие из allowlist. Токен, tenant и произвольный URL из аргументов модели не принимаются. Итоговая система также проверяет собственные права.
Синтетическая политика
actor: support-agent-user-42
tenant: example-tenant
purpose: draft_reply
resource: ticket:784
allow:
- ticket.read
- reply.draft
expires_at: 2026-09-26T18:00:00Z
requires_human_for:
- reply.send
- ticket.updateМанифест иллюстрирует контракт, а не готовую production-конфигурацию. В реальной системе личность приходит из доверенного источника, а ACL проверяется в момент вызова. Запрос модели на reply.send этот манифест не разрешает.
Компоненты и путь исполнения
Каталог публикует узкие схемы инструментов. Валидатор отклоняет неизвестные поля, некорректные ID и списки без лимитов. Политика совместно проверяет actor, tenant, цель, объект и эффект. Сервис согласования связывает решение человека с точным действием и хешем payload. Адаптер применяет короткоживущий делегированный токен либо собственную ограниченную личность и фиксирует результат в целевой системе. Логи хранят идентификаторы и решения, а не чувствительный текст тикета.
// Псевдокод: actor и tenant сервер получает вне модели.
const proposal = toolSchema.parse(modelCall.arguments);
const target = await ticketStore.resolve(proposal.ticketId);
const decision = await policy.evaluate({ actor, tenant, taskId, target, effect: "reply.draft" });
if (!decision.allowed) return deny(decision.reason);
const draft = await adapter.createDraft(target, proposal.body, requestId);
return verifyDraftAtDestination(draft.id, requestId);Для reply.send нужен отдельный этап согласования получателя и точного текста. Непосредственно перед отправкой права проверяют снова: пока черновик ожидал согласования, доступ мог измениться. Idempotency key и receipt уменьшают риск дубля, но неизвестный результат сначала сверяют в целевой системе.
Ошибки и failure modes
| Ошибка | Риск | Маршрут |
|---|---|---|
| Модель указывает тикет другого tenant | чтение чужих данных | отказ по ACL на сервере |
| Alias инструмента ведёт к более широкому действию | нежелательная запись | версия каталога и точный effect |
| Согласование относится к старому черновику | отправка изменённого текста | hash payload в approval |
| Роль отозвана после планирования | устаревшее разрешение | повторная проверка перед действием |
| Timeout после отправки | дубль при повторе | сверка receipt в целевой системе |
| В лог попадает полный текст тикета | утечка данных | редакция и срок хранения |
Изоляция процесса не заменяет авторизацию данных. Sandbox ограничивает код, файлы и сеть; политика PERMIT-7 определяет допустимый бизнес-объект и эффект.
Тестирование и production-чек
Проверьте разрешённое чтение, отказ для чужого tenant, лишние поля, устаревшую политику, истёкшую задачу, отозванную роль, изменённый после согласования черновик и повтор после неопределённой записи. Проверяйте ответ API и состояние целевой системы. Добавьте документ с вредоносной инструкцией вызвать более широкий инструмент: шлюз всё равно должен отказать.
Перед production инвентаризируйте инструменты и эффекты, назначьте владельцев политики, определите пороги согласования, срок хранения аудита, оборот ограниченных учётных данных и процедуру отзыва прав. Отслеживайте отказы, несовпадения approval и неизвестные исходы как сигналы эксплуатации, без выдуманных показателей. Prompt engineering помогает сузить предложения модели, AI-автоматизация — выстроить workflow. Для архитектурного ревью свяжитесь с командой.
const target = await store.resolve(proposal.ticketId);
const decision = await policy.evaluate({ actor, tenant, taskId, target, effect });
if (!decision.allowed) return deny(decision.reason);
return verifyAtDestination(await adapter.executeOnce(target, requestId));