--- title: 'Изоляция исполнения агента: OS и контейнерный уровень' tags: - agent-security - sandboxing - seccomp - gvisor - firecracker - bubblewrap - ssh - docker - research created: '2026-09-29' status: complete --- # Изоляция исполнения агента: OS и контейнерный уровень Исследование: 8 подходов + паттерны ограниченного доступа к хосту. Контекст: дать агенту собирать/тестировать код, но не дать дотянуться до чужих файлов и секретов. --- ## 1. gVisor (Google) — application kernel в userspace (`runsc`) - gVisor — **не seccomp-фильтр, не обёртка над Linux-примитивами и не VM**. Это «третий подход»: application kernel, реализующий Linux-подобный интерфейс, написанный на **Go (memory-safe)** и работающий в **userspace**. Себя описывают как «seccomp on steroids». - Архитектура: **Sentry** — application kernel на песочницу (перехватывает системные вызовы, сигналы, управление памятью, потоки); **Gofer** — на контейнер, даёт доступ к ФС. Системные вызовы приложения **не проходят** насквозь в ядро хоста — их обрабатывает Sentry. - OCI-runtime `runsc` интегрируется с Docker и Kubernetes (GKE Sandbox, minikube) — можно запускать обычные контейнеры «под gVisor» без переписывания. - Накладные расходы: **эмерджентны** (threads/memory mappings, а не фиксированные guest-ресурсы), быстрый старт, но **плохо для syscall-heavy нагрузок** (компиляция — как раз syscall-heavy, важно учитывать). - Преимущество для агентов: **защита от container-escape через kernel-эксплойты** — единственная поверхность это сам Sentry в Go. Комбинируется с rule-based (seccomp) для defense-in-depth. - Ссылка: https://gvisor.dev/docs/ ## 2. Firecracker microVM (AWS) + jailer - Firecracker — lightweight **microVM** (KVM-based, Rust), созданный для multi-tenant serverless (Lambda, Fargate). **Аппаратная виртуализация** = самая сильная граница изоляции при быстром старте (десятки мс) и низком footprint. - Компаньон **`jailer`** создаёт многослойную границу для VMM-процесса: - `chroot` + `pivot_root` в новый mount namespace; копирование бинарника в jail (защита от shared memory с другими Firecracker). - Сброс в **непривилегированный uid/gid** (`--uid`/`--gid`) — VMM не root. - **cgroups v1/v2** — лимиты CPU/памяти (`--cgroup cpuset.cpus=0`, `--parent-cgroup`). - `setrlimit` — **fsize** (ограничение размера создаваемых файлов) и **no-file** (по умолчанию 2048 дескрипторов). - Новый **PID namespace** (`--new-pid-ns` → `clone(CLONE_NEWPID)`, процесс становится init(1)), опционально `--netns`, `setsid()` + redirect I/O в /dev/null при `--daemonize`. - **Вычищает все env-переменные** родителя и закрывает все FD кроме stdin/stdout/stderr. - Каждая microVM изолирована обычными Linux-barriers через jailer + **seccomp-фильтры** для самого VMM-процесса (см. отдельный документ про seccomp filtering). - Ссылки: https://github.com/firecracker-microvm/firecracker/blob/main/docs/jailer.md , https://firecracker-microvm.github.io/ ## 3. E2B (e2b.dev) — sandbox для AI-агентов - Managed sandbox-API именно под AI-агентов; под капотом — **Firecracker microVM** (у E2B открытая инфра-стековая часть, Firecracker-основа). Долгоживущие песочницы с **persistence**. - Жизненный цикл: `Sandbox.create({timeoutMs})`, `setTimeout` для продления, `kill()` для остановки. Лимиты **до 24ч (Pro) / 1ч (Base)**, далее pause+resume (состояние сохраняется, окно таймаута сбрасывается). - **Эфемерность на задачу**: таймаут → авто-pause/kill; каждый sandbox — отдельная microVM (свой kernel, своя ФС, свой network). Агент не видит хост. - API: `Sandbox` из JS/TS/Python SDK; getInfo → sandboxId/templateId/startedAt/endAt; metadata. Шаблоны (templates) из Dockerfile. - Для паттерна «собирать/тестировать код»: sandbox = полное Linux-окружение, изолированное от хоста инженера; секреты хоста недостижимы физически. - Ссылка: https://e2b.dev/docs/sandbox ## 4. Daytona — control/compute plane sandbox-платформа - **Три плоскости**: Interface plane (SDK Python/TS/Ruby/Go/Java, CLI, Dashboard, **MCP-сервер**, SSH) → Control plane (NestJS API, Proxy, Snapshot builder, Sandbox manager; Redis/PostgreSQL/Auth0) → Compute plane (runners, sandbox daemon, snapshot store, volumes). - Изоляция: каждый sandbox — **isolated instance с собственными Linux namespaces** (process, network, filesystem mounts, IPC) + **dedicated vCPU, RAM и disk на sandbox**. Multi-tenancy на уровне organization boundary. - **Snapshot builder** собирает снапшоты из **Dockerfile или pre-built image** → пушит в внутренний OCI-registry. Быстрый provisioning эфемерных окружений под задачу. - Network: отдельный HTTP-прокси с **host-based routing** — `{port}-{sandboxId}.{proxy-domain}`; инжектит auth-заголовки, поддерживает WS. - **Sandbox daemon / Toolbox API** внутри sandbox: файловые и git-операции, исполнение кода, computer use, log streaming, терминальные сессии. Volumes — персистентное хранилище между sandbox. - Ссылка: https://www.daytona.io/docs/en/architecture/ ## 5. Modal Sandboxes — контейнеры для untrusted code на лету - Явно позиционируются как **secure containers for executing untrusted user or agent code**; определяешь контейнер **в runtime** (`modal.Sandbox.create(...)`), исполняешь произвольный код. Use-case прямо: «execute code generated by a language model», checkout git-репы и запуск тест-сьютов. - **Эфемерность**: default max lifetime **5 минут**, до **24 часов** через `timeout`; `idle_timeout` для авто-остановки (sandbox активен, если есть running command / stdin-write / open TCP over tunnel). - Lifecycle: Created → Scheduled (provision CPU/mem/GPU/volumes) → Started → Ready (readiness probe) → Finished (exit/timeout/OOM/terminate). - **Readiness probes** (TCP или Exec, interval_ms default 100ms, max 5 min) — идеально для «подняли окружение, накатили зависимости, готово к тестам». - Filesystem Snapshots — сохранить состояние и восстановить в новом sandbox (для работ >24ч). - Изоляция: каждое исполнение — отдельный контейнер на worker'е Modal; запуск команд через `sb.exec(...)` с таймаутами. - Ссылка: https://modal.com/docs/guide/sandbox ## 6. Fly Machines (Fly.io) — быстрые VM с супербыстрым стартом - **Быстро-запускаемые VM** с start/stop на **subsecond** скоростях; контроль количества машин, lifecycle каждой машины, ресурсов и region placement через **REST API или flyctl**. - Модель «одна машина = один экземпляр приложения/окружения»: полная VM-граница изоляции, микро-уровень ресурсов. Подходит как эфемерная «машина на задачу» для агента — создать, выполнить сборку/тесты, остановить. - Эфемерность: stop/start по API; отдельные `[machines]` с независимым lifecycle. Для агента удобно: run-per-task VM, старый экземпляр уничтожается. - Интеграция с flyd / hardware-virtualization (Firecracker-подобное) — граница уровня гипервизора, а не просто namespaces. - Ссылки: https://fly.io/docs/machines/ , https://fly.io/machines/overview ## 7. Anthropic Claude Code sandbox modes (macOS Seatbelt) - **Platform support**: sandboxed Bash tool встроен; работает на **macOS, Linux, WSL2**. **Native Windows не поддерживается** (только WSL2). - **macOS**: ничего ставить не надо — используется встроенный фреймворк **Seatbelt** (sandbox-exec / sandbox profiles). - **Linux/WSL2**: требуются пакеты **`bubblewrap`** (ФС-изоляция) и **`socat`** (relay сетевого трафика через sandbox-прокси). Опционально seccomp-фильтр из `@anthropic-ai/sandbox-runtime` (блок AF_UNIX sockets). - **Режимы-аналоги** (у Claude Code — permission modes + sandbox modes): **Manual** стартует read-only (built-in read-only команды `ls/cat/git status` без вопросов); **Accept Edits** авто-одобряет правки и фиксированный набор ФС-команд (`mkdir,touch,rm,mv,cp,sed`) в рабочей директории; **Auto mode** — отдельная classifier-модель ревьюит и блокирует небезопасные действия. - **Working directory boundary**: в Manual режиме запись **только в стартовую папку и подпапки**; чтение вне границы через Read/Grep/Glob требует разрешения. Расширяется `--add-dir` / `permissions.additionalDirectories`, сужается sandbox `denyRead`. - **Network isolation**: первый запрос к новому домену → промпт; `curl`/`wget` **не авто-одобряются**; deny-правила матчат команду «как написано», а независимую от текста сетевую политику даёт именно sandbox network isolation. - Escape hatch: `dangerouslyDisableSandbox` параметр (retry вне sandbox через обычный permission flow); можно запретить `allowUnsandboxedCommands: false` / `failIfUnavailable: true` для managed-деплоя. - Linux нюанс: на Ubuntu 24.04+ с `kernel.apparmor_restrict_unprivileged_userns=1` нужен AppArmor-профиль для `bwrap` (иначе unprivileged userns запрещён). - Ссылки: https://docs.claude.com/en/docs/claude-code/sandboxing , https://docs.claude.com/en/docs/claude-code/security ## 8. OpenAI Codex CLI sandbox (Seatbelt на macOS, bubblewrap/Landlock на Linux) - **Дефолт локально**: сеть **выключена**, write-права **ограничены активным workspace**; OS-enforced sandbox + approval policy сверху. - **Sandbox modes**: `read-only`, `workspace-write` (рабочая директория + оговорённые исключения), `danger-full-access`. Профили прав: built-in `:read-only`, `:workspace`, `:danger-full-access`, кастомные через `[permissions.]`. - **macOS**: **Seatbelt** (как и Chromium). **Linux**: исторически Landlock, теперь **bubblewrap по умолчанию** (Landlock отвергается для ФС-политик, т.к. **не умеет изолировать app-server Unix sockets**; флаг `features.use_legacy_landlock` надо выключать при апгрейде). - Реализация `codex-linux-sandbox` (крейт) поверх bwrap: - **`PR_SET_NO_NEW_PRIVS`** + in-process **seccomp network filter**. - ФС **read-only по умолчанию** (`--ro-bind / /`), writable-корни через `--bind `. - **Защищённые подпути** под writable-корнями (`.git`, resolved `gitdir:`, `.codex`) переоткрываются read-only через `--ro-bind`. - **`--unshare-user`**, `--unshare-pid` (по умолчанию), `--unshare-net` при запрете сети без прокси. - Порядок по path-specificity: `/repo=write`, `/repo/a=none`, `/repo/a/b=write` корректно комбинируются. - Защита от symlink/несуществующих путей: монтирование **`/dev/null`** поверх symlink или первого отсутствующего компонента. - **Managed proxy mode**: `--unshare-net` + внутренний TCP→UDS→TCP bridge; после старта bridge seccomp **блокирует создание AF_UNIX/socketpair**. - `bwrap` ищется на PATH вне CWD; при отсутствии — bundled fallback (`codex-resources/bwrap`); WSL1 не поддерживается (нет user namespaces). - **Two-phase в Codex cloud**: *setup phase* (сеть есть, ставим зависимости) → *agent phase* (по умолчанию offline). **Секреты доступны только в setup и удаляются до старта agent phase** — это ровно паттерн «дать собирать, но не дать украсть секреты». - Managed: `requirements.toml` может запретить `approval_policy = "never"` и `sandbox_mode = "danger-full-access"`. - Ссылки: https://developers.openai.com/codex/sandbox/ , https://github.com/openai/codex/blob/main/codex-rs/linux-sandbox/README.md ## 9. Chromium / Chrome seccomp-bpf sandbox (эталон многослойности) - **Multi-process security model**: процессы, обрабатывающие недоверенные данные (renderer, utility, GPU), ограничены; к привилегированным ресурсам — только через **медиацию Browser-процесса** (broker). - **Linux**: `namespaces` + **seccomp-BPF** (+ опционально legacy SELinux/AppArmor/Landlock в зависимости от доступных фич ядра). Несколько слоёв: confinement процесса **и** сокращение exposed kernel attack surface. - Ключевая проблема seccomp-bpf: фильтрация на уровне syscall даёт трудно-понятную семантику; если процесс A под одним seccomp-bpf policy, нужно **гарантировать, что он не может повлиять на целостность процесса B** под другим policy (иначе sandbox escape). - **macOS**: `sandbox/mac` использует **Seatbelt**; **Windows**: restricted tokens + job objects + alternate desktops + integrity levels. Один код-бейз, три разных OS-механизма. - **Broker-паттерн**: GPU/utility не ходят в ядро напрямую, а просят Browser-процесс выполнить операцию — переносится на любые агентские архитектуры (агент просит «runner» выполнить привилегированное действие). - Ссылки: https://github.com/chromium/chromium/tree/main/sandbox , https://chromium.googlesource.com/chromium/src.git/+/master/sandbox/linux/ ## 10. bubblewrap (bwrap) — unprivileged sandboxing (упоминался в DeepSeek Harness как sandbox seam) - **Low-level unprivileged sandboxing tool** (Flatpak, rpm-ostree, и теперь Claude Code / Codex на Linux). Ключ: использует **Linux user namespaces**, поэтому доступен **непривилегированному пользователю** — в отличие от docker/systemd-nspawn, которые админам. - Всегда создаёт **новый mount namespace**: root на **tmpfs**, невидимый с хоста, автоочистка при выходе последнего процесса. Опции конструируют ФС: `--ro-bind /usr /usr`, `--proc /proc`, `--dev /dev`, `--bind`. - Namespaces: `CLONE_NEWUSER` (`--unshare-user`, маппинг uid/gid), `CLONE_NEWIPC`, `CLONE_NEWPID` (`--unshare-pid` + trivial pid1 reaps zombies — решает docker pid-1 problem), `CLONE_NEWNET` (`--unshare-net`, только loopback), `CLONE_NEWUTS`; плюс **seccomp-фильтры**. - Использует **`PR_SET_NO_NEW_PRIVS`** — выключает setuid-бинарники, классический способ выйти из chroot. - ⚠️ Важно: bwrap **не готовый sandbox с политикой** — уровень защиты целиком определяется переданными аргументами. Владельцы могут повысить риск DoS. - ⚠️ Подводные камни: без фильтрации `TIOCSTI` нужен `--new-session` (CVE-2017-5226); **всё, что смонтировано, потенциально эскалирует привилегии** (напр. bind D-Bus socket = исполнение через systemd → используйте `xdg-dbus-proxy`); nested sandboxing: браузеры со своим seccomp требуют разрешить syscall `seccomp`, иначе не смогут применить собственные ограничения. - **Установка на Ubuntu 24.04+**: `apparmor_restrict_unprivileged_userns=1` блокирует unprivileged userns → нужен AppArmor-профиль `profile bwrap /usr/bin/bwrap flags=(unconfined) { userns }`. - Ссылка: https://github.com/containers/bubblewrap --- # Доступ к хосту с ограниченным набором команд (изоляция машины инженера) ## Паттерн A: SSH forced command (`authorized_keys command=`) - В `~/.ssh/authorized_keys` перед ключом — опции: `command="..."` заставляет **sshd игнорировать любую команду/шелл клиента и выполнить серверную команду**. Формат: `options keytype base64 comment`. - В паре с **`restrict`** (новый агрегат) — отключает PTY, agent forwarding, X11 forwarding, TCP forwarding и user rc processing **одним словом**. Эквивалент набора: `no-pty, no-port-forwarding, no-agent-forwarding, no-X11-forwarding, no-user-rc`. - Дополнительно: `from="IP"` — ограничение источника; `environment="..."` (только если `PermitUserEnvironment`); `permitopen`/`permitlisten` для точечного туннелирования. - **Wrapper-паттерн**: `command="/usr/local/bin/agent-wrapper.sh"` — скрипт читает `$SSH_ORIGINAL_COMMAND`, валидирует по **whitelist** допустимых команд, и только затем исполняет через `exec`. Это и есть command-whitelist wrapper: агент шлёт `ssh host "git status"`, wrapper сверяет с allowlist, остальное → reject + лог. - Реальный пример в природе: **`git-shell`** — логин-шелл только для git-операций; тот же принцип в GitHub/GitLab-деплой-ключах. - Отдельно можно задать **`ForceCommand`** в `sshd_config` (глобально/по Match-блоку) — серверная сторона, независимая от клиента. - Ссылки: https://man.openbsd.org/sshd.8 , https://www.simplified.guide/ssh/restrict-authorized-keys-command , https://superuser.com/questions/299927/ ## Паттерн B: bastion / jump host (граница «хост-инженера ↔ агент») - Отдельный **bastion-пользователь** (`agentrunner`) на отдельном хосте/VM: агент аутентифицируется ключом **только** к bastion, не к машине инженера. С бастиона — либо `ProxyJump`, либо жёсткий wrapper к целевому хосту. - `ssh -J bastion target` / `ProxyJump` в `~/.ssh/config` — единая точка аудита и rate-limit; удобно логировать весь трафик агента. - Bastion в **непривилегированном** аккаунте, `rbash`/restricted shell, chroot-джейл (см. паттерн A + `sshd_config Match`), все forward'ы запрещены кроме разрешённых. - Машина инженера полностью закрыта снаружи; даже скомпрометированный ключ агента ведёт лишь на узкий bastion с whitelist. - Ссылка: https://man.openbsd.org/ssh.1 (раздел про `-J`, port forwarding, agent forwarding) ## Паттерн C: restricted shells (rbash) — как дополнение, не как основная защита - `rbash`/`bash --restricted`: нельзя `cd`, менять `$PATH`/`$SHELL`, использовать `/` в именах команд, редиректы, `exec`. Работает только в связке с корректно настроенным `PATH` и неизменяемыми переменными. - ⚠️ `rbash` **легко обходится** (интерпретаторы, `vi`, `less`, `awk`, `find -exec`, git hooks) — общеизвестен как слабая защита. Использовать **только как второй слой**; основной — forced command + wrapper + опционально контейнер/VM. - Ссылка: https://man.openbsd.org/sshd.8 (login process), https://oneuptime.com/blog/post/2026-03-02-how-to-restrict-user-ssh-access-to-specific-commands-on-ubuntu/view --- # Docker socket proxy: как дать `docker build` без доступа к `docker.sock` ## Tecnativa/docker-socket-proxy - **Проблема**: дать сервису доступ к `/var/run/docker.sock` = дать **root на хосте** (даже на весь swarm). Прокси блокирует то, что сервису не нужно, возвращая **HTTP 403 Forbidden**. - Реализация: официальный Alpine-based **HAProxy** + маленький конфиг; **plain HTTP proxy** к хосту-unix-socket (TLS нет by design — ограничивать доступ сетью/Docker firewall). - Управление — **env-переменные по URL-префиксу** (напр. `AUTH` → блокирует `/auth/*`), значения **`0`=revoke, `1`=grant**: - Разрешены по умолчанию: `EVENTS`, `PING`, `VERSION` (почти безвредны). - **Запрещены по умолчанию (критично)**: `AUTH`, `SECRETS`, **`POST`** (при `POST=0` разрешены только GET/HEAD → весь API read-only). - Прочее по умолчанию off: `BUILD`, `CONTAINERS`, `EXEC`, `IMAGES`, `NETWORKS`, `VOLUMES`, `ALLOW_START/STOP/RESTARTS/PAUSE/UNPAUSE`, `COMMIT`, `CONFIGS`, `DISTRIBUTION`, `GRPC`, `INFO`, `NODES`, `PLUGINS`, `SERVICES`, `SESSION`, `SWARM`, `SYSTEM`, `TASKS`. - **Для `docker build`**: включить `IMAGES=1` и `BUILD=1` (или положиться на BuildKit-эндпоинты), но `POST` нужен разрешённым — иначе build не пройдёт. Точечно: НЕ давать `EXEC` (иначе агент влезет в чужой контейнер), `SECRETS`, `AUTH`. - Запуск: `docker run -d --privileged --name dockerproxy -v /var/run/docker.sock:/var/run/docker.sock -p 127.0.0.1:2375:2375 tecnativa/docker-socket-proxy` → клиент через `DOCKER_HOST=tcp://localhost:2375`. - **Обязательно**: не публиковать порт в публичную сеть — только во внутренний Docker network с прокси и потребителем. Использовать GitHub Container Registry образ, а не Docker Hub (остальные теги deprecated). - **Более сильные альтернативы для build**: **rootless docker**, **BuildKit без root** (`buildkitd` как непривилегированный демон, `buildctl`), **kaniko**/**buildah** (сборка образа без демона вообще), **sysbox**, **Podman** с user-namespaced rootless containers. Для «агенту надо собрать образ» лучше не давать docker.sock вообще, а дать rootless `buildah`/`kaniko` или удалённый build-сервис. - Ссылка: https://github.com/tecnativa/docker-socket-proxy --- # Сводка: как собрать «сборка/тесты — да, чужие файлы/секреты — нет» | Слой | Механизм | Инструмент | |---|---|---| | Граница железной изоляции | microVM | Firecracker (+jailer), Fly Machines | | Сильная граница, но дешевле VM | userspace kernel | **gVisor** (`runsc`) | | Unprivileged ФС-песочница | user/mount/pid/net namespaces + `NO_NEW_PRIVS` | **bubblewrap** | | ФС-политика в ядре | Landlock / seccomp-bpf | Chromium, Codex (legacy) | | macOS-граница | Seatbelt / sandbox-exec | Claude Code, Codex, Chromium | | Ограничение syscall | seccomp-bpf | Chromium, Firecracker VMM, Codex net-filter | | Непривилегированный юзер | uid/gid drop, rootless | jailer `--uid/--gid`, rootless docker | | Эфемерность | timeout + авто-kill + снапшоты | E2B, Modal, Daytona, Fly | | Секреты | доступ только в setup-фазе, удаляются до agent phase | **Codex two-phase** | | Доступ к хосту | forced command + whitelist wrapper + bastion | `authorized_keys command=`/`restrict`, `ForceCommand`, `-J` | | Docker без docker.sock | API-прокси с точечными правами | tecnativa/docker-socket-proxy | **Рекомендуемый минимум для агента-сборщика**: непривилегированный отдельный пользователь → bubblewrap/gVisor sandbox с read-only корнем и одним writable workspace → `--unshare-net`/прокси для сети → секреты только на этапе setup → отдельный bastion-пользователь с forced command + whitelist wrapper для доступа к хосту инженера → docker build через socket-proxy или (лучше) rootless BuildKit/buildah/kaniko.