Skip to main content
Glama

agent-sandbox

Я создал это, чтобы ИИ-агент для написания кода мог выполнять реальные команды инфраструктуры против реального кластера Kubernetes — не имея при этом постоянных учетных данных и не имея возможности что-либо разрушить без присмотра.

Три MCP-инструмента. Каждый вызов выполняется внутри Kubernetes Job в песочнице gVisor с кратковременными, узко ограниченными учетными данными, которые Vault выпускает для этого единственного действия. Любые разрушительные действия останавливаются на этапе одобрения человеком.

AI Agent (Claude Desktop / Cursor)
        │  MCP protocol (stdio)
        ▼
┌──────────────────────────────────────────┐
│  MCP Server            src/agent_sandbox │
│    3 tools -> guardrails -> broker ->    │
│    sandbox -> audit                      │
└───────┬──────────────────────┬───────────┘
        │                      │
        ▼                      ▼
┌────────────────┐   ┌──────────────────────────┐
│ Credential     │   │ Sandbox Runner           │
│ Broker (Vault) │   │ K8s Job + gVisor         │
│ 10-min leases  │   │ restricted PSS           │
│ per-action     │   │ default-deny NetworkPolicy│
│ scope          │   │ cpu/mem limits, deadline │
└────────────────┘   └──────────────────────────┘
        │                      │
        └──────────┬───────────┘
                   ▼
        ┌──────────────────────┐
        │ Guardrails + Approval│
        │ policy.yaml, SQLite, │
        │ agent-sandbox CLI    │
        └──────────────────────┘

Зачем я это создал

Один ИИ-инструмент, которым я пользовался, однажды предложил изменение Terraform для производственной инфраструктуры, которое привело бы к принудительной замене живого ресурса. План выглядел обычным. Причиной сбоя была не ошибка модели — а то, что между правдоподобным планом и разрушительным применением не было ничего.

Я создал этот проект как недостающий слой, в рабочем коде:

  • агент никогда не имеет учетных данных, которые можно использовать повторно

  • всё выполняется там, где не может навредить хосту

  • разрушительные изменения останавливаются и ждут человека

  • каждое действие фиксируется

make demo воспроизводит именно тот сценарий, с которым я столкнулся. Изменение метки в одну строку приводит к принудительной замене работающего Deployment, и шлюз это ловит.

Related MCP server: Emisar

Быстрый старт

Требуются Docker, kind, kubectl, vault, terraform и Python 3.11+.

brew install kind kubectl hashicorp/tap/vault terraform
make up      # ~5 minutes from cold: cluster, CNI, gVisor, Vault, image, verify
make demo    # the forces-replacement guardrail demo
make down    # tear it all down

make up идемпотентен. Он завершается запуском make verify, который доказывает утверждения об изоляции, а не просто заявляет их (см. ниже).

Направьте на него агента

cp examples/claude_desktop_config.json \
   ~/Library/Application\ Support/Claude/claude_desktop_config.json

Cursor: скопируйте examples/cursor_mcp.json в .cursor/mcp.json. Затем попросите агента "проверить статус подов в demo-app" или "спланировать terraform для k8s-demo".

Три инструмента

Инструмент

Риск

Поведение

k8s_get_pod_status(namespace)

низкий

Выполняется немедленно. Учетные данные ограничены get/list/watch pods в одном namespace.

terraform_plan(working_dir)

низкий

Выполняется немедленно. Сохраняет план, чтобы последующее применение выполняло точно проверенный diff.

terraform_apply(working_dir, approval_id?)

высокий

Без approval_id: вычисляет план, записывает ожидающее одобрение, ничего не применяет. С ним: использует одобрение и применяет сохраненный план.

Четыре компонента

1. Изолированное выполнение — src/agent_sandbox/sandbox.py

Одноразовый Job на каждый вызов инструмента. Каждый контроль здесь имеет конкретную причину:

Контроль

Предотвращает

runtimeClassName: gvisor

Системные вызовы попадают в sentry gVisor, а не в ядро хоста

PSS restricted, применяемый API-сервером

root, повышение привилегий, capabilities, записываемая rootfs

automountServiceAccountToken: false

Любая фоновая идентичность кластера внутри песочницы

NetworkPolicy с запретом по умолчанию + allowlist API-сервера

Исходящий интернет-трафик, боковое перемещение, метаданные-эндпоинты

resources.limits, activeDeadlineSeconds

Вышедший из-под контроля Job, который голодает узел или зависает навсегда

backoffLimit: 0

Неудачное разрушительное действие, которое молча повторяется

Учетные данные монтируются как файл, а не переменная окружения — переменные окружения утекают через kubectl describe, /proc и дампы при сбоях.

2. Брокер учетных данных — src/agent_sandbox/broker.py

cred = broker.issue_scoped_credential("k8s_get_pod_status")
# -> Vault mints a ServiceAccount + Role + RoleBinding, 10-minute lease
# -> revoked immediately after the Job finishes
  • Агент никогда не выбирает свою область действия. Область выводится из действия.

  • Запрет по умолчанию. Действие без сопоставленной области не получает учетных данных.

  • Радиус поражения ограничен. Запрос любого namespace, кроме целевого, отклоняется.

  • Токен никогда не покидает модуль. Credential.__repr__ выводит token=<redacted>, так что даже случайный лог не может его раскрыть.

Я проверил это вручную: токен pod-reader перечисляет поды в demo-app, отклоняется в kube-system, отклоняется для секретов и перестает работать в момент отзыва его аренды — не оставляя за собой ServiceAccount.

3. Защитные механизмы — policy/policy.yaml, src/agent_sandbox/guardrails.py

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

