Слепое пятно в телеметрии безопасности агентов
Большая часть телеметрии безопасности агентов строится вокруг содержимого. Промпты сканируются на строки инъекций, аргументы инструментов проверяются на секреты, ответы модели фильтруются на нарушения политик. Это полезная работа, и она также неполна так, что это легко упустить: запрос может быть полностью безобидным по полезной нагрузке и враждебным по пункту назначения и времени. Полезная нагрузка говорит GET /. Пункт назначения говорит, что этот агент никогда раньше не общался с этим хостом, и это четырнадцатый новый хост за последнюю минуту.
Списки разрешённых на каждый вызов не фиксируют последовательность. Если агенту разрешено достигать хоста A, хоста B и хоста C, то каждый отдельный вызов проходит. Эксплойт — это не какой-то один вызов. Эксплойт — это A, затем B, затем C, именно в этом порядке, в течение короткого окна, где A возвращает токен, который принимает B, а B возвращает локатор, который разрешает C. Каждый переход авторизован. Перемещение — нет. Инспекция содержимого не может это увидеть, потому что содержимое в порядке. Форма трафика — это и есть атака.
Этот пробел и призван закрыть журнал исходящего трафика.
Что записывает журнал исходящего трафика
Журнал исходящего трафика — это дописываемый только в конец журнал каждого исходящего сетевого события, которое производит агент, записываемый в точке, где соединение фактически устанавливается. Единица записи — пункт назначения, а не сообщение.
Для каждого события журнал должен фиксировать как минимум:

- идентичность пункта назначения: имя хоста, значение SNI или идентификатор, который клиент фактически использовал для адресации узла
- разрешённый адрес: IP, в который разрешилось имя в тот момент, что важно, потому что DNS — это плоскость управления, через которую можно управлять агентом
- протокол и порт: HTTPS, DNS, SMTP, сырой TCP и фактически использованный порт
- временная метка первого появления за запуск: не только когда произошло это событие, но и появлялся ли этот пункт назначения в этом запуске раньше
- идентичность запуска и агента: какой агент, какое выполнение, какая родительская задача его породила
Журнал ведётся по запуску, и запуск — это важная область. Пункт назначения, нормальный для долгоживущего воркера приёма данных, является новым для короткоживущего агента планирования. Кардинальность и новизна имеют смысл только относительно запуска, к которому они принадлежат.
Из этой записи почти бесплатно вытекают два производных сигнала:
- Кардинальность пунктов назначения за запуск. Сколько различных пунктов назначения затронул этот запуск? Агент планирования, который обычно достигает трёх внутренних сервисов и внезапно достигает сорока, не обязательно скомпрометирован, но он больше не ведёт себя как планировщик.
- Новизна относительно базовой линии. Сколько из этих пунктов назначения являются новыми относительно того, что этот агент в этой среде исторически достигал? Новизна — более острый сигнал, потому что она ограничена и сравнима между запусками.
Отклонённые попытки должны сохраняться, а не отбрасываться. Заблокированное соединение — это самая ценная строка в журнале: это агент, явно пытающийся пойти куда-то, куда политика запрещает, и это говорит вам о намерении, даже когда принудительное исполнение сработало. Отбрасывание отказов для чистоты лога удаляет именно те доказательства, которые нужны следователю.
Точки принудительного исполнения
Журнал заслуживает доверия ровно настолько, насколько надёжна точка, в которой он записывается. Если фреймворк агента пишет свой собственный журнал исходящего трафика, журнал — это утверждение агента о своём собственном поведении. Это нормально для отладки и бесполезно для безопасности.
Исходящий трафик должен завершаться на прокси, который агент не может обойти с помощью своих собственных учётных данных. На практике это означает, что у среды выполнения агента нет маршрута наружу, кроме как через прямой прокси или шлюз исходящего трафика, и учётные данные, которые держит агент, действительны только на этом шлюзе. Если агент может дост

При такой топологии следуют три свойства:
- Записи в журнал происходят на прокси, а не в фреймворке агента. Прокси видит соединение, потому что он и есть соединение. В агенте нет пути кода, который может пропустить запись.
- Политика оценивает последовательность и кардинальность, а не только принадлежность к имени хоста. Правило, которое говорит «хост A разрешён», — это проверка принадлежности. Правило, которое говорит «хост A разрешён, но только до хоста B, и никогда более N различных пунктов назначения в пятиминутном окне», — это проверка последовательности. Второе и ловит боковое перемещение.
- DNS находится внутри периметра. Разрешение — это событие исходящего трафика. Агент, который не может открыть TCP-соединение с контролируемым злоумышленником хостом, всё ещё может осуществить эксфильтрацию через DNS-запрос, если разрешение не проксируется и не логируется.
Конкретный механизм, который работает: прокси поддерживает в памяти набор пунктов назначения для каждого запуска, с ключом по идентификатору запуска. При каждом соединении он проверяет принадлежность, затем проверяет кардинальность относительно порога, затем проверяет переход относительно небольшого конечного автомата разрешённых предшествующих пунктов назначения. Если какая-либо проверка не проходит, соединение отклоняется и записывается событие отказа с полным контекстом. Конечный автомат невелик, потому что ему не нужно моделировать всё, что агент может делать; ему нужно моделировать те немногие переходы, которые указывали бы на перемещение.
Операционные компромиссы
Пороги новизны нуждаются в базовых линиях для каждой среды, иначе они будут постоянно вызывать оповещения. Среда staging, где агенты переразвёртываются ежедневно, будет производить новизну почти при каждом запуске, если базовая линия вычисляется глобально. Базовые линии должны быть ограничены по среде, по роли агента и, в идеале, по поколению развёртывания, и они должны пересчитываться по мере изменения системы. Порог, правильный в production, будет шумом в staging, и наоборот. Единого числа нет; есть обязанность по обслуживанию.
Логирование пунктов назначения дешевле логирования полезных нагрузок и переживает шифрование. Запись пункта назначения мала: имя, адрес, порт, временная метка, результат. Она не растёт с размером ответа, не требует перехвата TLS и остаётся значимой, когда полезная нагрузка зашифрована из конца в конец. Это практический аргумент в пользу журнала: он даёт вам сигнал безопасности в той единственной части трафика, которую вы всегда можете наблюдать, без стоимости и юридических рисков инспекции содержимого.
Честное ограничение состоит в том, что журнал говорит вам, куда агент ходил, а не что он там совершил. Вполне авторизованный пункт назначения всё ещё может быть местом, откуда уходят данные. Журнал сужает поиск; он не заменяет инспекцию содержимого и не заменяет человеческое суждение о том, какие новые пункты назначения законны. Что он делает — это делает перемещение видимым, а это та часть, которую инспекция содержимого никогда бы не увидела.
Для команд, строящих агентные системы, практическая последовательность такова: поместите исходящий трафик за прокси, который агент не может обойти, пишите журнал на прокси, сохраняйте отказы и оценивайте последовательность и кардинальность, а не только принадлежность. Инструментация невелика. Пробел в покрытии, который она закрывает, — нет.
