Корпоративный инцидент: через Azure OpenAI кто-то сгенерировал текст, которому не место за периметром компании. Ключ доступа отзывают за минуту, это стандартная реакция. Но у службы безопасности остаётся вопрос, на который отозванный ключ ответить не может: какая рабочая идентичность сделала вызов и с какой ролью.
Ключ прошёл проверку не потому, что был безопасным выбором, а потому, что был валидным. Валидность и расследуемость — разные свойства. Ключ подтверждает право на вызов, но ничего не говорит об авторстве. Для разбора инцидента вся работа сводится именно к этому разрыву.
Дальше — инженерный разбор одного конкретного решения: когда для доступа к Azure AI стоит выбрать Microsoft Entra ID вместо ключа ради самой возможности расследовать вызов, и какое доказательство нужно увидеть, прежде чем называть такой доступ «расследуемым». Сценарий с двумя service principals ниже не прогнан до готового лога — это воспроизводимый план проверки, а не отчёт о завершённом эксперименте.
Платите в рублях за AI-модели без наценки на токены через provod.ai
Что именно нужно доказать, а что не входит в разбор
Разработчик, который вбивает в поиск api azure ai, обычно получает рабочий запрос за пять минут: копирует ключ из портала, вставляет в заголовок, получает ответ модели. Удобство здесь и есть ловушка. Ключ — общий секрет ресурса, а не удостоверение личности того, кто им воспользовался. Если ключ знают пять сервисов и три инженера, факт успешного вызова говорит только одно: у отправителя был этот ключ.
Границу задачи стоит провести сразу, чтобы не размывать вывод. Речь не об общем споре «managed identity лучше пароля», а о конкретной аудируемости вызовов Azure AI: можно ли по журналам доказать, какая рабочая идентичность и с какой ролью выполнила именно этот data-plane запрос к модели. Нагрузка, которая живёт вне Azure, в этот разбор не входит: у чужого контура свой журнал и свой способ отвечать на тот же вопрос.
Фальсифицируемый тезис, который держит весь текст: если журнал не позволяет связать конкретный Azure AI-вызов с рабочей идентичностью и её ролью, Entra ID в этом сценарии не доказывает преимущества для расследования. Не «обычно лучше», а именно «не доказывает», пока карта не собрана.
Как включается Entra ID-доступ к ресурсу
По документации Microsoft Learn (доступ 2026-07-18) ресурсы Azure OpenAI и Foundry поддерживают аутентификацию через Microsoft Entra ID как альтернативу ключам API, но при двух обязательных условиях. Первое: у ресурса должен быть настроен пользовательский поддомен (custom subdomain), без него Entra ID-аутентификация не включается вовсе. Второе: вызывающая сторона (пользователь, service principal или managed identity) обязана держать роль вроде Cognitive Services OpenAI User или Cognitive Services OpenAI Contributor, иначе inference-вызов просто не пройдёт.
Клиентский поток документация показывает через DefaultAzureCredential: библиотека получает bearer-токен от Entra ID, и с этим токеном идёт вызов к модели. Сценарий аудита с двумя service principals повторяет ровно этот поток, только каждая идентичность получает собственный токен.
from azure.identity import DefaultAzureCredential, get\_bearer\_token\_provider from openai import AzureOpenAI
token\_provider = get\_bearer\_token\_provider( DefaultAzureCredential(), "https://cognitiveservices.azure.com/.default", )
client = AzureOpenAI( azure\_endpoint="https://<твой-поддомен>.openai.azure.com", azure\_ad\_token\_provider=token\_provider, api\_version="2024-10-21", )
Назначение роли делается через Access control (IAM) → Add role assignment. Роль можно назначить пользователю, группе, service principal или managed identity на уровне ресурса, группы ресурсов или подписки; по документации назначение становится активным в течение нескольких минут. Для карты расследования это значит, что у каждой из двух рабочих идентичностей появляется отдельный, прослеживаемый след намерения ещё на уровне control-plane.

