microsrv:~$
Консоль

← Все записи

Песочницы для AI-агентов: почему одного контейнера недостаточно

Опубликовано•17 мин чтения

Песочницы для AI-агентов: почему одного контейнера недостаточноПесочницы для AI-агентов: почему одного контейнера недостаточно

AI-агент, который умеет писать код, рано или поздно начинает его запускать. Сначала это безобидный python -c, затем — npm install, docker build и, возможно, terraform apply. Команды генерирует модель, а выполняются они на вашей инфраструктуре, где могут оказаться секреты, доступ к внутренним сервисам и другие ценные данные.

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

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

В microsrv такую песочницу можно создать за 5–10 секунд. Если включён режим сохранения состояния, виртуальная машина засыпает в период простоя и, по данным платформы, пробуждается за 100–250 мс.

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


1. Что происходит, когда AI-агент получает доступ к терминалу

Разница между агентом, который только предлагает решения, и агентом, который самостоятельно меняет систему, может сводиться к одному инструменту — shell.

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

Ошибки и непредсказуемые действия. Модель может неверно понять задачу, выбрать неподходящую команду или не учесть последствия. Вместо rm -rf ./build она, например, может выполнить более разрушительную команду с неверно указанным путём. Для этого не требуется злого умысла: достаточно ошибки.

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

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

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

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


2. От чего должна защищать песочница

Контейнеры используют пространства имён Linux (namespaces), контроль ресурсов через cgroups и дополнительные ограничения, например seccomp. Эти механизмы помогают изолировать процессы, ограничивать их возможности и распределять ресурсы.

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

Рассмотрим четыре сценария, которые стоит учитывать при проектировании песочницы.

Уязвимость в ядре Linux

В 2022 году была обнаружена уязвимость Dirty Pipe (CVE-2022-0847). При определённых условиях она позволяла изменять данные в кэше страниц и перезаписывать содержимое файлов, доступных только для чтения.

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

Уязвимость в среде выполнения контейнеров

Проблемы могут возникать не только в ядре, но и в компонентах, которые запускают контейнеры. Например, CVE-2019-5736 затрагивала runc — среду выполнения контейнеров. При определённых условиях уязвимость позволяла перезаписать исполняемый файл runc на хосте и добиться выполнения кода с привилегиями хоста.

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

Чрезмерные привилегии

Иногда для побега не нужна уязвимость. Достаточно слишком широких разрешений.

Например, запуск с --privileged, предоставление доступа к /var/run/docker.sock или выдача опасных возможностей, таких как CAP_SYS_ADMIN, могут существенно ослабить изоляцию. Конкретные последствия зависят от конфигурации, но в некоторых случаях процесс получает возможность управлять контейнерами или воздействовать на хост.

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

Доступ к внутренней сети и секретам

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

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

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

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


3. Контейнеры, gVisor и KVM: в чём разница

У этих подходов разные границы изоляции и разная цена их использования.

Критерий Docker / containerd gVisor KVM
Ядро Общее ядро хоста Пользовательское ядро Sentry Собственное ядро гостевой ОС
Обработка системных вызовов Ядром хоста В основном Sentry, с передачей отдельных операций хосту Гостевым ядром
Основная граница изоляции Механизмы Linux и настройки контейнера Sentry, дополнительные механизмы изоляции и настройки Гипервизор, виртуальные устройства и конфигурация ВМ
Совместимость Высокая для обычных Linux-приложений Высокая для поддерживаемых сценариев, но не полная Обычно близка к обычной Linux-машине
Время запуска Часто менее секунды Часто порядка 1–2 секунд В microsrv — около 5–10 секунд
Расход памяти Низкий Низкий, зависит от нагрузки Выше из-за гостевой ОС и её ядра
Основные риски Уязвимости ядра, рантайма и ошибочные настройки Уязвимости Sentry, интерфейсов взаимодействия с хостом и ошибочные настройки Уязвимости гипервизора, виртуальных устройств и ошибочные настройки

