Перейти к основному содержанию Перейти к навигации Перейти к нижнему колонтитулу

Безопасность и ограничения AI-агентов

Как CLI Rediacc предотвращает утечку секретов, перезапись учётных данных и повышение привилегий AI-ассистентами кодирования. Шлюзы знаний, редактирование, переопределения с проверкой цепочки предков и журнал аудита с хэш-связыванием.

Когда вы указываете AI-ассистент кодирования на вашу инфраструктуру, CLI Rediacc обнаруживает это. Если Claude Code, Cursor, Gemini CLI, Copilot CLI или любой другой AI-ассистент кодирования управляет rdc, CLI применяет иной набор правил, чем для человека за клавиатурой. На этой странице объясняется, что агент может делать, что не может, и как защитные ограничения удерживаются даже тогда, когда агент пытается их обойти.

Краткий справочник: что агенты могут и не могут делать

ОперацияПоведение агента по умолчаниюКак разблокировать для конкретного случая
rdc config show (с редактированием)✅ allowed
rdc config field get --pointer <pointer> (заглушка или дайджест)✅ allowed
rdc config field get --pointer <pointer> --digest✅ allowed
rdc config field set --pointer <pointer> (публичное поле)✅ allowed
rdc config field set --pointer <pointer> (чувствительное поле, с корректным --current)✅ allowed
rdc config edit --dump (редактированный JSONC)✅ allowed
rdc config audit {log, tail, verify}✅ allowed
rdc config field set --pointer <pointer> (чувствительное поле, без --current)🔴 refusedУказать --current "<старое значение>"
rdc config field get --pointer <pointer> --reveal🔴 refusedИспользовать --digest вместо этого
rdc config show --reveal🔴 refusedИспользовать простой rdc config show
rdc config edit (интерактивный редактор)🔴 refusedЧеловек устанавливает REDIACC_ALLOW_CONFIG_EDIT=* перед запуском агента
rdc config edit --apply <file>🔴 refusedТо же переопределение
rdc config field rotate --pointer <pointer>🔴 refusedТо же переопределение; использует интерактивное подтверждение
rdc term connect -m <machine> (прямой SSH на машину)🔴 refusedСначала сделать форк репозитория и подключиться к форку

Всё, в чём агенту отказывается, записывается в журнал аудита с outcome: refused и причиной.

Как агенты обнаруживаются

CLI считает процесс агентом, если выполняется хотя бы одно из условий:

  • Одна из переменных REDIACC_AGENT, CLAUDECODE, GEMINI_CLI, COPILOT_CLI установлена в "1", или CURSOR_TRACE_ID установлена вообще.
  • На Linux: любой родительский процесс в цепочке предков имеет одну из этих переменных в своём окружении (через /proc/<pid>/environ). Даже если агент удалит свои переменные с помощью env -i или скрипта-обёртки, родительская цепочка всё равно сообщит CLI, кто его запустил.

Обнаружение выполняется один раз на процесс и кэшируется. Его нельзя отключить.

Модель шлюза знаний

Чувствительные изменения следуют соглашению passwd(1): чтобы изменить секрет, докажите, что вы его уже знали. Одинаково для людей и агентов. Оба проходят через один и тот же шлюз. Нет никакого обхода типа «я сижу за клавиатурой».

  • Хотите ротировать токен API, хранящийся в /credentials/cfDnsApiToken?
  • CLI спрашивает: «какое текущее значение?»
  • Агент (или человек) предоставляет открытый текст через --current "$OLD". CLI хэширует $OLD с помощью SHA-256 и сравнивает с дайджестом хранящегося значения. Совпадение → запись выполняется. Несоответствие → отклонено, зафиксировано в аудите.
  • Для ротации без проверки предыдущего значения передайте --rotate-secret (взаимно исключающий с --current). Это громко записывается в журнал аудита как ротация.

Модель закрывает три поверхности атаки:

  1. Скрытая ротация: вызывающий (агент или человек) без предварительного доступа к $OLD не может заменить его своим значением.
  2. Утечка через зондирование: ответ с дайджестом никогда не содержит открытый текст; даже скомпрометированный журнал аудита показывает expected abc12345…, got deadbeef…, не базовые значения.
  3. Случайная перезапись конфигурации пользователя: требует намеренного --current каждый раз, даже в TTY. Ловит ошибку «я хотел установить STRIPE_TEST, но я в shell’е prod».

Структурированные подсказки следующего действия