Роль решает, будет ли вызов вообще
Наличия идентичности недостаточно: гейтит именно роль, и это легко пропустить. Роли Cognitive Services OpenAI User и Cognitive Services OpenAI Contributor документированы как способные «делать inference API-вызовы с Microsoft Entra ID». А более широкая управляющая роль, Cognitive Services Contributor, прямо задокументирована как неспособная на это: это control-plane роль, она управляет ресурсом, но не может провести данные через него.
Отсюда практический вывод. Если дать service principal якобы «сильную» роль Cognitive Services Contributor, он сможет управлять ресурсом целиком, но data-plane вызов к модели через Entra ID у него не пройдёт. Роль здесь не ярлык доступа, а условие самой возможности сгенерировать вызов, и для карты расследования это подарок: разные роли дают разный, различимый смысл события.
Именно на этом строится гипотеза сценария: два service principals с разными ролями должны оставить в журнале различимые следы. Это гипотеза, а не установленный факт, и проверить её должен сам тест. Есть и оговорка по датам: определения ролей RBAC для Cognitive Services и OpenAI менялись не раз (в исходной таблице Microsoft прямо стоят пометки вроде «Added Fall 2023»), таблица актуальна на дату документа (ms.date 2026-01-31, обновление 2026-06-05), но это движущаяся цель, а не постоянный контракт. Имена ролей стоит сверять с тем поколением портала, которое реально показывает твой tenant: Azure OpenAI сейчас существует в двух поколениях, «Foundry classic» и «Foundry», с пересекающимися, но не идентичными страницами документации.

Что реально попадает в журнал ресурса
Здесь карта становится хрупкой. Логирование на уровне ресурса Azure AI и Cognitive Services не включается само по себе: нужно вручную добавить diagnostic setting (Monitoring → Diagnostic settings) и выбрать категории логов, среди них Audit, RequestResponse и AllMetrics, а затем направить их в Log Analytics или Azure Storage. Заложи и задержку: до двух часов, прежде чем записанные данные станут доступны для запроса.
Категории ресурсных логов для Microsoft.CognitiveServices/accounts документированы раздельно: «Audit Logs», «Azure OpenAI Request Usage», «Request and Response Logs», «Managed Network Events», «Trace Logs». При маршрутизации в Log Analytics все они попадают в таблицу AzureDiagnostics, а отдельная таблица AzureActivity держит control-plane операции. «Журнал» здесь не одна сущность, а несколько потоков, которые ещё придётся сшивать.
Ключевой вопрос: несёт ли ресурсный лог идентичность вызывающего? Общая верхнеуровневая схема ресурсных логов Azure Monitor определяет опциональное поле identity: «JSON-блоб, описывающий идентичность пользователя или приложения, выполнившего операцию», обычно с claims авторизации или JWT-токеном от Microsoft Entra ID, плюс опциональные callerIpAddress и correlationId для связывания событий. Звучит как то самое доказательство. Но это платформенная схема общего назначения, и ни одна из специфичных для Azure OpenAI или Cognitive Services страниц не подтверждает, что это поле реально заполнено пригодным Entra ID object ID на каждой записи Request/Response или Audit для Microsoft.CognitiveServices/accounts.
Поэтому утверждение «ресурсный лог надёжно несёт идентичность вызывающего для каждого inference-вызова» остаётся непроверенной гипотезой: подтвердить или опровергнуть её должен сценарий с двумя service principals. Если поле окажется пустым или без object ID, карта рвётся именно здесь, и вывод придётся зафиксировать таким: сам по себе data-plane лог этого ресурса идентичность не доказывает.

