Azure для инженеров AWS: как применимы ваши инстинкты AWS (и где они терпят неудачу)
Вы уже знаете, как организовывать аккаунты, выдавать разрешения и инициализировать состояние в AWS. Вот как делать то же самое в Azure — концепции, которые легко переносятся, и четыре области, где ваша мышечная память AWS будет активно вводить вас в заблуждение.
Если вы свободно владеете AWS и теперь смотрите на Azure, хорошая новость в том, что примерно 80% ваших инстинктов переносятся напрямую: существует иерархия для организации вещей, ролевой способ предоставления доступа, подход OIDC для бесключевого CI и процедура начальной загрузки бэкенда состояния с нуля. Плохая новость — остальные 20%, и они сосредоточены в нескольких критических точках, где выполнение действий, привычных для AWS, приводит к сбивающему с толку отказу, а не к очевидной ошибке. Этот пост — это уровень перевода: те же задачи, которые вы выполняете в AWS, выполненные в Azure, с указанием ловушек.
Если вы прочитаете только один абзац, то вкратце: AWS по сути имеет одну плоскость разрешений (IAM), Azure имеет три, которые не взаимодействуют друг с другом; аккаунты AWS — это подписки Azure, но биллинг находится совершенно в другом месте; и Azure добавляет обязательный контейнер (группу ресурсов), для которого у AWS нет реального эквивалента. Всё нижеизложенное раскрывает эти положения.
Самое большое изменение: одна плоскость разрешений становится тремя
В AWS IAM фактически является всей историей. Одна служба управляет тем, кто являются вашими сущностями, что они могут делать с ресурсами, и — через Organizations — как создаются и группируются аккаунты. Разрешения сливаются таким образом, что вы, вероятно, даже не замечаете этого, пока это не исчезнет.
Azure намеренно разделяет эту единую плоскость на три отдельные плоскости с тремя системами ролей, тремя механизмами предоставления прав и почти полным отсутствием автоматического сквозного взаимодействия. Быть всемогущим в одной плоскости не даёт вам ничего в других. Это самое важное, что нужно усвоить, потому что это источник почти каждого момента "но я же администратор, почему мне отказано?".
Правило, которое вас спасет: когда Azure отказывает в чём-то, что "должно" работать, сначала спросите "с какой плоскостью я говорю?" — затем проверьте роли этой плоскости. Большинство загадочных отказов (невозможно прочитать подписку, невозможно перечислить группы управления, невозможно увидеть биллинг) — это не отсутствие разрешения внутри плоскости, а то, что вы обращаетесь к совершенно неправильной плоскости.
Плоскость 1 — роли каталога Entra ID (идентификация)
Эта плоскость управляет объектами каталога: пользователями, группами, субъектами-службами / регистрациями приложений, Conditional Access, политикой MFA, лицензиями. Она не управляет развертываемыми вами ресурсами.
- Роли здесь — это такие роли, как Global Administrator, User Administrator, Application Administrator. Они назначаются и оцениваются в Entra ID и отображаются через Microsoft Graph API.
- Global Administrator — это бог каталога, а не бог ресурсов. Это сбивает с толку всех: Global Admin может успешно управлять каждым пользователем и приложением в организации и при этом получить отказ в авторизации при попытке просто прочитать подписку. Ближайшая аналогия в AWS — "человек, который администрирует IAM Identity Center и сам каталог" — но она несовершенна именно потому, что AWS объединяет администрирование каталога с авторизацией ресурсов, а Azure отказывается это делать.
Плоскость 2 — Azure RBAC (ресурсы)
Это плоскость, в которой вы будете работать, и которую использует провайдер azurerm Terraform. Она управляет всем, что вы развертываете: VM, виртуальными сетями, хранилищами, AKS и так далее.
- Грант — это тройка: (субъект, определение роли, область), где область — это узел в цепочке
root → management group → subscription → resource group → resource, и она наследуется вниз. Встроенные роли: Owner, Contributor, Reader, а также любые пользовательские определения ролей, которые вы пишете. - Вот ловушка для умов AWS: нет политик, прикрепленных к сущностям. В AWS вы прикрепляете политику к пользователю или роли, и разрешение следует за сущностью. В Azure модель "роль в области" является единственной. Ближайшая аналогия в AWS — "политика IAM, прикрепленная к Organizations OU" — грант живет на узле дерева, а не на субъекте.
- Единственный санкционированный мост между плоскостями 1 и 2 — это преднамеренный шаг "разбить стекло": Global Administrator может переключить "Access management for Azure resources" (операцию
elevateAccess), чтобы предоставить себе роль User Access Administrator в корневой области. Это громко, обратимо и не является поведением по умолчанию — вы используете это один раз во время начальной загрузки, чтобы назначить себе Owner на корневом уровне клиента, что затем наследуется каждой подпиской.
Плоскость 3 — биллинг / коммерция (деньги)
Эта плоскость управляет биллинговыми аккаунтами, биллинговыми профилями, разделами счетов, методами оплаты — и, что критически важно, созданием подписок.
- Она имеет свой собственный набор ролей (Billing account owner, Billing profile owner, Azure subscription creator, …), предоставленных внутри биллингового аккаунта и хранящихся в биллинговой системе. Эти роли не отображаются в
az role assignment listили в панелях ролей Entra. Это совершенно отдельный мир. - Вы можете столкнуться с этой проблемой с обеих сторон. Максимальные права на идентификацию + ресурсы (Global Admin + User Access Administrator на корневом уровне + Owner в корневой группе управления) по-прежнему дадут вам пустой список из
az billing account listи отсутствие возможности создать подписку. И наоборот, владелец биллинга может предоставить права на биллинг одним щелчком. - Самая коварная часть: биллинг обслуживается через REST URL-адреса, похожие на ARM (
Microsoft.Billing/...), поэтому он выглядит как ресурсная плоскость — но авторизация оценивается по биллинговым ролям. Та же дверь, другой вышибала.
Конкретное следствие, о котором AWS никогда не заставляет вас задумываться: можете ли вы вообще программно создавать подписки, зависит от типа вашего биллингового соглашения. Устаревшие аккаунты с оплатой по мере использования / прямым доступом через веб-интерфейс могут создавать подписки только вручную на портале, используя исходную регистрационную сущность — это владение даже не может быть передано. Современное Клиентское Соглашение (Customer Agreement) поддерживает API для создания подписок (с розничными ограничениями для самообслуживаемых аккаунтов — всего несколько подписок и ограничение скорости в день), а корпоративные/партнерские соглашения снимают эти ограничения. В AWS CreateAccount просто работает из управляющего аккаунта; в Azure вопрос "могу ли я создать этот аккаунт с помощью кода?" является вопросом плоскости биллинга, на который вы должны ответить в первую очередь. Вот почему многие Azure-среды рассматривают подписки как импортированные в Terraform, а не созданные им.
Как плоскости пересекаются на практике
Большинство задач затрагивают ровно одну плоскость, а некоторые охватывают несколько — в этом и заключается вся важность разделения:
- Создание пользователя, группы или регистрации приложения → только Entra.
- Развертывание VM / VNet / учетной записи хранения → только ресурсы (Azure RBAC).
- Создание подписки → её создает биллинг, она привязывается к Entra клиенту и становится областью Azure RBAC. Три плоскости для одного действия.
- Экспорт журналов аудита каталога в Log Analytics workspace → Entra (источник) плюс ресурсы (назначение).
- Terraform
azurermпротивazuread→ API ресурсов против Graph API — разные конечные точки, разные аудитории токенов.
Последний пункт имеет реальное операционное значение: один вход создает отдельные токены для каждой аудитории (один для resource manager, один для Graph, один для Key Vault). Токен, выпущенный для API одной плоскости, бесполезен для API другой. Если ваш инструментарий захватывает только один, половина вашего Terraform будет загадочным образом возвращать 401.
"Entra ID", "клиент" (tenant) и "каталог" (directory) — (в основном) одно и то же
Три слова для одного объекта, рассматриваемого с разных ракурсов, плюс переименование, чтобы вас запутать:
- Entra ID — это продукт — служба идентификации. До 2023 года это был Azure Active Directory (Azure AD / AAD), и старое название встречается повсюду: в провайдере
azureadTerraform, кодах ошибокAADSTS…, "AAD auth" в документации. То же самое. - Клиент (tenant) — это выделенный экземпляр Entra ID вашей организации — контейнер и граница доверия/изоляции, идентифицируемый GUID и основным доменом. Пользователи, группы, приложения, Conditional Access и лицензии — всё это существует в рамках каждого клиента и не пересекает границы клиентов.
- Каталог (directory) — это содержимое клиента — база данных объектов идентификации. Один клиент равен одному каталогу, поэтому люди используют эти слова взаимозаменяемо; кнопка "Switch directory" на портале фактически переключает клиентов.
Следующие правила — это те места, где аналогия с AWS становится неточной:
- Подписка принадлежит ровно одному клиенту. Этот клиент является её областью аутентификации и поставляет её субъекты RBAC. (Подписки могут быть переданы между клиентами; биллинг — это отдельная ассоциация.)
- Одна организация может владеть множеством клиентов. Распространенный шаблон — это заблокированный производственный клиент плюс полностью изолированный песочница-клиент — отдельные миры идентификации, где ничто, что вы делаете в одном, не может повлиять на другое. В AWS нет эквивалента "второй, полностью отдельной вселенной идентификации в рамках одной и той же компании".
- Пользователи имеют один домашний клиент и могут быть гостями (B2B) в других местах. Гость получает локальный ID объекта в гостевом клиенте, сохраняя при этом свою домашнюю идентификацию. У AWS нет первоклассного понятия "гостевого пользователя из каталога другой организации".
Самая неточная аналогия с AWS: клиент — это примерно "AWS Organization, объединенная со своим каталогом Identity Center" — за исключением того, что подписки привязываются к клиенту только для идентификации, в то время как оплата привязывается к биллинговому аккаунту, а кросс-организационные гости являются нативным понятием.
Группы ресурсов: контейнер, которого нет у AWS
Группа ресурсов (RG) — это обязательный контейнер внутри подписки — каждый ресурс находится ровно в одной группе. Это та часть, для которой нет эквивалента в AWS (AWS "resource groups" — это просто сохраненные запросы тегов; игнорируйте совпадение имен).
RG — это четыре вещи одновременно:
- Область RBAC — предоставьте Reader на одной RG, и вы ограничите доступ именно к этой рабочей нагрузке.
- Область политики — примените правила управления на уровне RG.
- Единица жизненного цикла — удалите RG, и всё, что в ней находится, будет удалено вместе с ней.
- Граница стоимости — естественная статья расходов.
Идиоматический паттерн — одна RG на рабочую нагрузку (часто на регион), поэтому RG становится "папкой для этого приложения в этом регионе". RG имеет местоположение, но оно лишь указывает, где хранятся её метаданные — её ресурсы могут находиться в других регионах, поэтому не слишком зацикливайтесь на местоположении RG.
Идентификаторы ресурсов несут контекст, поэтому имена не обязательно должны это делать
Каждый ресурс Azure имеет полный Resource ID, такой как /subscriptions/<sub>/resourceGroups/<rg>/providers/Microsoft.App/containerApps/<name>. Подписка и RG сопровождают каждую запись журнала, событие аудита и вызов API — ту же работу, что и аккаунт и регион ARN в AWS.
Следствием именования является противоположность вашей привычке в AWS. В AWS имя часто является единственным контекстом, который вы получаете, поэтому вы впихиваете в него всё. В Azure имена должны опускать то, что уже закодировано областью: кластер с именем aks-quest внутри rg-quest внутри подписки qa уже полностью однозначен, и одни и те же имена RG/ресурсов могут безопасно повторяться в подписках dev/qa/prod. Только глобально уникальные типы ресурсов (учетные записи хранения, реестры контейнеров, Key Vaults) заставляют возвращать org/env/region в имя — и они имеют строгие ограничения на длину и символы, поэтому вы видите сжатые имена, такие как stcwtfstateplatformcus.
(Кстати, суффикс cus не выдуман — это собственный геокод Microsoft для Центрального США (Central US), из той же официальной таблицы, которую Azure использует для построения DNS-зон приватных конечных точек. eus/eus2 — это Восточные США (East US) и Восточные США 2 (East US 2). Раннее изучение таблицы геокодов окупается.)
Краткое сравнение AWS → Azure
Держите это рядом с собой в первый месяц:
- Organization → клиент Entra плюс группы управления. Идентификация (клиент) и структура (группы управления) в Azure — это отдельные вещи, а не одно целое.
- Аккаунт (Account) → подписка (subscription). Привязывается к клиенту для идентификации; выставляется счет отдельным биллинговым аккаунтом.
- SCP (механизм защиты) → Azure Policy в области группы управления — с более широкими эффектами, чем просто запрет (audit, deny, modify, deployIfNotExists).
- Роль/политика IAM → назначение роли RBAC — (субъект, роль, область). Помните: нет политик, прикрепленных к сущностям.
- Суперспособности корневого аккаунта → разделены на три части: Global Admin (идентификация) + elevateAccess (ресурсы) + владелец биллинга (деньги). Ни один субъект не начинает со всеми тремя.
CreateAccountв Organizations → API псевдонимов подписок + область биллинга — и только для тех типов биллинговых соглашений, которые это позволяют.- IRSA (IAM Roles for Service Accounts) → workload identity federation — та же идея OIDC.
- Группировка на основе тегов → группа ресурсов — структурная и обязательная, а не запрос тегов.
- ARN в логах → Resource ID (столбец
_ResourceId) — контекст области структурирован, а не закодирован в имени.
Начальная загрузка состояния Terraform, в переводе
Вот место, где ваш сценарий AWS почти работает, а затем ломается на нулевом шаге.
Известная вам начальная загрузка AWS: запуск бэкенда состояния с нуля в управляющей учетной записи (локальное состояние, затем миграция бэкенда в себя), хранение состояния бэкендов каждого OU в этом корневом бэкенде и создание дочерних учетных записей с использованием их собственных бэкендов. Инвариант, который делает это чистым, заключается в том, что вы всегда можете выполнить начальную загрузку из корневой учетной записи, потому что она всегда существует и может содержать S3 bucket.
Azure нарушает этот инвариант с самого начала. Объект, который всегда существует, — это клиент (tenant) — но клиент не может содержать ресурсы. Учетные записи хранения живут в подписках, а подписки рождаются из плоскости биллинга. Поэтому "корневой аккаунт" Azure — это любая подписка, которую вы назначаете корневой, и вам нужно выбрать её осознанно. На практике большинство клиентов получают одну подписку при регистрации, так что параллель в основном сохраняется: AWS предоставляет вам управляющую учетную запись, Azure предоставляет вам первую подписку.
Переведенный процесс, когда подписки уже существуют (распространенный случай):
- Один "холодный старт", навсегда: разверните бэкенд состояния в вашей designated корневой подписке с локальным состоянием, затем выполните
init -migrate-stateв себя. - Бэкенды для каждой подписки, состояние хранится в корневом бэкенде: компонент бэкенда каждой дополнительной подписки прикрепляет своё состояние к корневому бэкенду, так что их развертывание — это обычное применение — без "холодных стартов".
- Всё остальное в каждой подписке использует собственный бэкенд этой подписки.
С абсолютно чистого листа (создание подписок с помощью кода) порядок принудительный — сначала корневая подписка, затем корневой бэкенд — потому что бэкенд является учетной записью хранения, а учетной записи хранения нужна подписка, чтобы существовать. Обратите внимание на одну загвоздку "курица или яйцо": сам провайдер azurerm требует контекста подписки, поэтому при нуле подписок вы создаете самую первую подписку с помощью императивного вызова (CLI или провайдера azapi), а затем импортируете её в Terraform.
И вот здесь Azure действительно проще, чем мышечная память AWS: бэкенд в корневом аккаунте плюс ресурсы в дочерних аккаунтах не требуют никакой сложной инфраструктуры доверия AWS типа "звезда" — ни role_arn для бэкенда, ни assume_role для провайдера, ни двухсторонних политик доверия. Роль Owner на корневой группе управления клиента наследуется каждой подпиской, поэтому один токен работает в масштабе всего клиента; провайдер "переключается" между подписками, просто устанавливая subscription_id; а бэкенд — это просто доступ к данным BLOB-объектов, авторизованный грантом Storage Blob Data Contributor. Кросс-подписка — это параметр, а не согласование доверия. (Вы ужесточите это позже с помощью пользовательских ролей, PIM и выделенных сущностей CI — но даже тогда это будут назначения ролей в областях, а не рукопожатие политики доверия.) Если вы хотите углубиться в кодификацию любой из сторон, экзамен HashiCorp Terraform Authoring & Operations Pro построен именно вокруг этих паттернов состояния и провайдеров.
Четыре места, где ваши инстинкты AWS будут активно вводить вас в заблуждение
Если вы забудете всё остальное, помните эти пункты:
- "Админ" не является глобальным. Global Administrator относится только к идентификации; он не может читать подписку, пока кто-то не предоставит ему роль ресурса. Нет единого "корневого" субъекта.
- Разрешения прикрепляются к областям, а не к сущностям. Перестаньте искать политику у пользователя — ищите назначение роли на группе управления, подписке, группе ресурсов или ресурсе.
- Биллинг — это отдельная вселенная от ресурсов. Фраза "Я могу развернуть всё, что угодно" ничего не говорит о том, что "Я могу создать подписку". Другая плоскость, другие роли, невидимые для
az role assignment list. - Группа ресурсов является несущей конструкцией. Это не тег — это область RBAC, область политики и граница удаления. Проектируйте расположение ваших RG целенаправленно.
Какие сертификации охватывают каждую сторону
Управление облаком — иерархия, идентификация, механизмы защиты и состояние — является основой экзаменов по архитектуре и администрированию на обеих облачных платформах, поэтому подготовка к ним также является самым быстрым способом закрепить вышеизложенные концепции. Если у вас уже есть сертификат AWS, то соответствующий сертификат Azure в той же строке — ваш естественный следующий шаг.
Со стороны AWS (знания, с которых вы переходите):
- AWS Certified Cloud Practitioner (CLF-C02) — основы аккаунтов, IAM и Organizations.
- AWS Certified Solutions Architect – Associate (SAA-C03) — IAM, многоаккаунтная структура и основные архитектурные решения.
- AWS Certified Solutions Architect – Professional (SAP-C02) — многоаккаунтные Organizations, SCP и кросс-аккаунтный доступ в масштабе.
- AWS Certified Security – Specialty (SCS-C03) — углубленный IAM, SCP и управление ключами.
Со стороны Azure (знания, на которые вы переходите):
- Microsoft Certified: Azure Fundamentals (AZ-900) — клиенты (tenants), подписки, группы ресурсов и основы RBAC.
- Microsoft Certified: Azure Administrator Associate (AZ-104) — повседневная плоскость: RBAC, группы ресурсов, подписки и основы Entra.
- Microsoft Certified: Azure Solutions Architect Expert (AZ-305) — группы управления, управление и проектирование целевых зон.
- Microsoft Certified: Azure Security Engineer Associate (AZ-500) — Entra ID, RBAC, Azure Policy, Conditional Access и Key Vault.
Прагматичный путь, если вы сегодня сертифицированы по AWS: начните с AZ-900, чтобы разобраться с терминологией, затем переходите к AZ-104 (который охватывает плоскость ресурсов, используемую вами чаще всего), и добавьте AZ-305 или AZ-500 в зависимости от того, ориентирована ли ваша работа на архитектуру или безопасность.
Итог
Azure не сложнее, чем AWS — она спроектирована по-другому. AWS объединяет полномочия по идентификации, ресурсам и биллингу в одну плоскость и предоставляет вам управляющую учетную запись, которая может делать всё. Azure намеренно разделяет эти три области, что поначалу кажется затруднением, а к третьему месяцу — чистыми границами. Переведите концепции один раз — одна плоскость становится тремя, аккаунты становятся подписками, оплачиваемыми в другом месте, политики прикрепляются к областям вместо сущностей, а группа ресурсов — это реальная структура — и остальное становится вопросом терминологии. Закрепите это с помощью вышеуказанных сертификатов, и те части, которые казались произвольными отказами, начнут восприниматься как последовательный, продуманный дизайн.