Когда предусловие не выполняется, JSON-конверт (--output json) содержит структурированное поле errors[].next, которое точно говорит агентам, что предложить человеку:

{
  "errors": [{
    "code": "PRECONDITION_MISMATCH",
    "message": "...",
    "next": {
      "summary": "Provide the current value or acknowledge rotation.",
      "options": [
        { "description": "Re-read current digest, then retry with --current",
          "run": "rdc repo secret get --name mail --key STRIPE_KEY" },
        { "description": "Skip the precondition (rotation, audited)",
          "run": "rdc repo secret set --name mail --key STRIPE_KEY --value <new> --mode file --rotate-secret" }
      ]
    }
  }]
}

Агенты должны передавать next.options[].run в неизменном виде человеку, вместо того, чтобы синтезировать свои команды. Это избегает режима «агент придумывает команду, которой не существует» и держит оператора в контроле над действием.

Практический пример

# Получить короткий дайджест заглушки редактирования (безопасно для агентов).
$ rdc config field get --pointer /credentials/cfDnsApiToken
{"pointer": "/credentials/cfDnsApiToken", "value": "<redacted:secret>:abc12345"}

# Попытка перезаписи без доказательства: отклонено.
$ rdc config field set --pointer /credentials/cfDnsApiToken --new '"agent-picked-value"'
 Precondition failed: sensitive path requires --current (or --rotate-secret)

# Предоставить текущий открытый текст: разрешено.
$ rdc config field set --pointer /credentials/cfDnsApiToken \
    --current "$OLD_CF_TOKEN" \
    --new   "$NEW_CF_TOKEN"
Set /credentials/cfDnsApiToken

Если у агента никогда не было $OLD_CF_TOKEN, он не может выполнить предусловие, и ротация отклоняется. Пользователь, у которого есть токен, по-прежнему может это сделать через редактор или передав --current из своей оболочки.

Редактирование по умолчанию

Каждая команда rdc, которая читает чувствительное состояние: config show, config field get, config machine list, config edit --dump: возвращает заглушки редактирования для секретных полей, не открытый текст:

"sshKey":       "<redacted:credential>:9f3a2c1b"
"cfDnsApiToken":"<redacted:secret>:abc12345"
"storages.s3-prod.vaultContent": "<redacted:secret>:1f2e3d4c"

8-символьный шестнадцатеричный суффикс заглушки: это первые 8 символов sha256(canonicalize(value)): достаточно для различения двух разных значений с первого взгляда, недостаточно для обратного вычисления. Агент может использовать заглушку для отслеживания изменения значения, не видя его никогда.

--reveal снимает редактирование для людей на интерактивном TTY. Агентам отказывается независимо от состояния TTY. Каждое разрешение записывает запись аудита reveal_granted; каждый отказ записывает запись refused с прикреплёнными сигналами агента актора.

Переопределение REDIACC_ALLOW_CONFIG_EDIT

Некоторые операции: интерактивный редактор, --apply, field rotate: существуют для людей и не имеют безопасного пути для агентов. Если вы активно хотите, чтобы агент выполнил одну из них, вы устанавливаете:

export REDIACC_ALLOW_CONFIG_EDIT='*'          # полный обход
# или
export REDIACC_ALLOW_CONFIG_EDIT='/credentials/ssh/privateKey,/infra/cfDnsZoneId'
# (глобы области через запятую: подстановочные символы * допустимы на сегмент)

…и агент это наследует.

Важная деталь: переопределение должно появляться в процессе выше агента в цепочке предков. Если агент установит его в своём собственном окружении (или в порождённой им подоболочке), CLI откажет и сообщит об этом:

Interactive editor is blocked in agent environments (REDIACC_ALLOW_CONFIG_EDIT was set but ancestry verification failed: the override must be set by your shell, not by an agent).

Эффект: агент не может обойти ограничение, запустив export REDIACC_ALLOW_CONFIG_EDIT='*' в середине сессии. Только родительский процесс (вы, в своём терминале, перед запуском агента) может открыть эту дверь.

Поддержка платформ: как переопределение проверяется на каждой ОС

REDIACC_ALLOW_CONFIG_EDIT и REDIACC_ALLOW_GRAND_REPO оба полагаются на проверку цепочки предков, чтобы доказать, что переопределение установлено вами, а не внедрено агентом. Проверка работает на Linux, macOS и Windows, но источник данных, на который она опирается, отличается для каждой платформы, и уровень гарантии тоже различается:

ПлатформаИсточник данныхУровень гарантии
Linux/proc/<pid>/environ для каждого процесса вверх по цепочкеСнимок в момент exec, предоставляемый ядром. Процесс не может ретроактивно отредактировать, с чем он был запущен.
macOSСистемный вызов kern.procargs2, читаемый небольшим вспомогательным инструментом внутри rdcТо же свойство снимка exec как на Linux. Читаемо для собственных процессов без прав администратора.
WindowsБлок живого окружения каждого родительского процесса (PEB), читаемый тем же вспомогательным инструментом с защитой от переиспользования PIDСлабее: Windows не хранит снимок exec, поэтому проверка читает текущую память. Родителям по-прежнему невозможно переписать себя чем-либо, что обычно запускает агент, но источник данных не заморожен ядром, как на Linux и macOS.

На macOS и Windows CLI запускает свой встроенный бинарный файл renet для выполнения чтения; вспомогательный инструмент сообщает, какие из отслеживаемых переменных несёт каждый родитель, и вся логика решений остаётся в CLI. Если вспомогательный инструмент отсутствует, устарел или по какой-либо причине не работает, CLI не может проверить переопределение и отказывает безопасно: переопределение отклоняется и ошибка говорит, что проверка была недоступна, а не что вы что-то сделали неправильно. Рабочая установка никогда не покажет это сообщение; переустановка rdc восстанавливает вспомогательный инструмент.

Что остаётся верным на каждой платформе: переопределение должно быть уже присутствовать в окружении процесса агента при его запуске. Экспортируйте его в своём терминале, потом запустите агента. Агент, который устанавливает переменную в середине сессии, отклоняется.

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

Каждое изменение, каждый отказ, каждое разрешение --reveal записывает строку JSONL в ~/.config/rediacc/audit.log.jsonl (режим 0600, ротация при 10 МБ). Каждая строка связана хэшем: поле prevHash равно sha256("<предыдущая строка>"). Изменение любой строки разрывает цепочку во всех последующих строках.

{"ts":"2026-04-21T10:02:47.831Z","actor":{"kind":"agent","agentSignals":["CLAUDECODE"]},"command":"config field set","paths":["/credentials/cfDnsApiToken"],"outcome":"ok","configId":"...","configVersion":48,"prevHash":"sha256:9f3a..."}
{"ts":"2026-04-21T10:02:51.114Z","actor":{"kind":"agent","agentSignals":["CLAUDECODE"]},"command":"config edit","paths":[],"outcome":"refused","reason":"agent without REDIACC_ALLOW_CONFIG_EDIT=*","prevHash":"sha256:abc1..."}
{"ts":"2026-04-21T10:03:05.220Z","actor":{"kind":"human"},"command":"config show --reveal","paths":[],"outcome":"reveal_granted","configId":"...","configVersion":48,"prevHash":"sha256:deac..."}

Просмотр

# Список последних записей
rdc config audit log --since 24h

# Фильтр по глобу указателя
rdc config audit log --path '/credentials/*'

# Только записи от агентов
rdc config audit log --actor agent

# Потоковая трансляция новых записей в реальном времени (Ctrl+C для остановки)
rdc config audit tail

# Проверка целостности хэш-цепочки
rdc config audit verify
# → "Chain integrity verified across 247 entries."
#   ИЛИ
# → "Chain broken at line 103: file has been tampered with or corrupted."

Что никогда не появляется в журнале аудита

  • Открытый текст секретных значений
  • Парольные фразы, токены, SSH-ключи
  • Старые/новые значения при несоответствии предусловия --current (только 8-символьный префикс дайджеста)

Журнал можно безопасно передать проверяющему безопасности или прикрепить к отчёту об ошибке.

Ограничения поведенческой модели

Ограничения агента являются поведенческими, а не криптографическими. Решительный или специально настроенный агент, работающий с тем же UID, что и файл конфигурации, всегда может выполнить cat ~/.config/rediacc/rediacc.json и прочитать открытый текст, поскольку файл доступен для чтения процессом.

Для настоящего криптографического контроля используйте зашифрованное хранилище конфигурации: секреты хранятся на стороне сервера, каждое чувствительное поле несёт HMAC-обязательство на уровне поля, и воркер аккаунта отклоняет записи, чьё предусловие --current не совпадает по хэшу с хранящимися данными. Сервер никогда не видит открытый текст (нулевое знание), но шлюз применяется принудительно.

Локальный файл: лёгкий путь безопасен. Удалённое хранилище: обходной путь криптографически труден.

Что Rediacc не изолирует