Второй источник: журналы входов Entra ID
У задачи есть второй источник, и он устроен ровно под вопрос расследования. Журналы входов Microsoft Entra ID делятся на четыре типа: interactive user, non-interactive user, service principal и managed identity. Документация прямо позиционирует их как ответ на вопрос «к каким ресурсам Azure обращались managed identities и service principals», моделируя каждое событие как Who (идентичность), How (приложение или клиент) и What (ресурс, к которому обращались).
Записи входов service principal фиксируют имя и ID service principal, статус входа, IP-адрес и имя или ID ресурса, к которому шло обращение. Есть и подводный камень: Microsoft агрегирует повторяющиеся входы в одну строку, если совпадают service principal, статус, IP-адрес и ресурс, так что не каждый отдельный вызов получает отдельную строку. Для аудита это значит: «одна строка» не равно «один вызов», и объём активности по числу строк читать наивно нельзя.
Зато у sign-in логов есть свойство, которое и делает их пригодными как доказательство: записи системно-генерируемые, их нельзя изменить или удалить. Самоотчётный, редактируемый лог для расследования почти бесполезен, а неизменяемый уже похож на улику. Граница тоже есть: sign-in логи фиксируют аутентификацию в Entra ID, Microsoft Graph и Azure Resource Manager, а это отдельный источник от ресурсных, data-plane логов Cognitive Services. Ни один из источников не описывает единую готовую таблицу, которая уже сшила бы оба семейства логов, значит defensible-карта требует ручной корреляции по времени и полям связи. Именно эта корреляция, а не сам факт использования Entra ID, доказывает связку «роль, идентичность, вызов, событие».
Ключ или Entra ID: как выбрать под аудит
Сведём решение в таблицу. Каждая строка отвечает на один и тот же вопрос: что именно ты сможешь доказать после инцидента, а не только пройдёт ли запрос технически.
| Что нужно от доступа | Статический ключ | Entra ID + роль |
|---|---|---|
| Технически выполнить вызов | Да, сразу | Да, нужен custom subdomain и роль |
| Различить, какая рабочая идентичность звонила | Нет, ключ общий | Через service principal / managed identity |
| Связать вызов с ролью | Нет | Роль гейтит сам inference (User/Contributor против Cognitive Services Contributor) |
| Неизменяемая улика входа | Нет | Sign-in логи системно-генерируемы, не редактируются |
| Идентичность прямо в data-plane логе | Нет | Гипотеза: поле identity, проверяется сценарием |
| Стоимость настройки | Минимальная | Роли, diagnostic settings, сшивка журналов |
Управляемая идентичность действительно сложнее ключа: это честный размен, а не бесплатное улучшение. Ты платишь настройкой ролей, diagnostic settings и связыванием их с журналом. Взамен получаешь возможность привязать действие к проверяемой роли. Нормативный выбор здесь прямой: для расследуемого корпоративного доступа выбирай авторизацию, которую можно связать с ролью и событием. Но он держится ровно до тех пор, пока связка «идентичность, роль, вызов, аудитное событие» продемонстрирована, а не предположена. Если сценарий не создаёт проверяемого события или роль не удаётся привязать к вызову, Entra ID в этом конкретном случае не даёт того преимущества, ради которого его выбирали.
Похожий вопрос подотчётности встаёт и вне Azure, просто на другом уровне, и здесь важно не путать инструменты. provod.ai не заменяет Entra ID и его пообъектные роли: это отдельный API-контур доступа к моделям, а не механизм аудита Azure-ресурсов. Но у него своя единица учёта. Клиент, который поддерживает протокол OpenAI, подключается к provod.ai сменой base URL и ключа, а сам ключ живёт внутри командного рабочего пространства, где у участников есть роли и контроль доступа, а у организации — общий баланс расходов.
Уровни легко перепутать, и в разборе инцидента это дорого стоит. Такой учёт отвечает на вопрос «кто из команды и через какой ключ тратил», но не на вопрос «какая рабочая идентичность выполнила именно этот data-plane вызов к твоему Azure-ресурсу». Второй вопрос закрывает только связка ролей и журналов внутри собственного tenant.
Чего эта карта не решает
Карта «идентичность, роль, вызов, аудитное событие» — инструмент разбора, а не политика доступа. Она не заменяет политику доступа организации и не обещает полноту аудита; эти ограничения стоит проговорить вслух, чтобы не купить себе ложную уверенность.
Главное ограничение: карта не гарантирует, что нужное поле действительно заполнено. Пока сценарий не прогнан на конкретном ресурсе и deployment, состав полей и полнота события остаются неизвестными, это заложено в условиях задачи с самого начала. Ограничение потоньше касается самого сильного источника: даже неизменяемый sign-in лог отвечает на вопрос «кто аутентифицировался к ресурсу», а вопрос «кто сгенерировал конкретный prompt» держится на ручной корреляции двух журналов. Добавь к этому, что имена ролей и категорий логов — движущаяся цель между поколениями портала, и карта, собранная на «classic», может не совпасть по URL и ярлыкам с «Foundry».
Подход проваливается целиком, если первичная документация нужного журнала недоступна, если сценарий не создаёт проверяемого события или если роль не удаётся связать с вызовом. Тогда вывод звучит ограниченно: в этом сценарии расследуемость не доказана. Для инженерного разбора это нормальный результат, а не поражение.

