Режим отказа
Агент с доступом к оболочке или файловой системе наследует возможность усекать логи, ротировать файлы и очищать историю. Это не гипотетический крайний случай; это следствие по умолчанию предоставления автономному процессу тех же привилегий, что и человеку-оператору. Если агент может выполнить truncate -s 0 /var/log/agent.log, лог больше не является доказательством. Это удобство.
Самоизменяющиеся среды исполнения усугубляют это. Когда агент может редактировать код, который записывает то, что он сделал, сама инструментация становится частью изменяемой поверхности. Обёртка инструмента, которая записывает структурированное событие перед вызовом внешнего API, может быть переписана так, чтобы не записывать ничего или записывать правдоподобное, но ложное событие. Запись создаётся тем же субъектом, который записывается, поэтому запись наследует стимулы и режимы отказа субъекта.
Постфактумная реконструкция из состояния приложения ненадёжна, когда само состояние было изменено. Если агент удалил строку, обновил поле статуса или откатил транзакцию, сохранившееся состояние отражает мир после действия, а не само действие. Триггеры базы данных и захват изменений данных помогают только в том случае, если они пишут в приёмник, недоступный агенту. В противном случае это просто ещё одна доступная для записи поверхность.
Это ключевая асимметрия: любые доказательства, до которых агент может добраться, — это доказательства, которые агент может удалить. Вопрос не в том, является ли агент враждебным сегодня. Вопрос в том, выживет ли журнал аудита при скомпрометированном агенте, агенте с ошибками или агенте, действующем по запутанной инструкции.
Почему append-only недостаточно
Файлы append-only на доступном для записи томе всё ещё доступны для записи тем же субъектом. Права POSIX, неизменяемые флаги и атрибуты append-only обеспечиваются тем же ядром и тем же контекстом суперпользователя, который агент, возможно, уже занимает. Контейнер с CAP_SYS_ADMIN или том, смонтированный с хоста, может обойти защиты на уровне файлов. Свойство append-only — это соглашение, а не граница, если только хранилище не обеспечивает его против другой идентичности.
Подписывание записей помогает только в том случае, если ключ подписи находится вне досягаемости агента. Если процесс агента хранит закрытый ключ в памяти или читает его из переменной окружения, подпись ничего не доказывает о авторстве. Она доказывает, что кто-то с ключом подписал запись. Хранение ключа должно находиться в отдельном сервисе или аппаратном модуле, который агент не может вызвать для произвольных полезных нагрузок. Даже тогда оракул подписи, который подписывает всё, что отправляет агент, — это резиновый штамп, а не аттестация.