Одобрения защищены от очевидных атак:

  • одноразовые — расходуются в одной SQLite-транзакции, так что два одновременных применения не могут использовать одно одобрение

  • привязаны к параметрам — привязаны к хэшу точного инструмента + параметров, так что одобрение для k8s-demo нельзя воспроизвести против prod-cluster

  • с истечением срока — 30 минут по умолчанию

  • внеполосные — выдаются через отдельный CLI-процесс. Нет MCP-инструмента для одобрения чего-либо; у агента нет пути кода для одобрения собственного запроса.

4. MCP-сервер — src/agent_sandbox/server.py

Построен на официальном Python SDK (mcp 2.0, MCPServer). Транспортный слой намеренно тонкий и не дает собственных полномочий — ошибка там не может расширить возможности агента, потому что политика и Pod Security admission API-сервера являются фактическими контролами.

Журнал аудита

Каждый вызов создает коррелированную цепочку событий в var/audit.jsonl:

tool.request -> guardrail.decision -> credential.issued -> sandbox.started
   -> sandbox.completed -> credential.revoked -> tool.result
make audit
./.venv/bin/agent-sandbox audit --request-id req-4239b8bb5459 --json

Значения учетных данных рекурсивно очищаются перед записью; область, идентификатор аренды и TTL сохраняются. Тест проверяет, что ни одна строка в форме JWT никогда не попадает в журнал.

Проверено, а не предположено

Две вещи в этом проекте легко заявить и тихо не иметь, поэтому я не принимал их на веру. make verify проверяет обе на живом кластере:

== 1. gVisor kernel check ==
     kernel reported: Linux version 4.19.0-gvisor
  PASS: sandbox runs on the gVisor sentry kernel
== 2. NetworkPolicy egress enforcement check ==
  PASS: baseline connectivity works (got PONG)
  PASS: default-deny egress enforced (traffic blocked)

Это выявило реальную проблему, пока я его создавал. Стандартный CNI kind (kindnet) принимает объекты NetworkPolicy и молча игнорирует их — я применил политику запрета исходящего трафика по умолчанию, и трафик между подами всё равно проходил. Песочница выглядела бы изолированной, имея при этом полный сетевой доступ. Я исправил это, отключив kindnet и установив Calico, который применяет политики по-настоящему. См. scripts/install-calico.sh.

Я столкнулся с похожей ловушкой при добавлении API-сервера в allowlist: ClusterIP не работает, потому что kube-proxy делает DNAT к реальному эндпоинту до того, как Calico оценивает исходящий трафик. Симптомом была песочница, которая просто зависала без события об отказе политики, объясняющего это. Документировано в scripts/apply-sandbox-policy.sh.

Честные ограничения

  • gVisor работает, но это всё еще kind. Я установил runsc внутри узла kind (контейнер в Linux VM Docker Desktop) и проверил, что он активен. Это настоящая песочница gVisor, а не узел, закаленный для продакшена.

  • Путь AWS/STS условен. scripts/vault-setup.sh настраивает AWS secrets engine Vault только при наличии реальных учетных данных AWS; без них он пропускается и сообщает об этом. Я не хотел имитировать этот путь только для того, чтобы демо выглядело полным. Живой, демонстрируемый путь учетных данных — это Kubernetes, который полностью реален: динамические ServiceAccounts, реальный RBAC, реальные аренды, реальный отзыв.

  • Vault работает в dev-режиме — в памяти, root-токен root, без печати. Подходит для локального проекта, но не для развертывания как есть.

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

  • Одноузловой кластер, поэтому PVC, хранящий состояние Terraform, имеет ReadWriteOnce на одном узле.

Структура

cluster/      kind config, RuntimeClass, namespaces, RBAC, network policy
images/       sandbox runner image (terraform + kubectl, providers vendored)
policy/       guardrail policy: risk tiers and destructive signals
scripts/      up/down, gVisor + Calico install, verification, demo
src/          the package: broker, sandbox, guardrails, approvals, audit, MCP
terraform/    demo module managed by the agent
tests/        56 unit tests + a real-stdio MCP integration check

Тестирование

make test       # 56 unit tests, no cluster required
make test-mcp   # drives the server over real MCP stdio (needs the stack up)
make verify     # proves gVisor + NetworkPolicy enforcement on the live cluster
F
license - not found
Not graded
quality - not tested
C
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Servers

  • A
    license
    Not graded
    quality
    C
    maintenance
    Enables AI agents to securely perform privileged actions like creating GitHub issues by minting short-lived, single-purpose tokens on demand, with policy enforcement and audit logging.
    MIT
  • F
    license
    Not graded
    quality
    A
    maintenance
    Give AI agents Zero-Trust access to production infrastructure without the risks of granting them shell access. Actions are bounded by policy and an on-host runner.
    409
  • F
    license
    Not graded
    quality
    B
    maintenance
    Enables AI coding agents to evaluate actions against team-defined policies, record decisions, and obtain human approvals for potentially risky operations.
    165
    1
  • A
    license
    C
    quality
    B
    maintenance
    A policy-aware MCP server for GitHub and GitHub Actions that enables safe AI-assisted infrastructure workflows—inspecting repositories, preparing branches and pull requests, and constrained remote mutations behind explicit preview-bound approval tokens.
    18
    MIT

View all related MCP servers

Related MCP Connectors

  • Let AI operate servers without SSH. Choose actions, approve risky changes, and audit every step.

  • Runtime permission, approval, and audit layer for AI agent tool execution.

  • The bridge from K2 agents through Wrangler to your master AI - safe, approval-gated Cloudflare ops.

View all MCP Connectors

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Mustafa12z/agent-mcp-sandbox'

If you have feedback or need assistance with the MCP directory API, please join our Discord server