中文翻译暂不可用,显示俄语原文。

Как проектировать agent permissions (least privilege модель)?

Краткий тезис

Проектирование разрешений для AI-агентов строится на принципе наименьших привилегий (least privilege) — агент получает ровно столько доступа, сколько необходимо для выполнения конкретной задачи, и не больше. Ключевые механизмы: динамическое ограничение области (dynamic scoping) на уровне сессии и вызова, использование OAuth2- и JWT-токенов с ограниченным временем жизни, а также Human‑in‑the‑Loop (HITL) для опасных операций. Правильная модель permissions предотвращает утечки данных, несанкционированные действия и эскалацию привилегий через цепочки вызовов инструментов.


1. Термин: Agent permissions (разрешения агента)

Agent permissions — это набор прав, определяющих, какие инструменты (API, базы данных, файловые системы, внешние сервисы) может вызывать агент, какие данные он может читать/писать и в каких контекстах (сессиях, запросах) эти права действуют.

В отличие от традиционных RBAC (Role‑Based control|Access Control), где права привязаны к статической роли пользователя, агентская модель требует динамичности: один и тот же агент в разных сессиях может иметь разные разрешения в зависимости от запроса, доверенности пользователя и этапа выполнения задачи.

Термин «Least privilege» (наименьшие привилегии) — агент получает минимально необходимые права для выполнения текущего шага, а не максимально возможные.


2. Зачем нужна separate permission модель для агентов?

Без явного управления permissions агенты быстро становятся векторами атак:

РискПример
Утечка данныхАгент читает все документы, хотя нужен только один
Несанкционированная записьАгент изменяет профиль другого пользователя
Эскалация привилегийАгент вызывает инструмент, который сам вызывает другой инструмент с более широкими правами
Цепочка действийАгент удаляет файл, а потом не может его восстановить, потому что права были временными

Правильная модель permissions позволяет:

  • Ограничить ущерб в случае компрометации агента (например, через prompt injection)
  • Аудить каждое действие агента
  • Динамически расширять/сужать права в зависимости от контекста

3. Принцип Least Privilege для агентов

Least privilege для агентов — это не просто «дать минимум прав при старте». Это continuous enforcement на каждом шаге:

  1. Минимальный набор инструментов — агент получает только те инструменты, которые прописаны в его конфигурации для данной задачи.
  2. Минимальные данные — агент видит только те документы/записи, которые релевантны запросу (фильтрация на уровне retrieval).
  3. Минимальная область влияния — агент может изменять только объекты, принадлежащие текущему пользователю или сессии.

Пример: агент поддержки клиентов

  • Разрешено read:tickets (только свои тикеты), write:notes (только заметки в своём тикете)
  • Запрещено read:user_profiles, write:status (изменение статуса тикета — только через HITL)

4. Dynamic scoping — ключ к гибкости

Dynamic scoping — механизм, при котором разрешения определяются не статически (на уровне агента), а динамически на основе:

  • Сессии пользователя — права привязаны к идентификатору сессии
  • Запроса — из запроса извлекаются параметры (например, user_id, document_id)
  • Вызова инструмента — каждый вызов получает свежий токен с ограниченным временем

Уровни dynamic scoping:

УровеньОписаниеПример
Session‑levelПрава действуют только в пределах одной сессии (диалога)Агент может читать документы, загруженные в эту сессию
Request‑levelПрава действуют только на время обработки одного запросаПосле ответа токен инвалидируется
Call‑levelПрава действуют только на один вызов инструментаКаждый вызов API получает одноразовый токен

Реализация передача scoped‑токена в каждом вызове инструмента через context (например, в LangGraphState).


5. Типы scopes (областей доступа)

Scopes (или scope tokens) — строковые идентификаторы, описывающие разрешения. Рекомендуется следовать синтаксису action:resource: read:documents, write:user_profile_own.

Примеры типовых scopes для агента:

ScopeОписаниеКогда использовать
read:documentsЧтение документов из векторного хранилищаДля retrieval‑агентов
write:user_profile_ownЗапись только в свой профильАгент‑помощник, редактирующий профиль
send:emailОтправка email (с HITL)Агент‑коммуникатор
execute:code_sandboxЗапуск кода в изолированной средеАгент‑программист
read:knowledge_base_kb42Чтение только из конкретной базы знанийДля агента по продукту X

Правила именования

  • {action}:{resource} — широкий scope
  • {action}:{resource}_{sub_resource} — более узкий
  • {action}:{resource}?filter=owner_id — с фильтром по владельцу (dynamic scoping)

6. Human‑in‑the‑Loop (HITL) как разновидность permissions

Human‑in‑the‑Loop — обязательное подтверждение человека перед выполнением опасного действия. Это не отдельный scope, а gate (шлюз) на уровне runtime.

Примеры действий, требующих HITL:

  • Отправка email от имени пользователя
  • Удаление файлов
  • Создание пользователей с повышенными правами
  • Выполнение денежных транзакций

Реализация

# Псевдокод: вызов инструмента с HITL
tool_call = {
    "tool": "send_email",
    "params": {...},
    "scope": "send:email",
    "hitl_required": True
}
# Runtime приостанавливает выполнение, ждёт подтверждения от человека
response = await hitl_approve(tool_call)

Важно HITL не должен быть единственным барьером — scope всё равно должен быть минимальным (например, send:email только на свой домен).


7. Реализация: OAuth2 Scopes и JWT

Современные агенты обычно развёрнуты как микросервисы. Протокол OAuth2 с JWT (JSON Web Tokens) — стандарт де‑факто для передачи scopes.

