Практическое руководство

Как ограничить права инструментов AI-агента

Уровень: средний Чтение: до 8 минут Результат: минимальные права и журнал разрешений

Зачем ограничивать инструменты отдельно

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

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

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

1. Составьте карту действий

Начните не с ролей, а с операций, которые действительно нужны сценарию.

Инструмент Необходимое действие Не выдавать по умолчанию
Файлы Чтение ./workspace/input/, запись в ./workspace/output/ Доступ к домашнему каталогу, секретам и системным файлам
API GET /v1/tasks POST, PUT, PATCH, DELETE и другие адреса
Команды Одна утилита с фиксированным набором аргументов Оболочка, перенаправления, конвейеры и произвольные программы

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

2. Введите запрет по умолчанию

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

policy:
  default: deny
  unknown_tools: deny
  on_policy_error: deny

tools:
  filesystem:
    enabled: true
  http:
    enabled: true
  process:
    enabled: true

on_policy_error: deny задаёт безопасное поведение при повреждённой или неполной конфигурации. Если ваша платформа не поддерживает такой параметр, обеспечьте тот же результат на уровне запуска: агент не должен стартовать при ошибке загрузки политики.

3. Разделите чтение и запись файлов

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

tools:
  filesystem:
    read:
      roots:
        - ./workspace/input
      extensions:
        - .json
        - .txt
      follow_symlinks: false

    write:
      roots:
        - ./workspace/output
      extensions:
        - .json
      overwrite: false

    deny:
      patterns:
        - "**/.env"
        - "**/.git/**"
        - "**/*secret*"
        - "**/*credential*"

Проверяйте путь после его нормализации, а не только исходную строку. Запись вида ./workspace/input/../../private.txt не должна обходить ограничение каталога. Символические ссылки лучше запретить, если они не требуются сценарию.

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

4. Ограничьте API по адресу, методу и назначению

Сетевой инструмент не должен принимать произвольный URL. Разрешите конкретный узел, HTTPS, нужные пути и методы. Токен храните вне промпта и подставляйте на стороне шлюза.

tools:
  http:
    allow:
      - origin: https://api.internal.example
        methods:
          - GET
        paths:
          - /v1/tasks
        max_response_bytes: 1048576

    redirects: deny
    private_networks: deny
    credentials:
      source: runtime_secret_store
      expose_to_model: false

Домен api.internal.example здесь является зарезервированным примером и должен быть заменён вашим реальным разрешённым адресом. Если агенту нужна изменяющая операция, выделите её отдельным инструментом и потребуйте подтверждение перед вызовом:

approval:
  required_for:
    - tool: task_update
      methods:
        - POST
        - PATCH
        - DELETE
  expires_after_seconds: 300
  bind_to:
    - tool
    - method
    - resource_id
    - arguments_hash

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

5. Не передавайте агенту полноценную оболочку

Разрешение bash -c, sh -c или аналогичной команды превращает список разрешённых программ в формальность: оболочка может запускать другие процессы, читать файлы и перенаправлять вывод. Предпочтительнее отдельные типизированные инструменты.

tools:
  process:
    shell: false
    allow:
      - executable: /usr/bin/jq
        arguments:
          - "--compact-output"
          - "--monochrome-output"
        input:
          source: stdin
          max_bytes: 1048576
    environment:
      inherit: false
      allow:
        - LANG
    timeout_seconds: 10
    network: false
    working_directory: ./workspace/output

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

6. Добавьте журнал разрешений

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

audit:
  enabled: true
  destination: ./logs/agent-permissions.jsonl
  events:
    - permission_requested
    - permission_allowed
    - permission_denied
    - approval_requested
    - approval_granted
    - tool_completed
    - tool_failed
  redact_fields:
    - authorization
    - cookie
    - api_key
    - token
    - file_content
  include:
    - timestamp
    - run_id
    - agent_id
    - tool
    - action
    - resource
    - decision
    - policy_rule
    - approval_id
    - result_status

Пример одной записи журнала:

{
  "timestamp": "2026-01-15T10:30:00Z",
  "run_id": "example-run",
  "agent_id": "report-agent",
  "tool": "filesystem",
  "action": "read",
  "resource": "./workspace/input/tasks.json",
  "decision": "allow",
  "policy_rule": "filesystem.read.input",
  "approval_id": null,
  "result_status": "completed"
}

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

Проверка результата

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

  1. Попросите агента прочитать тестовый .json внутри ./workspace/input/. Ожидаемый результат: чтение разрешено и отражено в журнале.
  2. Запросите чтение файла за пределами разрешённого корня. Ожидаемый результат: отказ до обращения к файлу, в журнале указано правило запрета.
  3. Проверьте путь с ../ и символическую ссылку наружу. Ожидаемый результат: отказ после нормализации пути.
  4. Попробуйте перезаписать существующий файл в каталоге вывода. При overwrite: false ожидается отказ.
  5. Запросите POST вместо разрешённого GET, другой путь, другой узел и перенаправление. Все четыре варианта должны быть отклонены.
  6. Передайте команде незаявленный аргумент или запросите другую программу. Ожидаемый результат: процесс не запускается.
  7. Вызовите действие, требующее подтверждения, сначала без него, затем с подтверждением для других аргументов. Оба вызова должны быть отклонены.
  8. Просмотрите журнал: разрешения и отказы присутствуют, но токены, заголовки авторизации и содержимое файлов отсутствуют.

Если невозможно отличить «инструмент не вызывался» от «инструмент вызван и получил отказ», аудит недостаточен. Эти состояния должны иметь разные события.

Типовые ошибки

Один токен администратора для всех инструментов
Компрометация одного вызова открывает весь API. Выпускайте отдельные учётные данные с минимальными областями действия и ограниченным сроком жизни.
Проверка только имени команды
Без проверки аргументов разрешённая программа может читать неожиданные файлы или выполнять опасные операции. Валидируйте исполняемый файл, аргументы, рабочий каталог, окружение и лимиты.
Общий каталог для входа и выхода
Агент может изменить собственные исходные данные или подменить файл для следующего шага. Разделяйте каталоги и запрещайте перезапись по умолчанию.
Разрешение домена без ограничения путей и методов
Доступ к безопасному чтению незаметно становится доступом к административным операциям. Политика должна учитывать всю комбинацию: протокол, узел, путь и HTTP-метод.
Подтверждение без привязки к аргументам
Агент может заменить объект или параметры после согласия пользователя. Подписывайте или хешируйте нормализованный набор аргументов подтверждённого вызова.
Секреты в промпте и журнале
Модель не должна видеть токен, если его может добавить доверенный прокси. Маскирование выполняйте до записи события, а не при последующем просмотре.
Политика разрешает действие при внутренней ошибке
Ошибка парсинга, неизвестный инструмент или недоступный сервис подтверждений должны приводить к отказу, а не к обходу проверки.

Ограничения подхода

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

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

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

Итоговая проверочная карта

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

Другие практические материалы собраны в разделе руководств, а определения терминов — в глоссарии.