Files
obsidian-vault/Research/Isolation of Agent Execution - OS and Container Level.md
T

28 KiB
Executable File
Raw Blame History

title, tags, created, status
title tags created status
Изоляция исполнения агента: OS и контейнерный уровень
agent-security
sandboxing
seccomp
gvisor
firecracker
bubblewrap
ssh
docker
research
2026-09-29 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.<name>].
  • 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 <root> <root>.
    • Защищённые подпути под 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.