diff --git a/Research/Gatekeeper Architecture for Agent Tool Calls.md b/Research/Gatekeeper Architecture for Agent Tool Calls.md new file mode 100644 index 00000000..e955a423 --- /dev/null +++ b/Research/Gatekeeper Architecture for Agent Tool Calls.md @@ -0,0 +1,120 @@ +--- +tags: + - ai-agents + - security + - guardrails + - mcp + - policy-engine +title: Gatekeeper Architecture for Agent Tool Calls +date: '2026-09-29' +status: complete +--- +# Привратник для агентских инструментов: контроль tool calls отдельным слоем (2025–2026) + +> Исследование: как в агентских системах проверяют и одобряют **каждый tool call** отдельным слоем (policy engine / interception / MCP proxy), а не самим агентом. +> Дата: 2026-09-29. Все ссылки проверены. + +## Общий вывод + +Единого стандарта «привратника» в 2025–2026 нет. Сложилось **4 архитектурных уровня**, где может сидеть контроль: + +1. **In-harness hooks** (Claude Code PreToolUse, ADK callbacks, LangChain middleware) — контроль внутри runtime агента, ближе к самому агенту. +2. **Policy engines вне агента** (OPA/Rego, Cedar/AVP) — решения принимаются детерминированным внешним движком. +3. **MCP proxy / gateway** — сетевой слой-посредник, фильтрует трафик tool calls в обе стороны. +4. **Guardrail/scan слои** (Invariant, LlamaFirewall, NeMo, Lasso) — ML-классификаторы + правила поверх трафика. + +Ключевой консенсус: **детерминированные проверки — policy engine; семантические («токсично/инъекция») — ML-классификатор, а не policy**. И любое решение должно быть **explainable + логируемым** (для апелляций и итерации правил). + +--- + +## Подход 1. Claude Code: permissions + PreToolUse hooks +**Зрелость: ВЫСОКАЯ (production, v2.x, ноябрь 2025+)** + +- Трёхуровневая система правил `allow` / `ask` / `deny` с порядком вычисления **deny → ask → allow** (первое совпадение побеждает; специфичность не влияет). +- **PreToolUse hook** срабатывает *перед* permission-промптом на **каждый** tool call (кроме `EndConversation`); hook возвращает JSON `{permissionDecision: "deny"|"ask"|"allow", permissionDecisionReason}` и может заблокировать/форсировать промпт/пропустить его. +- Hooks — это shell-команды, HTTP-endpoint, MCP tool calls, LLM-промпты или subagents; три уровня конфигурации: event → matcher → handler. +- Важно: правила **enforced by Claude Code, not by the model** — инструкции в CLAUDE.md/prompt *не* меняют то, что разрешено. +- Deny с bare tool name удаляет инструмент из контекста модели; scoped deny (`Bash(rm *)`) оставляет инструмент, но блокирует вызов. +- Источник: https://code.claude.com/docs/en/permissions , https://code.claude.com/docs/en/hooks + +## Подход 2. MCP Authorization Spec (OAuth 2.1) + Security Best Practices +**Зрелость: СРЕДНЕ-ВЫСОКАЯ (спек в draft/2025-06-18, OPTIONAL, ломающие ревизии)** + +- Спецификация описывает **transport-level authorization** на основе OAuth 2.1 (RFC6750, RFC8414, RFC7591, RFC8707, RFC9728) только для HTTP-транспорта; STDIO — берёт креды из env, спек не применяет. +- Роли: MCP server = OAuth resource server, MCP client = OAuth client, плюс authorization server. Принцип least privilege через `scope` в `WWW-Authenticate`, поддерживается step-up authorization. +- Dynamic Client Registration **deprecated** (оставлен для обратной совместимости); вместо него Client ID Metadata Documents. +- Отдельный документ **Security Best Practices** покрывает confused deputy, token passthrough, per-client consent, обязательный валидатор `state`, `__Host-` cookies, точный redirect_uri match. +- Важное ограничение: авторизация **OPTIONAL** и НЕ покрывает *per-tool-call* политику (какие конкретно инструменты можно звать) — это оставляют приложениям/proxy. +- Источник: https://modelcontextprotocol.io/specification/draft/basic/authorization , https://modelcontextprotocol.io/specification/draft/basic/security_best_practices + +## Подход 3. OPA (Open Policy Agent) как policy engine для tool calls +**Зрелость: ВЫСОКАЯ (CNCF graduated, но agent-интеграции — 2025+, молодые)** + +- OPA развязывает **policy decision от enforcement**: клиент шлёт JSON input → OPA (Rego + data) → решение. `deny`/`allow`/`requires-approval`/`not-applicable`. +- Экспрессивность Rego (Datalog, Тьюринг-полный) позволяет multi-hop решения («может ли агент читать данные проекта из того же отдела»); p99 латентность < 1 ms in-process. +- Прямая agent-интеграция: **`@ai-sdk/policy-opa`** (Vercel AI SDK) через `toolApproval` callback — правила вынесены в `.rego`, тестируются `opa test` в CI, меняются без деплоя. Policy `input` несёт `messages` (история tool calls) → правила вида «approval после N записей», «deny второго необратимого действия», бюджет/токен-квоты. +- Эмпирическое правило вендора: если можно указать поле в `input` и написать точную проверку — это правильный инструмент; семантику («no toxic content») сюда класть нельзя. +- OPA MCP (npm `@orygn/opa-mcp`) даёт агенту 50+ инструментов для authoring/debug Rego. +- Источник: https://www.openpolicyagent.org/docs/latest/ , https://ai-sdk.dev/docs/agents/policy-tool-approvals , https://inferensys.com/differences/mcp-security-gateways-and-agent-tool-sandboxes/policy-as-code-engines-for-agents/open-policy-agent-opa-vs-cedar-agent-tool-authorization + +## Подход 4. Cedar (AWS) как policy language +**Зрелость: СРЕДНЕ-ВЫСОКАЯ (Apache 2.0, AWS Verified Permissions; agent-специфика ранняя)** + +- Purpose-built язык авторизации: четыре элемента — **principal / action / resource / context** + schema. Схема используется *только* для валидации политик, не при evaluation. +- Ключевое преимущество: **ограниченная выразительность намеренно** — делает автоматический анализ политик вычислимо возможным (напр. доказать, что политика никогда не даёт публичный доступ). Это критично для security-аудита. +- Интеграция с AWS IAM / Amazon Verified Permissions / Verified Access; p99 < 2 ms (managed). Практический предел ~1000 правил против 10000+ у OPA. +- Trade-off: менее выразителен, чем Rego (нет графовых обходов), AWS-центричен; standalone engine требует кастомной интеграции. +- MCP-нативной интеграции нет ни у OPA, ни у Cedar — нужен «custom adapter» (отсюда и весь рынок MCP gateway/proxy). +- Источник: https://docs.cedarpolicy.com/ , https://inferensys.com/differences/... + +## Подход 5. MCP proxy / security gateway (сетевой привратник) +**Зрелость: ВЫСОКАЯ популярность, СРЕДНЯЯ зрелость (Invariant acquired by Snyk 2025; Lasso open-source)** + +- **Invariant Labs: MCP-scan** — два режима: пассивный `scan` (статически ищет tool poisoning / prompt injection в описаниях инструментов) и активный `mcp-scan proxy` (фоновый динамический слой, мониторит и логирует весь MCP-трафик). Guardrails покрывают tool calls/responses, PII/secrets detection, tool restrictions, custom policies. **Tool Pinning** (хэширование) ловит rug-pull атаки; cross-origin escalation → tool shadowing. +- **Invariant Guardrails** работает **out-of-band**: ingests execution traces + MCP server definitions → static information-flow analysis над ними, поднимает policy violations (unsafe tool-call sequences). Т.е. контроль отдельным слоем над трейсом, а не в loop. +- **Lasso MCP Gateway** (MIT, open source, апр 2025): proxy-and-orchestrator между LLM и другими MCP; перехватывает request/response, mask secrets/PII, блокирует prompt injection и command injection/RCE. Плагины: `basic` (secrets masking), `presidio` (PII), `lasso` (custom policy + injection + harmful content). Унифицированный интерфейс `get_metadata` / `run_tool`. +- Паттерн де-факто: **MCP gateway = привратник на сетевом слое**, независимый от агента, применяет фильтры к обеим сторонам трафика. +- Источник: https://invariantlabs-ai.github.io/docs/mcp-scan/ , https://www.agentpatternscatalog.org/landing/compositions/invariant-labs/ , https://github.com/lasso-security/mcp-gateway + +## Подход 6. Guardrail-фреймворки (ML-слой поверх tool calls) +**Зрелость: ВЫСОКАЯ (Meta/Microsoft/NVIDIA — production, но акцент на content/инъекции, не на per-tool authz)** + +- **LlamaFirewall (Meta)** — «policy engine», оркеструет сканеры: PromptGuard 2 (BERT-классификатор prompt injection), **AlignmentCheck** (аудит chain-of-thought рассуждений агента в реальном времени — ловит goal hijacking / indirect injection), CodeShield (статический анализ LLM-кода, 8 языков), regex/custom. Возвращает `ScanResult {decision, reason, score}`. Поддерживает `scan_replay` по трассам. Реально open source (4.4k★). +- **NeMo Guardrails (NVIDIA)** — rails (input/retrieval/dialog/execution/output), Colang flows, YAML. Явно есть **agentic security**: tool call validation (валидирует входы/выходы инструмента до/после вызова), интеграция с LangGraph. Библиотека+микросервис, конфиг переносим. +- **Guardrails AI** — validation-фреймворк (Hub валидаторов); в 2026 команда ушла в Harvey (сайт-леденящий), самостоятельный продукт фактически заморожен. +- **Prompt Security** — теперь часть **SentinelOne**; предлагает AI Gateway + open-source (ClawSec — integrity/drift detection skills, ps-fuzz — fuzzing промптов). Это скорее enterprise AI gateway, чем tool-level привратник. +- Граница: guardrail-фреймворки сильны на *semantic* рисках (инъекции, токсичность, PII), но они **не заменяют** детерминированную авторизацию tool calls. +- Источник: https://github.com/meta-llama/PurpleLlama/tree/main/LlamaFirewall , https://docs.nvidia.com/nemo/guardrails/ , https://www.prompt.security/ + +## Подход 7. Interception в агентских фреймворках (callbacks / middleware) +**Зрелость: ВЫСОКАЯ (first-class API в трёх крупных SDK)** + +- **OpenAI Agents SDK**: tool guardrails выполняются на **каждой** guarded function-tool invocation (input до, output после), включая локальные MCP-инструменты. Tripwire-механизм: `.tripwire_triggered` → `Input/OutputGuardrailTripwireTriggered`. Есть `run_in_parallel` (быстро, но агент может успеть выполнить tool до отмены) vs blocking (расход до tool execution). Отдельно — sanitized placeholder `"Output withheld by an output guardrail."`. +- **Google ADK**: 6 типов callbacks, включая **Before Tool / After Tool**. Return `None` = продолжать, return объект = **override и skip** дефолтного поведения (жёсткий interception). Важный совет вендора: для security guardrails использовать **ADK Plugins**, а не callbacks (модульность). +- **LangChain**: `HumanInTheLoopMiddleware` — интерцепт tool calls через `after_model` hook + LangGraph `interrupt()`. Pause-Decide-Resume; решения `approve` / `edit` / `reject` / `respond`; настраивается `interrupt_on` (True/False/config) и **`when` predicate** (условный interrupt, напр. только записи вне `/workspace/`). Требует checkpointer (Postgres/Mongo в проде). +- Все три — это «in-harness» привратник: контрольный слой в самом рантайме агента, а не внешний сервис. +- Источник: https://openai.github.io/openai-agents-python/guardrails/ , https://google.github.io/adk-docs/callbacks/ , https://docs.langchain.com/oss/python/langchain/human-in-the-loop + +## Подход 8. Jev / TypeSafe System One — typed evaluation как гейт +**Зрелость: НИЗКО-СРЕДНЯЯ (нишевый, молодой; community-репо 9–18★; сайты-спутники — community)** + +- **Jev — это НЕ LLM и НЕ drop-in замена модели агента.** «System One model»: принимает `state` + набор **typed questions**, возвращает структурированные ответы — `choice` (с вероятностями по опциям), `score` (по рубрике), `noul` (0–1 для true/false утверждения). Не генерирует текст и не вызывает инструменты. +- Паттерн tool-approval: между *намерением* агента и *side effect*. Вопросы: `risk` (score 0–3), `injection` (noul), `exfiltration` (noul). Затем **порог и действие — в ВАШЕМ коде**: `if (risk.score >= 1.5 || injection.noul >= 0.8) deny(); if (risk.score >= 0.5 || exfiltration >= 0.5) askUser(); return allow();` +- Ключевая идея: судить **действие, а не payload** — JSON schema валидирует форму (`send_email` с валидным списком адресов), а Jev судит intent/scope/proportionality («уместны ли 214 получателей для этой задачи»). Порог варьируют по «blast radius» (read_only / single_target / external_many). +- Позиционирование: «strict-typed decisions by construction», замена хрупкому «верни JSON» промпту. Латентность — сотни миллисекунд на каждый tool call (предупреждают о накоплении). Вендор говорит: **один слой defense-in-depth**, не замена sandboxing/least privilege. +- Community-реализации: `leepokai/jev-guard` (18★, deny/ask/allow на каждый tool call + injection flagging), `win4r/jev-security-scan` (ревью skills/MCP кода), `jev-mcp` / `typesafe-mcp`. +- Источник: https://typesafe-jev.com/en/use-cases/tool-approval/ , https://jevmodel.org/use-cases/tool-call-guardrails/ , https://docs.typesafe.ai/introduction/coding-agents + +--- + +## Итоговая карта: кто что даёт + +| Слой | Примеры | Сильная сторона | Слабость | +|---|---|---|---| +| In-harness hooks/callbacks | Claude Code PreToolUse, ADK, LangChain HITL, OpenAI SDK | Глубокая интеграция, доступ к полному контексту | Привязан к рантайму; «сам агент» часто и решает | +| Policy engine | OPA/Rego, Cedar/AVP | Детерминизм, аудируемость, CI-тесты, развязка policy/code | Не понимает семантику; нужен адаптер под MCP | +| MCP proxy/gateway | Invariant MCP-scan, Lasso Gateway | Независим от агента, перехват трафика в обе стороны | Доп. hop; статически не видит намерение | +| Guardrail/scan | LlamaFirewall, NeMo, Prompt Security | Ловит инъекции/утечки/токсичность | ML-вероятностность; не замена авторизации | +| Typed evaluation | Jev / TypeSafe | Судит intent и blast radius, калиброванные вероятности | Молодой, нишевый, добавляет латентность на каждый вызов | + +**Рекомендуемая композиция «привратника»:** deterministic policy engine (OPA для гибкости / Cedar для аудируемости) на сетевом MCP-proxy слое, дополненный ML-сканером для семантических рисков и typed-оценкой (Jev-подобной) для intent/blast-radius — с логированием каждого решения (probabilities + triggering rule) для апелляций и итерации правил. diff --git a/Research/Isolation of Agent Execution - OS and Container Level.md b/Research/Isolation of Agent Execution - OS and Container Level.md new file mode 100644 index 00000000..5236905a --- /dev/null +++ b/Research/Isolation of Agent Execution - OS and Container Level.md @@ -0,0 +1,195 @@ +--- +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.