ИИ-агенты и автоматизация

Изоляция ИИ-агента: почему Docker недостаточно

Изоляция ИИ-агента: почему Docker недостаточно

Практика последних месяцев сходится на неприятном выводе: обычный Docker не годится как граница безопасности для кода, который пишет языковая модель. Причина техническая — контейнеры делят ядро с хостом, и вся изоляция держится на механизмах этого ядра плюс на правильной настройке. Появился и измеримый разбор: работа с бенчмарком побегов из контейнера показывает, что многие типичные конфигурации Docker перестают удерживать модель при активном исследовании среды. Рекомендация исследователей однозначная — для недоверенного кода использовать микровиртуальные машины вроде Firecracker или Kata Containers, а gVisor допускать там, где много вычислений и мало ввода-вывода. Разбираем, почему привычная изоляция вдруг перестала быть достаточной и что с этим делать.

Почему контейнер — это не виртуальная машина

Разница, которую многие держат в голове неточно, а от неё зависит всё остальное.

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

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

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

Долгие годы этого хватало, потому что в контейнерах запускали свой код. Свой код не изучает среду и не ищет выход. Он просто делает то, что написано.

Что изменилось с приходом агентов

Три свойства, которых у обычной нагрузки нет.

Код не проходит ревью. Модель генерирует команду и тут же её выполняет. Между появлением кода и его запуском нет человека, нет тестов и нет статического анализа.

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

Инструкция может прийти извне. Агент читает документы, письма, веб-страницы. Всё это — текст, который модель не отличает от команды разработчика. Мы разбирали случай, когда промпт-инъекцию спрятали в судебном документе белым шрифтом по белому фону.

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

Чем изолируют по-настоящему

Три уровня, от самого прочного к компромиссному.

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

Перехват системных вызовов. gVisor ставит между приложением и ядром собственную реализацию системных вызовов. Ядро хоста при этом почти не видно. Подходит для вычислительных задач; там, где много ввода-вывода, заметно проигрывает по скорости.

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

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

Что ещё стоит закрыть, кроме ядра

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

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

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

Смонтированные тома. Проброшенный внутрь каталог — это дыра ровно того размера, какой каталог. Особенно если случайно пробросили сокет самого Docker.

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

Откуда берётся ложное чувство защищённости

Стоит разобрать, почему проблема так долго оставалась незамеченной, — механизм здесь психологический, а не технический.

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

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

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

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

Как проверить свою среду

Четыре вопроса, ответы на которые стоит знать до того, как их выяснит агент.

От кого работает процесс внутри? Если от привилегированного пользователя, это первое, что надо менять, и меняется оно одной строкой.

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

Куда есть сеть? Не «настроена ли сеть», а конкретно: какие адреса доступны. Ответ «все» означает, что данные могут уехать наружу без всякого побега.

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

Ответы на эти четыре вопроса закрывают заметно больше, чем смена среды выполнения, и требуют несравнимо меньше усилий. Менять Firecracker на Docker имеет смысл после того, как базовая гигиена наведена, а не вместо неё.

Что это значит для вашей архитектуры

Практический минимум, отсортированный по отношению эффекта к трудозатратам.

  1. Определите, выполняет ли ваш агент код. Если модель только пишет текст, а исполняет его человек, вся эта история вас не касается. Если между генерацией и выполнением нет людей — касается напрямую.
  2. Выключите сеть по умолчанию. Это одна строка настройки и самая большая доля пользы.
  3. Уберите секреты из окружения. Агенту они не нужны; нужные операции делайте через отдельный сервис с узкими правами.
  4. Смените среду выполнения там, где выполняется недоверенный код. Переход на микровиртуальные машины — работа на день-два, а не на квартал.
  5. Ограничьте права, а не поведение. Фильтровать текст бесполезно, это мы разбирали в своде по правам агента.

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

Чего мы не утверждаем

Не утверждаем, что Docker небезопасен вообще. Он безопасен ровно для того, для чего создавался: изоляция своих сервисов друг от друга. Проблема в новом сценарии, а не в инструменте.

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

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

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

Что держать в голове

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

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

Как мы отделяем проверенное от предполагаемого — на странице о проекте. Отдельный ключ с собственным лимитом под каждого агента: keydealer.ru/login.

Частые вопросы

Почему обычного Docker недостаточно для агента?

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

Чем это отличается от обычного запуска чужого кода?

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

Чем изолировать вместо Docker?

Микровиртуальными машинами вроде Firecracker или Kata Containers, где у нагрузки своё ядро. Для вычислительных задач с малым вводом-выводом подходит gVisor, перехватывающий системные вызовы.

Это касается только агентов, выполняющих код?

В первую очередь да. Если модель только генерирует текст и никуда его не отправляет, поверхность атаки принципиально меньше.

Что с этим на стороне KeyDealer?

Мы передаём запросы к моделям и не выполняем код. Изоляция среды, где работает ваш агент, — задача вашей инфраструктуры.

Источники