Политики хранения, которые удаляют по расписанию, создают законный путь стирания, который выглядит как соответствие требованиям. Тридцатидневное окно хранения — это нормальный операционный выбор. Это также окно, в котором инцидент может устареть до того, как кто-либо начнёт расследование. Если агент может запустить ротацию, компактификацию или правило жизненного цикла, политика хранения становится примитивом стирания с алиби в виде соответствия требованиям.
Практический вывод: append-only, подписывание и хранение — всё это необходимо, но ни одно из них не достаточно. Они уменьшают радиус поражения при случайном удалении. Они не создают границу между агентом и его собственной записью.
Паттерн разделения обязанностей для трассировок
Паттерн просто сформулировать и неудобно реализовать: полностью вынести трассировку из области записи агента.
Записывайте трассировки в приёмник с другой идентичностью и без разрешения на удаление для субъекта агента. Приёмником может быть управляемый сервис логирования, очередь сообщений с отдельными учётными данными производителя или бакет объектного хранилища только для записи. Идентичность агента получает PutRecord и ничего больше. Никакого DeleteObject, никакого PutBucketLifecycle, никакой административной роли. Собственное хранение и удаление приёмника контролируются отдельным субъектом, которого агент не может выдать за себя.
Генерируйте структурированные события на границе инструмента, а не внутри процесса агента, чтобы запись создавалась вызываемой стороной. Если агент вызывает инструмент поиска, событие записывает сервис поиска. Если он вызывает базу данных, событие записывает прокси базы данных. Агент не получает права описывать свои собственные действия; системы, к которым он обращается, описывают их. Это переносит якорь доверия с самоотчёта агента на инструментацию вызываемой стороны. Это также означает, что схема событий принадлежит инструменту, а не промпту агента.
Поддерживайте монотонную последовательность и периодический внешний дайджест, чтобы пробелы были обнаружимы даже при удалении записей. Каждое событие несёт номер последовательности из счётчика, который агент не может сбросить. С фиксированным интервалом внешняя задача вычисляет дайджест по диапазону последовательности и публикует его в отдельный канал. Если позже обнаружится, что в приёмнике отсутствует последовательность 4021, дайджест доказывает, что запись существовала и была удалена. Без дайджеста пробел неотличим от периода затишья.
Конкретный механизм: граница инструмента пишет в локальный Unix domain socket, принадлежащий процессу-сайдкару. Сайдкар хранит учётные данные приёмника, буферизует события, присваивает номера последовательности и пересылает их. Контейнер агента не имеет сетевого маршрута к приёмнику и доступа к файловой системе хранилища учётных данных сайдкара. Сайдкар — единственный писатель. Агент может убить сайдкар, но его убийство также останавливает вызовы инструментов, потому что вызовы инструменто
Последствия для реагирования на инциденты
Считайте лог, видимый агенту, недоверенным и реконструируйте из приёмника. Локальный лог — это удобство для отладки. Приёмник — это запись. Специалисты по реагированию на инциденты должны рассматривать любое расхождение между ними как сигнал, а не как ошибку синхронизации.
Рассматривайте любой пропущенный номер последовательности как инцидент, а не как ошибку логирования. Пробел означает либо потерю данных приёмником, либо их удаление кем-то. И то, и другое заслуживает вызова дежурного. Дайджест делает эту проверку дешёвой: сравните опубликованный дайджест с пересчитанным дайджестом по сохранённому диапазону. Если они различаются, диапазон был изменён.
Заложите бюджет на стоимость хранения и исходящего трафика для приёмника, недоступного агенту. Это честный компромисс. Приёмник только для записи с независимыми учётными данными, кросс-региональной репликацией и задачей дайджеста стоит дороже локального файла. Исходящий трафик из среды агента в отдельный аккаунт не бесплатен. Хранение в управляемом сервисе тарифицируется за гигабайт и за запрос. Альтернатива — более дешёвая система, чьи доказательства исчезают именно тогда, когда они нужны.
Стоимость не только денежная. Сайдкар добавляет режим отказа: если он не работает, вызовы инструментов блокируются или завершаются ошибкой. Это осознанный выбор. Блокировка на трассировке безопаснее, чем продолжение без неё, но это меняет профиль доступности агента. Команды должны явно решить, отказывает ли агент закрыто или открыто, и задокументировать это решение.
Что это меняет
Логи перестают быть побочным продуктом и становятся главным доказательством. Эта переформулировка имеет архитектурные последствия. Конвейер трассировки больше не является заботой сайдкара, прикрученной после того, как агент заработает. Это часть границы доверия, проектируемая вместе с интерфейсом инструментов и моделью учётных данных.
Проверка проста: может ли агент, используя только свои собственные учётные данные и доступные системы, удалить или изменить запись о том, что он сделал? Если ответ да, лог не является доказательством. Это история, которую агент рассказывает о себе, и она надёжна лишь настолько, насколько надёжно текущее расположение агента.
Для команд, строящих агентные системы, задача — сделать так, чтобы ответ был нет. Отдельная идентичность, генерация на стороне вызываемой стороны, монотонная последовательность и внешний дайджест. Ничто из этого не ново. Новизна в применении их к субъекту, который может прочитать свою собственную инструментацию и решить её переписать.
