В сопутствующем посте было введено понятие дрейфа наименьших привилегий как gap между тем, что агент ИИ имеет разрешение делать, и тем, что наблюдается в его действиях. В том посте рассматривалась концепция: почему формируется gap, как наблюдение методом первичного чтения создаёт различие между разрешённым и наблюдаемым, и как политика в виде кода устраняет это различие на этапе доступа. Этот пост погружается на один уровень глубже — в то, как дрейф превращается в структурированное, классифицированное и подлежащее сортировке обнаружение внутри модуля безопасности и что с ним происходит после того, как он возникает.
Краткая версия: дрейф — это не метрика панели мониторинга и не строка лога. Это сохраняемый объект с классификацией, уровнем серьёзности, уровнем доверия и жизненным циклом сортировки. Он подпитывает очередь аномалий, обогащает судебные временные шкалы и честен в том, что может и чего не может доказать.
Три источника сигналов
Каждое ребро в карте доступа фиксирует отношение доступа между источником (агентом, идентичностью, сеансом) и ресурсом. Каждое ребро несет два булевых флага: Permitted и Observed. Интерес представляют ребра, у которых эти флаги не совпадают.
Но флаги не появляются из ниоткуда. Они поступают из различных источников сигналов, каждый из которых имеет свой профиль доверия:
Политика (разрешено). Ребро с signal_source=policy или signal_source=scoped_grant представляет собой заявленное разрешение: что-то, что учетные данные, роль IAM или собственная система определения области платформы указывают, что этот агент имеет право делать. Эти ребра являются permitted=true, observed=false до тех пор, пока телеметрия их не подтвердит. Они являются потолком. Коннекторы идентичности (WIF издатели, списки API-ключей, роли рабочего пространства) подпитывают эту сторону. Аккаунт федерации, которому разрешена область OAuth его правила в рабочем пространстве, является таким ребром.
Телеметрия (наблюдаемая). Кооперативные сигналы из трасс OpenTelemetry, журналов pgAudit, записей CloudTrail, аннотаций MCP, наблюдений по протоколу A2A и вебхуков GitHub/GitLab. Они создают связи там, где observed=true. Их доверие зависит от источника: классификация pgAudit READ является attributed (база данных знает, кто делал запрос и был ли он чтением или записью); MCP readOnlyHint является approximate по спецификации — сама спецификация MCP говорит, что аннотации инструментов недостоверны.
Ядро (истинные данные). Ограничитель eBPF (signal_source=ebpf) работает на уровне системных вызовов; данные ядра поступают от датчика Tetragon, который вы разворачиваете сами, а Olivares AI читает экспорт Tetragon и сам не загружает программы eBPF. Это сигнал, вокруг которого агент не может обойтись. Когда слой eBPF видит connect() или write(), которые не были зафиксированы совместной телеметрией, это не журналирующий gap — это сигнал против обхода. Модуль безопасности объединяет наблюдения со стороны ядра и со стороны совместной работы в коррелированную аномалию, поэтому агент, который отключает свою телеметрию, становится источником выявления, а не слепой зоной.
Карта доступа — это запрос к этим связям, а не отдельная схема. Дрейф наименьших привилегий — это подмножество, где два флага не совпадают.
Как дрейф становится источником выявления
Разногласие между Permitted и Observed является исходным сигналом. Движок классифицирует его в один из двух видов дрейфа, прежде чем он попадет в очередь аномалий:
// DriftKind классифицирует дрейф наименее привилегированного доступа между разрешенным и наблюдаемым.
type DriftKind string
const (
// DriftUnusedGrant — это разрешенный доступ, который никогда не наблюдался (чересчур предоставленный доступ).
DriftUnusedGrant DriftKind = "unused_grant"
// DriftViolation — это наблюдаемый доступ, который не разрешен.
DriftViolation DriftKind = "violation"
)
unused_grant означает, что политика говорит, что агент может что-то делать, чего никогда не наблюдалось. Это неиспользуемая привилегия — риск без какой-либо выгоды. Это сигнал для очистки при периодических проверках доступа: отзывайте то, что не используется.
violation означает, что агент был замечен за выполнением действия, которое не разрешено ни одной политикой или грантом. Это активная находка. Это строка в таблице diff, которая читается как “нераспознанная запись” — важное ребро, которое приоритетизируется в очереди аномалий.
Классификация не является бинарной между “в порядке” и “проблемой.” Структура PrivilegeDrift связывает нарушающее ребро с его типом:
// PrivilegeDrift — это несоответствие минимальным привилегиям: ребро, у которого флаги Permitted
// и Observed не совпадают.
type PrivilegeDrift struct {
Edge AccessEdge
Kind DriftKind
}
Сам край содержит полную информацию о происхождении: источник (какой агент), ресурс, режим доступа read/write, источник сигнала, который его сгенерировал, степень уверенности в атрибуции и окно наблюдения (FirstSeen, LastSeen, OccurrenceCount). Выявление дрейфа никогда не означает «что-то не так где-то». Оно указывает на конкретного агента, конкретный ресурс, конкретный режим доступа, наблюдаемый конкретным сборщиком, с указанием временного диапазона.
Очередь аномалий: не просто «отличается», а классифицировано
Когда модуль безопасности строит представление аномалий (конечная точка GET /v1/m/security/anomalies), он извлекает дрейф из хранилища access-edge и классифицирует каждый violation в приоритетную аномалию. Классификация добавляет контекст, которого сырой край не несет:
Дрейф доступа. Базовая линия: доступ, который был зафиксирован, но не разрешён. Аномалия называется «Неожиданный доступ: зафиксирован, но не разрешён», степень серьёзности — средняя, и помечена как confidence=approximate, потому что дрейф на уровне хранилища является необработанным сигналом — ещё не сверенным с полной графовой моделью «агент-к-идентичности». Сверенная версия находится в собственном эндпойнте карты доступа /drift; очередь аномалий использует необработанный сигнал и помечает его честно.
Предположительно Egress/exfiltration. Когда ресурс на границе дрейфа является сетевым узлом для внешнего, непринадлежащего частной сети назначения (коннектор eBPF генерирует их как tcp://host:port URI), аномалия переклассифицируется в egress_exfil_suspected и повышается до высокого уровня важности. Агент, записывающий данные во внешний узел, к которому ему никогда не предоставлялся доступ, представляет собой иной тип обнаружения, чем агент, читающий таблицу базы данных, к которой у него не было прав доступа.
Повышение чувствительности. Когда ресурс несет метку чувствительности (high или secret), серьезность повышается независимо от того, является ли доступ исходящим. violation в отношении ресурса с высокой чувствительностью требует более быстрого рассмотрения, даже если назначение внутреннее.
Каждая аномалия содержит evidence карту с исходными деталями:
ev := map[string]any{
"origin_kind": edge.OriginKind,
"origin_id": edge.OriginID.String(),
"resource_id": edge.ResourceID.String(),
"mode": string(edge.Mode),
"signal_source": string(edge.SignalSource),
"occurrence_count": edge.OccurrenceCount,
"reconciled": false,
}
reconciled: false преднамеренный. Он сообщает потребителю, что это сигнал на уровне магазина в исходном виде, а не согласованное представление access map от агента к идентичности. Очередь аномалий не ждет согласования, чтобы показать violation — но она не притворяется, что атрибуция окончательна, когда это не так.
Уровни доверия: что можно доказать
Каждое ребро в access map несет уровень доверия. Продукт использует два:
-
Приписанный (
confidence=attributed): доступ надежно связан с источником собственными доказательствами коллектора. Запись pgAudit с указанием роли базы данных агента, событие CloudTrail, связанное с учетными данными IAM агента, либо совместная телеметрия OpenTelemetry с идентификатором агента. Цепочка атрибуции от начала до конца. -
Примерно (
confidence=approximate): атрибуция выводится и может быть неточной. Сигнал поступил с общего сервисного аккаунта, где несколько агентов используют одни и те же учетные данные, из ненадежного источника (экземпляр Redis, который не ведет лог идентичности для каждого подключения) или из аннотации MCP, которая, согласно спецификации, считается ненадежной. Любая связь eBPF тоже approximate, потому что сигналы ядра указывают на процесс, cgroup или контейнер, а не на агента. Связь все еще является сигналом — но оператор знает, что доказательство слабее.
Уровень доверия влияет на оценку приоритета аномалии. Функция приоритета (priorityFor) оценивает каждую аномалию от 0 до 100, и приблизительное отклонение доверия учитывается со скидкой:
if confidence == string(sdkmodel.ConfidenceApproximate) {
// скидка: несогласованное отклонение является шумным
}
Это предотвращает вытеснение шумного сигнала с общей идентичностью сигнала с чёткой attributed violation. Оба появляются в очереди; approximate имеет более низкий рейтинг. Это тот же принцип, который применяется при судебно-экспертном обогащении: когда обнаруживается общая идентичность (SharedIdentity: true, AgentCount > 1), в хронике отмечается, что «принадлежность к агенту может быть неоднозначной», вместо того чтобы притворяться, что принадлежность точная.
Продукт никогда не подделывает уверенность. Край с пометкой только-аннотация MCP не имеет той же значимости, что связь, источник которой несёт идентичность отдельного агента. Выявление дрейфа с учётной записи общего сервиса не имеет той же значимости, что и с идентичности отдельного агента. Оператор видит разницу и распределяет по приоритету соответственно.
Дрейф в судебно-экспертной хронике
Обнаружения дрейфа существуют не только в очереди аномалий. Когда открывается судебное дело и его хронология восстанавливается из связанного по хэшам аудиторского журнала, модуль безопасности обогащает восстановление дрейфом субъекта:
out.Drift = subjectDrift(r.Context(), sc, c.SubjectRef)
Функция subjectDrift выполняет запрос к хранилищу access-edge для дрейфа по типу нарушения, где субъект является источником, и возвращает список записей driftRefDTO — каждая из которых содержит источник, ресурс, режим доступа, источник сигнала, количество случаев и временную метку последнего обнаружения. Эти данные считываются из собственного расчета дрейфа хранилища и не пересчитываются модулем безопасности.
Хронология также содержит информацию о приписывании идентичности субъекта и происхождении данных, поэтому следователь, рассматривающий дело, видит полную картину: под чьим именем действует агент (и разделяется ли эта идентичность), к чему он имел доступ, чего не следовало, и из каких данных он получил ответы. Каждое из этих дополнений терпимо к отсутствующим соседям — если модуль знаний не установлен, происхождение опускается, а не подделывается; если идентичность не имеет разрешенной привязки агента, приписывание указывает «ещё не привязано», а не придумывает его.
Жизненный цикл сортировки
Находка, возникшая из дрейфа, поступает в систему со статусом open. Далее она проходит стандартный жизненный цикл сортировки находок:
- открыто: находка существует, никто ещё не предпринял действий.
- triaged: оператор подтвердил это, назначил на проверку.
- resolved: основная причина была устранена (грант был отозван, политика ужесточена, агент перераспределен).
- dismissed: оператор проверил это и определил, что это не реальная угроза (известное поведение, ложное срабатывание от атрибуции approximate).
Каждое изменение состояния триажа самоаудируется по отношению к реальному субъекту. Сам факт отклонения находки фиксируется в журнале с защитой от подделки, поэтому аудитор может увидеть не только, какие изменения произошли, но и кто их проверял и какое было принято решение. Доказательства находки (ее тип, степень серьезности и хеш деталей) неизменны после создания; изменения триажа касаются только состояния рабочего процесса.
Что это означает на практике
Агенту предоставлен API-ключ, назначенный для рабочего пространства Claude. Коннектор идентичности считывает список участников рабочего пространства и создает политику: этому ключу разрешено вызывать API в этом рабочем пространстве. Агент работает в течение трех недель. Телеметрия показывает, что он вызывает API в этом рабочем пространстве — отклонений нет. Затем изменение в развертывании дает агенту доступ к ключу второго рабочего пространства. Телеметрия фиксирует, что агент обращается к обоим рабочим пространствам. Для второго рабочего пространства политика отсутствует. Создается находка о дрейфе типа violation: произошло, но не разрешено. Она попадает в очередь аномалий как access_drift, средняя степень серьезности, доверие approximate (политика еще не согласована с графом идентичности). Если ресурс во втором рабочем пространстве имеет метку чувствительности high, степень серьезности повышается. Находка остается в очереди оператора до тех пор, пока кто-то ее не классифицирует.
Вот в чем разница между логированием и структурированным дрейфом: находка классифицируется, attributed (с честным уровнем уверенности), приоритизируется и подлежит триажу. Она сохраняется до тех пор, пока кто-то не разрешит её или не отклонит. Она появляется в судебной временной шкале, если агент впоследствии становится объектом рассмотрения инцидента. И каждое действие, предпринятое с ней, фиксируется в цепочке, чью целостность продукт может доказать.
Дрейф не является метрикой для минимизации. Это находка для триажа. Разница gap между тем, что агенту разрешено делать, и тем, что он наблюдается делающим, является наиболее значимым индикатором для обеспечения принципа наименьших привилегий — но только когда gap структурирована, классифицирована и достоверна в том, что она может доказать.
Чтобы увидеть карту доступа и поверхность дрейфа на действующем имении, посетите страницу продукта с картой доступа или обзор продукта.