Процесс:

  1. Аутентификация пользователя — получает access_token с базовыми scopes (например, role:user).
  2. Инициализация сессии агента — агент получает свой собственный JWT, подписанный сервером, с ограниченным временем жизни (TTL) и scopes, унаследованными от пользователя, но суженными до необходимого минимума.
  3. Каждый вызов инструмента — передаёт JWT, сервер проверяет:
    • Подпись (не подделан)
    • Срок действия (не истёк)
    • Scope содержит action:resource для данного вызова
  4. Возврат результата — токен не обновляется, после завершения сессии он теряет силу.

Пример структуры JWT (payload):

{
  "sub": "agent_session_abc123",
  "user_id": "user_42",
  "scopes": ["read:documents_owned", "write:notes_own"],
  "iat": 1717000000,
  "exp": 1717003600,
  "context": {
    "session_id": "session_789",
    "max_documents_read": 10
  }
}

Дополнительные фичи

  • One‑time tokens — для call‑level scoping (токен можно использовать только один раз)
  • Token binding — привязка к конкретному агенту (проверка client_id)

8. Аудит и мониторинг permissions

Даже идеальная модель permissions бесполезна без логирования. Каждый вызов инструмента должен записывать:

  • ID сессии, пользователя, агента
  • Запрошенный scope
  • Результат проверки (allowed / denied)
  • Время жизни токена

Инструменты: OpenTelemetry для трассировки, ELK Stack для анализа логов.

Пример структуры лога:

{
  "timestamp": "2025-05-20T12:00:00Z",
  "agent_id": "agent_support_v3",
  "session_id": "sess_001",
  "user_id": "u_42",
  "tool": "read:documents",
  "resource": "doc_123",
  "scope_used": "read:documents_owned",
  "allowed": true,
  "decision_source": "JWT scope check"
}

9. Best practices и частые ошибки

Best practices:

  • Используйте принцип «Deny by default» — всё, что не разрешено явно, запрещено.
  • Передавайте scope через контекст (state), а не через глобальные переменные.
  • Минимизируйте время жизни токена — 15–30 минут максимум для session‑level, 1 минута для call‑level.
  • Регулярно ревьюите набор инструментов — удаляйте неиспользуемые.
  • Тестируйте эскалацию привилегий — напишите тесты, где агент пытается вызвать инструмент с чужим ресурсом.

Частые ошибки:

ОшибкаПоследствие
Слишком широкий scope (например, read:*)Агент читает все данные, включая чужие
Статический scope без dynamic scopingНевозможно ограничить по владельцу
Долгоживущие токены (часы/дни)При утечке токена злоумышленник получает доступ на долгое время
Отсутствие HITL для опасных операцийАгент может удалить всё
Игнорирование контекста вызова (один scope для всех инструментов)Потеря гранулярности

10. Интеграция с agentic framework

Пример на LangGraph (концептуально):

class AgentState(TypedDict):
    session_id: str
    user_id: str
    scopes: list[str]  # динамический список

def get_token_for_tool(state: AgentState, tool_name: str) -> dict:
    """Генерирует или достаёт временный JWT для вызова инструмента."""
    return {
        "tool": tool_name,
        "scopes": get_scopes_for_tool(state["scopes"], tool_name),
        "exp": time.time() + 60
    }

def call_tool(state: AgentState, tool_call: dict) -> dict:
    token = get_token_for_tool(state, tool_call["tool"])
    # Валидация на стороне сервера инструмента
    result = actual_tool_invoke(tool_call, token=token)
    return result

11. Сравнение с традиционными RBAC

ХарактеристикаRBAC (статическая роль)Agent Permissions (динамическая)
ГранулярностьРоль → набор разрешенийScope + dynamic scoping + сессия
ИзменяемостьТолько через админ‑панельАвтоматически на основе запроса
Время жизниПостоянноСессия / вызов / запрос
Поддержка HITLНет (обычно)Встроенный механизм
АудитЛоги входа/выходаЛог каждого вызова инструмента

Пет-проект для закрепления

Задача Создать микросервис‑агента, который помогает пользователю управлять личными заметками, но не может читать/писать чужие заметки.

Инструменты

Шаги:

  1. Спроектировать API заметок — CRUD, поле owner_id = user_id.
  2. Реализовать OAuth2 flow — пользователь логинится, получает JWT с user_id и role.
  3. Создать агента — два инструмента: read_note(note_id) и write_note(note_id, content). Каждый инструмент принимает JWT текущей сессии.
  4. Добавить dynamic scoping — в JWT добавить scope notes:own и ограничить доступ по owner_id:
    def read_note(note_id: str, token: dict):
        if "notes:own" not in token["scopes"]:
            raise PermissionDenied
        note = db.query(note_id)
        if note.owner_id != token["user_id"]:
            raise PermissionDenied
        return note
    
  5. Добавить HITL для удаления заметки — запрос подтверждения.
  6. Написать тесты:
    • Пользователь A не может прочитать заметку пользователя B
    • Токен с истекшим сроком отклоняется
    • Запрос на удаление приостанавливается до подтверждения

Ожидаемый результат Работающий агент, который строго соблюдает least privilege. Вы сможете продемонстрировать на собеседовании понимание механизмов JWT, dynamic scoping и HITL.


Связь с другими вопросами

ВопросТема
888Инструменты и API для агентов
889Память и контекст агента
890Наблюдаемость агентов (traces, logs)
891Безопасность агентских систем
124Prompt injection и mitigation (пересечение с разрешениями)

Навигация