Защитные ограничения агента на этой странице защищают собственную инфраструктуру Rediacc: файл конфигурации, Docker-демон каждого репозитория, LUKS-зашифрованные данные репозитория, ограниченную SSH-песочницу. Они не защищают внешние сервисы, для которых ваш репозиторий хранит учётные данные.

Форк репозитория это BTRFS reflink тома родителя. Всё, что хранится на диске у родителя, побайтово идентично в форке: код, данные и .env файлы одинаково. Если ваш репозиторий содержит STRIPE_LIVE_KEY, AWS_ACCESS_KEY_ID, токен Railway API или любые другие долгоживущие учётные данные для стороннего сервиса, форк наследует их. Агент, работающий в песочнице форка, может прочитать этот файл, экспортировать значение или использовать его для вызовов стороннего API. У стороннего сервиса нет способа узнать, что вызов пришёл из форка, а не из продакшн.

Это линия разделения ответственности:

ГраницаВладелец
Данные репозитория, пространство имён монтирования, область Docker, защитные ограничения агента, журнал аудита, инъекция секрета во время развертыванияRediacc
Код приложения, который использует эти секреты, и любые учётные данные, встроенные в образ во время сборкиРазработчик репозитория

Основная защита встроена: секреты для каждого репозитория хранятся в отдельной области от зашифрованного образа репозитория и не копируются через границу форка. Контейнеры форка загружаются с пустой картой секретов и идентифицируют себя как другой внешний субъект, чем родитель. Устанавливайте их с помощью rdc repo secret set (режим env для интерполяции compose, режим file для блоков tmpfs secrets:). Шлюз мутации одинаков. И люди, и агенты должны предоставить --current (предусловие passwd-стиля) или --rotate-secret (ротация в журнале аудита) для перезаписи или удаления существующего значения.

Кроссрепозиторная изоляция применяется принудительно. Вредоносный или халатный compose-файл в репо B не может ссылаться на каталог секретов репо A. Валидатор compose renet жёстко отклоняет любой путь secrets: file:, configs: file: или env_file:, который указывает за пределы директории ${REDIACC_NETWORK_ID} текущего репо, и отклонение НЕ переопределяется с помощью --unsafe. Оборона в глубину: песочница Landlock вокруг bash-подпроцесса Rediaccfile ограничивает чтение файловой системы только директорией секретов текущей сети, поэтому cat /var/run/rediacc/secrets/<other>/X из вредоносного Rediaccfile не срабатывает с EACCES на уровне ядра.

Два дополнительных шаблона закрывают граничные случаи:

  1. Не встраивайте учётные данные продакшена в саму файловую систему репозитория. .env файл, коммитенный в образ, или учётные данные, сохранённые в томе во время up(), рефлинкиются в форк. Функция секретов для каждого репозитория защищает только значения, которые вы храните в плоскости секретов. Она не может постфактум защитить байты, которые уже живут внутри LUKS-образа. Для существующих репо с встроенными .env файлами поднимите их в секреты для каждого репозитория вручную.
  2. Ограничьте исходящий сетевой трафик форка с помощью eBPF egress-фильтрации так, чтобы форк мог достигать только localhost и явных конечных точек песочницы. Сетевая изоляция Rediacc для каждого репозитория является основой; allowlist исходящего трафика для каждого форка не построен сегодня, но путь открыт.

Rediacc обрабатывает инъекцию во время развертывания, кросс-форк изоляцию и кросс-репо изоляцию. Половина «не встраивайте в образ» лежит на вас.

Быстрые рецепты

Разрешить агенту ротацию одного облачного токена

# Под вашей учётной записью, перед запуском агента:
export REDIACC_ALLOW_CONFIG_EDIT='/credentials/cfDnsApiToken'
claude-code              # или cursor, gemini и т. д.

Теперь агент может выполнить config field rotate /credentials/cfDnsApiToken --new …, но по-прежнему не может редактировать /credentials/ssh/privateKey или открыть интерактивный редактор.

Разрешить агенту широкую сессию редактирования конфигурации

export REDIACC_ALLOW_CONFIG_EDIT='*'
claude-code

Агент может открыть rdc config edit, использовать --reveal и запустить field rotate. Каждое действие по-прежнему записывается в журнал аудита с actor.kind: agent и сигналом CLAUDECODE.

Узнать, какие поля агент может трогать

rdc config field list --sensitive --output json

Возвращает каждый шаблон указателя, его тип (secret / credential / pii / identifier) и входит ли он в HMAC-конверт на стороне сервера.

Смотрите также