AI-агенты в песочнице: как я перестал бояться давать Claude доступ к системе

AI-агенты в песочнице: как я перестал бояться давать Claude доступ к системе

Долго сопротивлялся тому факту, что Claude Code имеет полный доступ к моему терминалу (не открытие, но я всегда на эту часть знаний закрывал глаза). Может запускать любые bash-команды. Читать ~/.ssh, переменные окружения с токенами. Всё.

Галлюки тоже с ростом проекта и его сложностью – возрастают. Например, он пытался запустить несуществующую команду. Безобидно, конечно. Но мысль осталась: а что если следующая галлюцинация будет с rm -rf или curl с моими секретами куда-нибудь не туда? Тем более что обнаруженные промпт-инъекции всё чаще находят уже те, кто пострадал.

Проблема: AI-агенты – это не просто чатботы

Есть принципиальная разница между ChatGPT в браузере и Claude Code / Cursor Agent. Первый может только текст генерировать. Вторые – выполняют команды. Реальные команды на твоей машине.

Что видит AI-агент в типичном сетапе:

  • Полный доступ к файловой системе (включая ~/.ssh, ~/.config)
  • Все переменные окружения (SERVER_1_API_KEY, BLA_BLA_ACCESS_KEY, всё что ты там экспортируешь)
  • Возможность запускать любые shell-команды
  • Историю bash с твоими прошлыми командами
  • Git-коммиты, хронологию и тд

Галлюцинации + shell = потенциальный риск. Как ранее говорил, AI иногда выдумывает команды, путает синтаксис, или пытается сделать «лучше» без спроса. Особенно когда контекст уже перевалил за 90% в допустимом буфере.

Пара реальных сценариев, которые могут случиться:

  • AI решает «почистить» временные файлы и промахивается с путём
  • Отправляет диагностику куда-то через curl (видел такое в логах у другого блогера)
  • Добавляет вредоносный MCP в конфигуратор (а supply chain атаки – уже не теория)
  • Читает .env файл и включает его содержимое в ответ, который уходит в API

Не то чтобы это происходит каждый день. Но когда работаешь с чем-то важным – хочется подстраховаться. Да и параноик я по жизни.

А ещё с ростом проекта ты начинаешь обзаводиться тех. долгом и сессия работы агента начинает растягиваться (у меня стабильно 10+ минут на каждую таску) + уже работаю в двух терминалах, знаю людей, у которых их уже 6+. Хочется в момент ожидания не тиктоки листать и в телеге залипать, а следующие таски запускать. Это та самая дофаминовая петля – мозг требует ещё и ещё результатов. Но такой подход ломается, если ты не запускаешь Claude в режиме без ограничений (чтобы каждый чих не апрувить и согласовывать).

Решение: Dev Containers как песочница

AI-агенты в песочнице: как я перестал бояться давать Claude доступ к системе

Использую: Dev Container. Это способ запускать окружение разработки внутри Docker-контейнера. VS Code (или Cursor) подключается к нему, и ты работаешь как обычно. Только изолированно от хост-системы.

Почему именно devcontainer, а не просто Docker:

  • Интеграция с IDE из коробки – расширения, терминал, отладка работают прозрачно
  • Стандартизированный формат – devcontainer.json понимают VS Code, Cursor, Antigravity
  • Удобное управление секретами через remoteEnv
  • Можно настроить один раз и забыть

Философия простая: AI в контейнере. Сломает что-то – пересоздашь за минуту. Хост-система в безопасности.

Чем не угодили автору изолированные git-ветки и просто deny в настройках агентов?

  1. Я и так пользуюсь изолированными ветками для всех задач (и сессий, в которых понимаю, что будут изменения в нескольких файлах). Вернуться на пару коммитов раньше и начать заново намного быстрее, чем заново контейнер поднимать.
  2. Deny можно замутить, но я за месяцы работы так и не смог толком сформировать глобальный файл конфигурации, чтобы его можно было ctrl+c / ctrl+v из одного проекта в другой. А ещё, поверьте, если он захочет получить доступ к файлу – он этот deny найдёт как обойти. У меня до абсурда кейс был: когда он не смог получить доступ, пошёл написал shell-скрипт, не смог его запустить, пошёл в python, сделал py-скрипт и там всё-таки добрался до нужного.

Что из себя представляет devcontainer

Дисклеймер: я очень, подчеркну, очень мало работал с контейнерами, но мне эта тема интересна. И если я где-то в чём-то перемудрил или наоборот сделал хуже – можете кинуть какашку в комментарии, но я буду безмерно благодарен, если дадите конструктивный совет 🔥

Вот примитивная конфигурация, которую использую (это проект по выгрузке постов из телеги в md-формате).

devcontainer.json:

{"name":"my-project","build":{"dockerfile":"Dockerfile"},"features":{"ghcr.io/devcontainers/features/node:1":{"version":"20"}},"remoteEnv":{"TELEGRAM_API_ID":"${localEnv:TELEGRAM_API_ID}","TELEGRAM_API_HASH":"${localEnv:TELEGRAM_API_HASH}","ANTHROPIC_API_KEY":"${localEnv:ANTHROPIC_API_KEY}"},"mounts":["source=project-data,target=/workspaces/project/data,type=volume"],"runArgs":["--cap-drop=ALL","--security-opt=no-new-privileges"],"postCreateCommand":"bash .devcontainer/post-create.sh","remoteUser":"vscode"}

Чуть-чуть пояснения:

--cap-drop=ALL – сбрасываем все Linux capabilities. Контейнер не может менять сетевые настройки, монтировать файловые системы, работать с устройствами. Только базовые операции.

--security-opt=no-new-privileges – процессы внутри контейнера не могут повышать привилегии. Даже если AI найдёт какой-то эксплойт – не сможет им воспользоваться.

remoteEnv – секреты передаются из хост-системы в контейнер, но не записываются в образ. Если кто-то получит доступ к образу – секретов там не будет.

Named volume для данных – персистентные данные (например, сессии) хранятся в Docker volume, а не в bind mount. Изоляция от хост-файловой системы.

remoteUser: vscode – работаем от непривилегированного пользователя, не от root.

Dockerfile – минимальный:

FROM mcr.microsoft.com/devcontainers/python:3.12RUN apt-get update && apt-get install -y --no-install-recommends \ libffi-dev \ libssl-dev \ && rm -rf /var/lib/apt/lists/*WORKDIR /workspaces/projectUSER vscode

post-create.sh – инициализация после создания контейнера:

#!/bin/bashset -e # Node.js доступен здесь (установлен через features) sudo npm install -g @anthropic-ai/claude-code # Python окружение python -m venv .venv source .venv/bin/activate pip install -r requirements.txt

Всё это дело можно упростить следующим образом:

  1. Открываете любого AI-агента и проект, который раньше у вас запускался не в контейнере.
  2. Создаёте ему задачу следующего типа:

Данный проект должен иметь возможность запускаться в devcontainer. Создай необходимые файлы конфигурации. Конфигурацию создай на основе описания проекта, зависимостей. По необходимости создай скрипты по установке дополнительных инструментов после сборки образа.

Во что я вляпался, пока всё это отлаживал

Показать только результат – скучно же.

npm недоступен при сборке образа. Пу-пу-пу. Хотел установить Claude Code CLI прямо в Dockerfile через npm install -g. Получил ошибку: npm not found.

Причина: Features (включая Node.js) применяются ПОСЛЕ сборки Dockerfile. Это, видимо, особенность архитектуры devcontainers. Dockerfile собирается первым, потом накатываются features, потом запускается postCreateCommand. Ну либо я рукожоп.

Решение: перенёс установку CLI в post-create.sh. Там Node.js уже доступен.

Кэширование PATH в bash. После установки Claude Code и других CLI-полезностей через npm новый путь добавляется в PATH. Но если терминал уже открыт (а я делаю это всё внутри Cursor) – bash помнит старый PATH. Получаешь «claude: command not found», хотя всё установлено.

Решение: перезапустить терминал или выполнить hash -r для сброса кэша команд.

Секреты не пробрасываются. Настроил remoteEnv, но переменные пустые внутри контейнера.

Причина: переменные должны быть экспортированы на хосте ДО запуска контейнера. Если добавил export TELEGRAM_BLA_BLA_KEY=... после – нужно пересоздать контейнер.

Чего этот подход НЕ решает

Важно понимать ограничения.

AI всё ещё видит код проекта. Сам ору с этого тезиса, но следующая мысль важна. Если в коде есть захардкоженные секреты (не делайте так) – AI их увидит. Вычищайте всё заранее.

Сетевой доступ есть. Контейнер может делать запросы в интернет. Можно ограничить через --network none, но тогда сломается npm install, pip install, git clone и вообще всё полезное. Возиться с white-списком мне лень.

Секреты в remoteEnv доступны AI внутри контейнера. Внутри контейнера AI может прочитать эти переменные (если захочет). Разница в том, что он не видит ВСЕ секреты хост-системы – только те, что явно пробросили.

Первый запуск = сборка образа. Готовьтесь ждать несколько минут. У меня две минуты на чистую сборку. Потом кэш спасает.

Не защищает от логических ошибок. Если AI сгенерирует код с SQL-инъекцией – devcontainer никак не поможет. Это про изоляцию окружения, не про code review.

Когда это нужно, а когда overkill

Используй devcontainer, если:

  • У тебя на устройстве корпоративные проекты
  • Работаешь с реальными API-ключами и секретами
  • Проект связан с продакшн-инфраструктурой
  • Есть доступ к чувствительным данным (клиентские данные, финансы)
  • Хочешь воспроизводимое окружение для команды
  • Паранойя – твоё второе имя

Не заморачивайся, если:

  • Pet-проект без секретов
  • Личный комп, на котором ничего важного нет
  • Учебный код
  • Публичный open-source без credentials
  • Доверяешь AI больше, чем я

Как сделать такое же у себя?

Если решил попробовать, вот что нужно:

  1. Установи Docker Desktop и Dev Containers (расширение для Cursor).
  2. Создай папку .devcontainer в проекте
  3. Добавь devcontainer.json с базовой конфигурацией
  4. Добавь runArgs с --cap-drop=ALL и --security-opt=no-new-privileges
  5. Пробрось только нужные секреты через remoteEnv
  6. Установи AI-инструменты в postCreateCommand, не в Dockerfile
  7. Проверь что всё работает: Cmd+Shift+P → «Reopen in Container» в IDE
AI-агенты в песочнице: как я перестал бояться давать Claude доступ к системе

Занимает 15-20 минут на первую настройку.

AI-агенты – новая категория инструментов, и практики безопасности для них ещё формируются. Dev Containers – один из возможных подходов, который лично мне даёт спокойствие при работе с Claude Code на проектах с секретами.

А вы как защищаете систему от AI-агентов? Или просто доверяете и не паритесь? Делитесь опытом.

Начать дискуссию