Приведённые сроки запуска — ориентиры, а не универсальные показатели: они зависят от образа, оборудования, конфигурации и способа запуска.

gVisor: дополнительная изоляция без полноценной виртуальной машины

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

Это уменьшает объём кода хостового ядра, с которым непосредственно взаимодействует приложение. Для веб-сервисов и многих задач на Python или Node.js такого подхода достаточно, при этом контейнеры остаются сравнительно лёгкими.

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

KVM: отдельное ядро для каждой песочницы

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

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

Для недоверенного кода это существенное преимущество, особенно когда ему нужны широкие права внутри гостевой системы.

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


4. Почему агенту может понадобиться полноценный Linux

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

Для этого могут понадобиться:

  • apt и системные пакеты — для установки зависимостей;
  • gcc, cargo, go build, node-gyp — для сборки программ;
  • systemd — для запуска и управления службами;
  • Docker — для сборки и проверки образов;
  • mount, FUSE и отдельные операции ioctl — для работы с файловыми системами и устройствами;
  • доступ к параметрам ядра или модулям — при отладке низкоуровневого ПО.

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

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

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

В виртуальной машине агент получает обычное ядро Linux и может выполнять большинство задач, доступных администратору гостевой системы. Например, Docker можно установить и использовать внутри гостя без необходимости предоставлять контейнеру прямой доступ к Docker-демону хоста.

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


5. Жизненный цикл песочницы в microsrv

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

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

Создание: готовая виртуальная машина за 5–10 секунд

Виртуальную машину можно создать через консоль microsrv, API или инфраструктурный код. По данным платформы, типичное время запуска составляет 5–10 секунд.

Начальную настройку удобно автоматизировать с помощью cloud-init. Например, при первом запуске можно установить Docker, компиляторы и инструменты для работы с Python.

#cloud-config
package_update: true
packages:
  - docker.io
  - build-essential
  - python3-pip
runcmd:
  - systemctl enable --now docker
  - usermod -aG docker ubuntu

Это пример базовой настройки, а не универсальная конфигурация для всех образов. Имена пользователей и пакетов могут отличаться. Если агенту действительно нужен Docker, следует также учитывать, что членство в группе docker обычно даёт широкие полномочия внутри гостевой системы.

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

Для административного доступа используется SSH-шлюз, позволяющий подключаться по стабильному имени:

ssh agent@<sandbox>.msrv.space

При этом не нужно открывать SSH-порт самой виртуальной машины всему интернету.

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

Между шагами агента: сохранить состояние и освободить ресурсы

Работа агента обычно состоит из нескольких этапов: получить задачу, прочитать код, выполнить команды, дождаться результатов, проанализировать их и продолжить работу. Между этими этапами виртуальная машина может простаивать.

Вместо того чтобы держать её постоянно включённой, в microsrv можно использовать бессерверный режим с сохранением состояния.

В бессерверном режиме, состояние виртуальной машины сохраняется, чтобы его можно было восстановить при пробуждении. По данным microsrv, пробуждение занимает около 100–250 мс. Фактическая задержка может зависеть от состояния машины и инфраструктуры.

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

Подробнее механизм описан в статье о бессерверных виртуальных машинах.

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

Долгие задачи и живая миграция

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

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

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

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

Удаление: завершить задачу и убрать временную среду

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

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

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

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

Управление песочницами через OpenTofu

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

Например:

resource "microsrv_vm" "sandbox" {
  project_id            = microsrv_project.prod.id
  region_id             = data.microsrv_region.central.id
  flavor_id             = data.microsrv_flavor.std.id
  class                 = "shared"
  name                  = "agent-sandbox-${var.task_id}"
  boot_volume_id        = microsrv_volume.boot_disk.id
  network_interface_ids = [microsrv_network_interface.eth0.id]
  ssh_key_ids           = [microsrv_ssh_key.deployer.id]
  volume_ids            = [microsrv_volume.data_disk.id]
  serverless            = true
}

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

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


