Entra ID и управление доступом (RBAC)
Кто вы такой, что вам можно и на каком именно ресурсе — три вопроса, на которые в Azure отвечают Entra ID и RBAC.
Microsoft Entra ID (бывший Azure AD) отвечает на вопрос «кто ты» — это каталог удостоверений. Azure RBAC отвечает на вопрос «что тебе можно» — это система ролей поверх ресурсов. Первое без второго бесполезно, второе без первого невозможно.
Зачем это на практике
Пока в подписке один человек — вы, — вопрос доступа кажется надуманным. Но проект растёт: приходит стажёр, подключается CI/CD-пайплайн, аналитику нужны логи, приложению — файлы из Storage. И вот тут начинается: «дай ему Owner, чтоб не мучиться». А через месяц стажёр удаляет ресурсную группу prod, потому что она была рядом с dev и называлась похоже.
Второй сюжет — секреты. Приложению нужно читать из Storage. Самый простой путь: взять ключ доступа и положить в переменную окружения. Ключ утекает в git, в логи, в скриншот в чате. Правильный путь: у приложения есть собственное удостоверение, и Azure выдаёт ему токен без единого пароля. Это называется managed identity, и это одна из лучших вещей в Azure.
Кто может быть субъектом доступа
В терминах Azure субъект называется security principal. Их четыре вида:
| Тип | Что это | Когда использовать |
| User | живой человек с учётной записью в Entra ID | разработчики, админы |
| Group | группа пользователей | всегда, когда людей больше одного |
| Service principal | удостоверение приложения с секретом или сертификатом | внешние системы, CI/CD вне Azure |
| Managed identity | удостоверение ресурса Azure, пароля нет вообще | всё, что работает внутри Azure |
Managed identity бывает двух видов. System-assigned привязана к конкретному ресурсу: создаётся вместе с ним и удаляется вместе с ним. User-assigned — отдельный ресурс, который можно назначить сразу нескольким приложениям и который переживает пересоздание виртуалки. Для продакшена с IaC чаще берут user-assigned: назначения ролей не приходится переделывать после каждого terraform destroy.
# отдельное удостоверение, живущее своей жизнью
az identity create --resource-group rg-shop --name id-shop-api
# или включить system-assigned identity у веб-приложения
PRINCIPAL_ID=$(az webapp identity assign \
--resource-group rg-shop \
--name app-shop-api \
--query principalId -o tsv)
echo "Object ID удостоверения: $PRINCIPAL_ID"
Роли: три классических и много точных
Роль — это набор разрешений вида Microsoft.Storage/storageAccounts/read. Три встроенные роли знает каждый:
| Роль | Что можно | Чего нельзя |
| Reader | смотреть конфигурацию ресурсов | менять что-либо; читать данные внутри Storage/Key Vault |
| Contributor | создавать, менять и удалять ресурсы | назначать роли другим |
| Owner | всё то же плюс назначать роли | — |
Обратите внимание на строчку «Contributor не может назначать роли» — это специально сделано, чтобы Contributor не мог тихо повысить себя до Owner. Если человеку нужно раздавать доступы, но не нужно всевластие, есть роль Role Based Access Control Administrator.
И самое важное для повседневной работы: помимо трёх широких ролей в Azure есть сотни узких встроенных ролей, и почти всегда найдётся та, что подходит идеально. Storage Blob Data Reader — читать блобы, но не трогать сам аккаунт. Key Vault Secrets User — читать секреты, но не создавать хранилища. AcrPull — скачивать образы из реестра контейнеров. Именно из этих ролей и складывается принцип наименьших привилегий: выдаём ровно то, что нужно для работы, и ни разрешением больше.
Область (scope): где именно действует роль
Каждое назначение роли живёт на конкретном уровне иерархии, и роль наследуется вниз:
Management group
└── Subscription
└── Resource group
└── Resource (конкретный Storage, VM, Key Vault)
Contributor на подписке — это Contributor на каждой ресурсной группе и на каждом ресурсе в ней. Отменить наследование нельзя: Azure RBAC аддитивен, разрешения складываются, «вычитающих» правил в обычном режиме нет. Отсюда практическое правило: назначайте роль на минимально возможном уровне. Приложению нужен один Storage — давайте роль на этот Storage, а не на ресурсную группу «чтобы наверняка».
SCOPE=$(az storage account show --name stshopfiles --resource-group rg-shop --query id -o tsv)
az role assignment create \
--assignee-object-id "$PRINCIPAL_ID" \
--assignee-principal-type ServicePrincipal \
--role "Storage Blob Data Reader" \
--scope "$SCOPE"
# проверяем, кому и что выдано на этом ресурсе
az role assignment list --scope "$SCOPE" -o table
Флаг --assignee-principal-type ServicePrincipal лучше указывать явно: без него CLI лезет в Entra ID за уточнением типа и на свежесозданном удостоверении может промахнуться из-за задержки репликации каталога.
Как это работает
Внутри всё построено на OAuth 2.0 и токенах. Когда приложение с managed identity хочет обратиться к Storage, происходит вот что:
- Приложение делает локальный HTTP-запрос к эндпоинту удостоверения — на виртуалке это
169.254.169.254(IMDS), в App Service — адрес из переменнойIDENTITY_ENDPOINT. Никаких паролей: платформа знает, какой ресурс её спрашивает. - В ответ приходит JWT-токен от Entra ID, в котором записан
oid— идентификатор удостоверения — и для какого ресурса токен выписан (audience). - Приложение шлёт этот токен в Storage. Storage проверяет подпись токена и спрашивает у RBAC: «у принципала с таким
oidесть право.../blobs/readна этот контейнер?» - Если есть — данные отдаются. Если нет —
403 Forbidden.
Из этой механики следуют две вещи, о которые все спотыкаются. Во-первых, токен кэшируется (обычно до часа), а изменения назначений ролей распространяются не мгновенно — до нескольких минут, иногда дольше. Выдали роль, а приложение всё ещё получает 403? Подождите и перезапустите его, прежде чем чинить то, что не сломано.
Во-вторых, есть разделение на control plane и data plane. Control plane — это операции с самим ресурсом (создать, удалить, посмотреть настройки), их обслуживает Azure Resource Manager. Data plane — это операции с данными внутри ресурса (прочитать блоб, достать секрет). Роль Reader относится к control plane: она позволит увидеть, что Storage существует, но не даст прочитать ни одного файла. Для данных нужны отдельные роли вроде Storage Blob Data Reader. Это, пожалуй, самый частый источник недоумения у новичков в Azure.
Частые ошибки
- Owner для CI/CD-пайплайна. Скомпрометированный токен сборки с ролью Owner на подписке — это конец. Пайплайну почти всегда достаточно Contributor на одной ресурсной группе.
- «Дам Contributor, пусть настроит доступы». Не сможет: Contributor не назначает роли. Нужен Owner или RBAC Administrator.
- Роли на людей вместо групп. Через год вы не вспомните, кому и что выдавали, а при увольнении будете вычищать назначения по всей подписке. Назначайте роли на группы Entra ID.
- Ключи вместо удостоверений. Ключи доступа Storage и строки подключения — это пароли, которые не истекают и не аудируются. Managed identity бесплатна и решает проблему целиком.
- Путаница ролей Entra и ролей Azure. Global Administrator в Entra ID — это власть над каталогом (пользователи, приложения), а не над подпиской. Пока он не включит переключатель «Access management for Azure resources», ресурсов он не увидит.
- Осиротевшие назначения. Удалили виртуалку с system-assigned identity — в списке ролей останется запись
Identity not found. Чистите их: это мусор, который мешает аудиту.
Про деньги: сам RBAC, назначения ролей, managed identity и базовый Entra ID Free ничего не стоят. Платные вещи — это лицензии Entra ID P1/P2 (порядка 6–9 $ за пользователя в месяц), которые нужны для Conditional Access и PIM (выдача роли на время, с подтверждением). Для учебного проекта они не нужны, для боевой команды — почти обязательны.
Итоги
- Entra ID хранит удостоверения, Azure RBAC раздаёт права на ресурсы — это две разные системы, и роли у них разные.
- Для всего, что работает внутри Azure, используйте managed identity: пароля нет, значит, нечему утекать.
- Owner раздаёт роли, Contributor — нет, Reader смотрит конфигурацию, но не данные.
- Роль наследуется вниз по иерархии и складывается с другими; назначайте её на минимальном уровне.
- Control plane и data plane — разные миры: чтобы читать данные, нужна data-роль вроде
Storage Blob Data Reader. - Изменения ролей и кэш токена дают задержку — не паникуйте от 403 в первые минуты.