OpenShell: рантайм, в котором агент не видит ваших ключей

OpenShell: рантайм, в котором агент не видит ваших ключей

Проверьте свой агент прямо сейчас. Найдите его PID и выполните tr '\0' '\n' < /proc/$PID/environ | grep -i key. Если в выводе есть рабочий ключ, значит любая строка, попавшая в контекст модели, может уйти наружу вместе с ним: через ссылку, которую агент решил открыть, через пакет, который он поставил, через файл, который он прочитал и пересказал.

Именно эту схему на этой неделе попробовала сломать NVIDIA. Компания выложила на GitHub проект OpenShell под Apache 2.0, рантайм для флотов автономных агентов, где ключей в окружении агента просто нет. Разбор механизмов появился в блоге Сэма Лаббе 23 октября, и он полезен тем, что автор читал не пресс-релиз, а исходники: крейты providers и openshell-prover, документацию по политикам, схему установки.

Что такое OpenShell

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

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

Шлюз, супервизор и песочницы

Внутри три части. Шлюз (gateway) работает как control plane: хранит записи провайдеров, политики и маршруты доступа. Супервизор запускает песочницу и следит за её жизненным циклом. Сама песочница по умолчанию это минимальный Ubuntu без единого агента внутри: bring your own, как говорят в документации.

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

Песочницы поддерживают проброс GPU и масштабирование через Kubernetes: шлюз ставится Helm-чартом, а CNI в кластере обязан реально применять NetworkPolicy, иначе сетевые правила останутся декларацией. Есть SDK на Python, TypeScript, Go и Rust, а для кодовых агентов предусмотрены skills, которые ставятся командой npx skills add NVIDIA/OpenShell.

Инверсия с ключами

Самое интересное в OpenShell это смена владельца секретов. Сегодняшний дефолт выглядит так: вы экспортируете OPENAI_API_KEY в окружение агента и надеетесь на лучшее. Ключ лежит в /proc/self/environ, попадает в дочерние процессы, в дампы, в трейсы ошибок и в логи, которые кто-то обязательно собирает в ELK.

OpenShell переставляет custody. Крейт providers находит ключи, bearer-токены и локальные конфиги в вашем окружении, нормализует их и складывает в записи шлюза. В контракте крейта прямо прописано требование редактировать чувствительные поля при любом выводе наружу, чтобы ключ не утёк в лог при первом же print(config).

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

Смысл в размере ущерба. Раньше скомпрометированный агент означал «все ключи, которые были в окружении». Теперь он означает «те адреса, которые назвала политика этой песочницы». Агент по-прежнему читает файлы, ставит пакеты и вызывает API, просто ключей от остального мира в комнате нет.

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

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

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

Z3 на входе в политику

Второй механизм я не ожидал увидеть в проекте версии 0.1. Крейт openshell-prover это формальный верификатор политик. Он кодирует политику, привязанный к ней набор учётных данных и реестр возможностей в модель Z3 SMT, а затем задаёт вопросы достижимости: может ли эта песочница теперь дотянуться до нового хоста с ключами, может ли вызвать новый метод API.

Практический эффект простой. Когда политика меняется, будь то руками инженера или предложением самого агента, OpenShell не ограничивается диффом YAML. Он кодирует предполагаемое состояние и проверяет, какие новые возможности оно открывает. Опасные дельты уходят на ревью человеку, а не применяются молча.

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

Самое важное в реализации это поведение при отказе. Модель Z3 имеет границы: ASCII-литералы в сетевых селекторах, запрет встроенных NUL-байтов. Если политика использует конструкцию, которую проверить нельзя, крейт возвращает unsupported_policy_shape, то есть «я не могу ничего доказать», вместо зелёного света. В собственной документации крейта написано: неизвестные значения трактовать как отказ. Именно так и должна вести себя защита, которая не умеет врать в свою пользу.

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

Три ограничения, которые честно названы

Первое: ограничение не равно доказательству. OpenShell отвечает на вопрос «что агент может сделать», а не «что он реально сделал». Агент внутри песочницы всё ещё способен натворить дел в её пределах, и после инцидента вам понадобится защищённый от подмены журнал, а не только список стен, которые стояли. Это разные слои, и для серьёзного флота нужны оба. Про то, почему обычным логам агентов нельзя доверять, у нас был отдельный разбор: аудит AI-агентов.

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

Третье: версия 0.1.x. Темп релизов стабильный, тесты есть, RFC-процесс и политика раскрытия уязвимостей тоже, но проекту несколько недель. Документация провера сама перечисляет формы политик, которые не входят в модель. Перед тем как направлять на OpenShell боевой флот, стоит прочитать support matrix, а не только quickstart.

Чем это отличается от docker agent

В начале октября мы разбирали docker agent в Docker Desktop 4.63: агент описывается YAML, подключается к MCP-серверам, умеет жить в песочнице с сетью default-deny. Проблема была в дефолтах: песочница выключена, пока её не включат руками.

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

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

Как попробовать

Требования: Linux, macOS на Apple Silicon или Windows с WSL 2 в экспериментальном режиме, плюс Docker, Podman или виртуализация на хосте. Установка выглядит так:

curl -LsSf https://raw.githubusercontent.com/NVIDIA/OpenShell/main/install.sh | sh
openshell sandbox create --name demo

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

Телеметрия включена по умолчанию, но собирает только операционные категории и счётчики, без имён песочниц, путей, промптов и учётных данных. Отключается переменной OPENSHELL_TELEMETRY_ENABLED=false на шлюзе или флагом server.telemetryEnabled=false при установке через Helm. Проверять это стоит не на веру, а по коду: проект молодой, и доверие к нему пока строится из читаемости исходников.

Почему это важно именно сейчас

Стек безопасности агентов собирается послойно, и в октябре 2026 это видно уже по релизам. Песочницы на уровне ядра отвечают за ограничение. Шлюзы с учётными данными отвечают за custody. SMT-проверка отвечает за то, чтобы новая политика не расширила права молча. Журналы и аттестации отвечают за доказательства постфактум.

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

Часто задаваемые вопросы

OpenShell заменяет песочницу Docker?

Нет. Docker даёт формат агента и удобный запуск, OpenShell даёт слой принуждения под уже существующими агентами. Они спокойно сосуществуют: OpenShell умеет работать поверх Docker, Podman или виртуализации на хосте.

Нужна ли GPU для OpenShell?

Нет. По умолчанию песочница это минимальный Ubuntu без агента, и работает он на ноутбуке под macOS на Apple Silicon, Linux или WSL 2. Проброс GPU нужен только для задач инференса внутри песочницы.

Можно ли ставить OpenShell в продакшен на версии 0.1.x?

Можно, если вы готовы читать support matrix и держать шлюз как критичную инфраструктуру. Проект молодой, часть форм политик проверить нельзя, и документация честно это перечисляет. Начните с одного агента и одного ключа, а не с флота.

Что произойдёт, если политику нельзя проверить?

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

Итог

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

Практический следующий шаг простой. Возьмите одного своего агента, посмотрите, какие ключи лежат в его окружении, и прикиньте, к каким адресам он реально ходит. Если список адресов короткий, а ключей много, OpenShell стоит вечера на эксперимент.

← Все записи