28 KiB
Executable File
28 KiB
Executable File
title, tags, created, status
| title | tags | created | status | |||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Изоляция исполнения агента: OS и контейнерный уровень |
|
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, сужается sandboxdenyRead. - 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, resolvedgitdir:,.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 требуют разрешить syscallseccomp, иначе не смогут применить собственные ограничения. - Установка на 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 вообще, а дать rootlessbuildah/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.