6. Агент и песочница — не одно и то же

В статье про Hermes Agent мы разворачивали самого агента в контейнере: использовали готовый образ, сохраняли состояние на отдельном томе и публиковали панель управления через HTTPS-шлюз.

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

AI-агент как сервис Песочница для выполнения кода
Что запускается Сам агент и его инструменты Код, который агент получил или сгенерировал
Время жизни Постоянная работа с сохранением состояния Обычно одна задача или ограниченная сессия
Основные требования Доступность, состояние, экономичность Изоляция, совместимость, ограниченный срок жизни
Подходящая среда Контейнер с дополнительной изоляцией, например gVisor KVM-виртуальная машина для более строгой изоляции

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

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

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

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


7. Чек-лист безопасности для песочниц AI-агентов

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

  1. По возможности используйте отдельную песочницу для каждой задачи. Не переносите между независимыми задачами файлы, процессы и учётные данные без необходимости.
  2. Не храните долгоживущие секреты внутри песочницы. Передавайте только те данные, которые нужны для конкретной задачи, и по возможности ограничивайте срок их действия.
  3. Устанавливайте срок жизни среды. Автоматически удаляйте забытые песочницы и проверяйте, что очистка действительно завершилась.
  4. Не открывайте входящие порты без необходимости. Для административного доступа используйте SSH-шлюз, а публичные приложения публикуйте через подходящий шлюз с аутентификацией.
  5. Ограничивайте исходящие соединения. Если задаче не нужен интернет, запретите выход в сеть. Если нужен, разрешайте только необходимые направления, где это возможно.
  6. Не предоставляйте доступ к хостовым ресурсам. Не подключайте к песочнице Docker-сокет хоста, домашние каталоги или ключи, которые не нужны для задачи.
  7. Храните журналы за пределами песочницы. Команды, сетевые обращения и важные события лучше записывать во внешнюю систему, к которой исполняемый код не может изменить доступ.
  8. Продумайте управление ресурсами. Ограничивайте процессорное время, память, размер диска и длительность задачи, чтобы агент не мог бесконтрольно расходовать ресурсы.
  9. Отделите права на выполнение кода от прав на управление инфраструктурой. Агенту, который запускает тесты, не обязательно давать возможность создавать и удалять любые виртуальные машины в проекте.
  10. Проверяйте очистку после выполнения. Убедитесь, что удаляются не только виртуальная машина, но и ненужные диски, временные файлы и выданные на время задачи полномочия.

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


8. Когда виртуальная машина оправдана, а когда достаточно контейнера

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

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

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

KVM особенно полезен, когда:

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

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

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


Итоги

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

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

В microsrv можно создавать такие машины за 5–10 секунд, автоматически настраивать их через cloud-init, сохранять состояние в период простоя и удалять после завершения задачи.

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


Источники и материалы

FAQ

Можно ли обойтись одним контейнером gVisor?

Да, если агент выполняет обычные задачи на Python или Node.js и не нуждается в неподдерживаемых системных возможностях. gVisor обеспечивает дополнительную изоляцию по сравнению с обычным контейнером. Виртуальная машина предпочтительнее, если требуется собственное ядро, запуск Docker с широкими системными полномочиями или более строгая граница между исполняемым кодом и хостом.

Насколько дорого создавать виртуальную машину для каждой задачи?

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

Если сам агент работает в контейнере, почему бы не запускать код там же?

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

Что помешает агенту удалить песочницу или данные других задач?

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

Запускайте serverless виртуалки, контейнеры и базы данных

microsrv обеспечивает мгновенный старт виртуальных машин и контейнеров, быстрые СУБД на NVMe, а VPC и шлюзы доступа уже включены в стоимость.

Перейти в консольЗадать вопрос