Пошагово: как собрать проверяемый сценарий
Порядок стоит прогнать заранее, до того как инцидент потребует ответа прямо сейчас. Это план к исполнению, а не отчёт о уже выполненном тесте.
- Включи на ресурсе custom subdomain и Entra ID-аутентификацию.
- Заведи два service principals: одному дай роль Cognitive Services OpenAI User, другому — Cognitive Services Contributor. Ожидай, что первый сможет сделать inference-вызов, а второй нет; это и есть проверка гипотезы о различимых следах.
- Добавь diagnostic setting с категориями Audit, RequestResponse, AllMetrics в Log Analytics и заложи до двух часов на появление данных.
- Сделай по одному вызову от каждой идентичности через
DefaultAzureCredential. - Открой
AzureDiagnosticsи sign-in логи Entra ID (тип service principal). Проверь на реальных записях: заполнено ли полеidentity, есть лиcorrelationId, совпадают ли времена, виден ли отказ у роли Cognitive Services Contributor.
Результат сценария условен по построению: карта покажет, какие идентичности и роли действительно можно доказуемо связать с вызовом, а при отсутствии нужного события вывод будет ограничен ровно этим пробелом. Отвечать службе безопасности придётся в этой же форме: перечислением того, что журнал доказывает, и того, что он оставляет открытым.
Частые вопросы
Достаточно ли просто включить Entra ID вместо ключа? Нет. Без роли, способной делать inference (User или Contributor), вызов не пройдёт вовсе, а без diagnostic setting событие вообще не запишется. Аутентификация — это только первая треть карты.
Ресурсный лог уже содержит, кто звонил? Это не подтверждено для Microsoft.CognitiveServices/accounts. Поле identity определено на уровне платформенной схемы как опциональное; заполнено ли оно object ID на каждой inference-записи, проверяется сценарием, а не принимается на веру.
Можно ли обойтись одним журналом? По имеющимся источникам нет: единой готовой таблицы, сшивающей sign-in и ресурсные логи, документация не описывает. Корреляцию по времени и correlationId придётся делать вручную.
Почему в sign-in логе меньше строк, чем вызовов? Entra ID агрегирует повторяющиеся входы в одну строку при совпадении service principal, статуса, IP-адреса и ресурса. Число строк не равно числу вызовов.
Решение об авторизации Azure AI принимается до инцидента, а не во время него. Тот же принцип работает и для контура вне Azure: подотчётность нужно проектировать заранее, а не достраивать в момент, когда вопрос уже задан.

provod.ai — российский LLM API-агрегатор
Один OpenAI-совместимый endpoint вместо набора интеграций: подключайте модели к продукту, агентам, IDE и SDK через общий API. Во многих совместимых инструментах достаточно заменить base_url и API-ключ.
В одном каталоге — актуальные модели для текста и медиа: GPT от OpenAI, Claude от Anthropic, Gemini от Google, Grok от xAI, DeepSeek, Qwen, GLM, Kimi и MiniMax; для изображений — Nano Banana 2 Pro и GPT Image; для видео — последние версии Seedance, Kling, Veo и Google Omni. Также доступны модели для reasoning, поиска, документов, эмбеддингов, музыки и аудио.
Цены 1:1 с официальными ценами провайдеров — без собственной наценки provod.ai. Оплата в рублях, единый баланс и документы для юридических лиц.
Если статья была полезной — попробуйте provod.ai: форма регистрации · цены на модели · защита данных по 152-ФЗ · API и интеграции
Источники
- Azure OpenAI / Entra ID, managed identity и поток
DefaultAzureCredential: Microsoft Learn, https://learn.microsoft.com/en-us/azure/ai-foundry/openai/how-to/managed-identity?view=foundry-classic (доступ 2026-07-18). - RBAC, роли и их data-plane/control-plane сплит: Microsoft Learn, https://learn.microsoft.com/en-us/azure/foundry-classic/openai/how-to/role-based-access-control (доступ 2026-07-18).
- Диагностическое логирование и категории: Microsoft Learn, https://learn.microsoft.com/en-us/azure/ai-services/diagnostic-logging (доступ 2026-07-18).
- Категории ресурсных логов Azure OpenAI и таблицы Log Analytics: Microsoft Learn, https://learn.microsoft.com/en-us/azure/foundry/openai/monitor-openai-reference (доступ 2026-07-18).
- Общая схема ресурсных логов Azure Monitor (поле
identity): Microsoft Learn, https://learn.microsoft.com/en-us/azure/azure-monitor/platform/resource-logs-schema (доступ 2026-07-18). - Типы sign-in логов Entra ID и их неизменяемость: Microsoft Learn, https://learn.microsoft.com/en-us/entra/identity/monitoring-health/concept-sign-ins (доступ 2026-07-18).
- Поля входов service principal и агрегация строк: Microsoft Learn, https://learn.microsoft.com/en-us/entra/identity/monitoring-health/concept-service-principal-sign-ins (доступ 2026-07-18).
