Azure para ingenieros de AWS: cómo se traducen (y dónde fallan) tus instintos de AWS
Ya sabes cómo organizar cuentas, otorgar permisos e iniciar el estado en AWS. Así es como se hacen las mismas cosas en Azure: los conceptos que se mapean limpiamente y los cuatro puntos donde tu memoria muscular de AWS te engañará activamente.
Si dominas AWS y ahora te encuentras frente a Azure, la buena noticia es que aproximadamente el 80% de tus instintos se transfieren directamente: hay una jerarquía para organizar las cosas, una forma basada en roles para conceder acceso, una estrategia OIDC para CI sin claves y una rutina de arranque para "iniciar en frío el backend de tu estado". La mala noticia es el otro 20%, y se concentra en algunos puntos de alto tráfico donde hacer lo mismo que en AWS produce una denegación confusa en lugar de un error obvio. Esta publicación es la capa de traducción: los mismos trabajos que haces en AWS, realizados en Azure, con las trampas señaladas.
La versión corta, si solo lees un párrafo: AWS tiene esencialmente un plano de permisos (IAM), Azure tiene tres que no se comunican entre sí; las AWS accounts son Azure subscriptions, pero la facturación reside en un lugar completamente diferente; y Azure añade un contenedor obligatorio (el resource group) para el que AWS no tiene un equivalente real. Todo lo que sigue expande estos puntos.
El mayor cambio: un plano de permisos se convierte en tres
En AWS, IAM es, en efecto, toda la historia. Un servicio rige quiénes son tus identidades, qué pueden hacer con los recursos y —a través de Organizations— cómo se crean y agrupan las cuentas. Los permisos se mezclan de una manera que probablemente ni siquiera notas hasta que desaparecen.
Azure divide deliberadamente ese plano único en tres planos separados, con tres sistemas de roles, tres mecanismos de concesión y casi ninguna mezcla automática. Ser todopoderoso en un plano no te otorga nada en los otros. Esta es la cosa más importante a interiorizar, porque es la fuente de casi todos los momentos de "¿pero soy un administrador, por qué se me deniega esto?".
La regla que te salva: cuando Azure deniega algo que "debería" funcionar, primero pregunta "¿a qué plano me estoy refiriendo?" — y luego verifica los roles de ese plano. La mayoría de las denegaciones misteriosas (no se puede leer una subscription, no se pueden listar management groups, no se puede ver la facturación) no son un permiso que falte dentro de un plano, sino que te estás comunicando con el plano equivocado por completo.
Plano 1 — Roles de directorio de Entra ID (identidad)
Este plano rige los directory objects: usuarios, grupos, service principals / app registrations, Conditional Access, MFA policy, licenses. No rige los recursos que implementas.
- Los roles aquí son cosas como Global Administrator, User Administrator, Application Administrator. Se asignan y evalúan en Entra ID y se exponen a través de la Microsoft Graph API.
- Global Administrator es un dios del directorio, no un dios de los recursos. Esto confunde a todos: un Global Admin puede gestionar felizmente a cada usuario y aplicación en la organización y aun así obtener un fallo de autorización al intentar simplemente leer una subscription. La analogía más cercana en AWS es "la persona que administra IAM Identity Center y el propio directorio", pero es imperfecta, precisamente porque AWS fusiona la administración de directorios con la autorización de recursos y Azure se niega a hacerlo.
Plano 2 — Azure RBAC (recursos)
Este es el plano en el que vivirás, y el que impulsa el proveedor de Terraform azurerm. Gobierna todo lo que implementas:
VMs, virtual networks, storage, AKS, y así sucesivamente.
- Una concesión es una tripleta: (principal, role definition, scope), donde scope es un nodo en la cadena
root → management group → subscription → resource group → resource, y hereda hacia abajo. Los roles integrados son Owner, Contributor, Reader, además de cualquier role definition personalizada que escribas. - Aquí está la trampa para las mentes de AWS: no hay identity-attached policies. En AWS, adjuntas una policy a un usuario o rol y el permiso viaja con la identidad. En Azure, el rol-en-un-scope es el único modelo. La forma mental más cercana de AWS es "una IAM policy adjunta a una Organizations OU"—la concesión reside en el nodo del árbol, no en el principal.
- El único puente sancionado entre los planos 1 y 2 es un movimiento deliberado de "break-glass": un Global Administrator puede alternar
"Access management for Azure resources" (la operación
elevateAccess) para otorgarse a sí mismo User Access Administrator en el root scope. Es ruidoso, reversible y no un valor predeterminado — lo usas una vez durante el arranque para asignarte Owner en el tenant root, que luego hereda en cada subscription.
Plano 3 — facturación / comercio (dinero)
Este plano rige las billing accounts, billing profiles, invoice sections, payment methods — y, críticamente, la creación de subscriptions.
- Tiene su propio conjunto de roles (Billing account owner, Billing profile owner, Azure subscription creator, …), concedidos
dentro de la billing account y almacenados en el billing system. Estos roles no aparecen en
az role assignment listni en las blades de roles de Entra. Son un mundo completamente separado. - Puedes chocar con esta pared desde ambas direcciones. Los derechos máximos de identidad + recursos (Global Admin + User Access
Administrator en el root + Owner en el root management group) todavía te darán una lista vacía de
az billing account listy ninguna capacidad para crear una subscription. Por el contrario, un billing owner puede conceder derechos de facturación con un solo clic. - La parte más engañosa: la facturación se sirve a través de URLs REST que parecen ARM (
Microsoft.Billing/...), por lo que parece el plano de recursos — pero la autorización se evalúa contra los billing roles. Misma puerta, portero diferente.
Una consecuencia concreta en la que AWS nunca te hace pensar: si puedes crear subscriptions programáticamente o no, depende de tu
tipo de billing agreement. Las cuentas legacy pay-as-you-go / web-direct solo pueden crear subscriptions
manualmente en el portal, por la identidad de registro original — esa propiedad ni siquiera es transferible. El modern Customer
Agreement soporta una subscription-creation API (con límites de venta al público en cuentas de autoservicio — un puñado de subscriptions
en total, y un límite de tasa por día), y los enterprise/partner agreements levantan los límites. En AWS, CreateAccount simplemente
funciona desde la management account; en Azure, "¿puedo crear esta cuenta con código?" es una pregunta del plano de facturación que tienes
que responder primero. Es por eso que muchos entornos de Azure tratan las subscriptions como importadas a Terraform, nunca creadas por este.
Cómo se cruzan los planos en la práctica
La mayoría de las tareas tocan exactamente un plano, y algunas abarcan varios — que es la razón principal por la que la división importa:
- Crear un user, group o app registration → Solo Entra.
- Implementar una VM / VNet / storage account → Solo recursos (Azure RBAC).
- Crear una subscription → la facturación la crea, se aloja en un Entra tenant, y se convierte en un Azure RBAC scope. Tres planos para una acción.
- Exportar directory audit logs a un Log Analytics workspace → Entra (origen) más recursos (destino).
- Terraform
azurermvsazuread→ la resource API vs la Graph API — diferentes endpoints, diferentes token audiences.
Ese último punto tiene una implicación operativa real: un solo login genera tokens separados por audience (uno para el resource manager, uno para Graph, uno para Key Vault). Un token emitido para la API de un plano es inútil en la de otro. Si tu herramienta solo coge uno, la mitad de tu Terraform misteriosamente obtendrá un 401.
"Entra ID," "tenant," y "directory" son (en su mayoría) lo mismo
Tres palabras para un objeto visto desde diferentes ángulos, más un cambio de nombre para confundirte:
- Entra ID es el producto — el servicio de identidad. Hasta 2023 era Azure Active Directory (Azure AD / AAD),
y el nombre antiguo está en todas partes: el proveedor de Terraform
azuread, los códigos de errorAADSTS…, "AAD auth" en la documentación. Es lo mismo. - Un tenant es la instancia dedicada de tu organización de Entra ID — el contenedor y el límite de confianza/aislamiento, identificado por un GUID y un primary domain. Los usuarios, grupos, apps, Conditional Access y licenses viven por tenant y no cruzan tenants.
- El directory es el contenido de un tenant — la base de datos de identity objects. Un tenant es igual a un directory, por lo que la gente usa las palabras indistintamente; el botón "Switch directory" del portal en realidad cambia de tenants.
Las reglas que siguen son donde la analogía de AWS se vuelve imprecisa:
- Una subscription se aloja exactamente en un tenant. Ese tenant es su realm de autenticación y suministra sus principales de RBAC. (Las subscriptions pueden transferirse entre tenants; la facturación es una asociación separada.)
- Una organización puede poseer muchos tenants. Un patrón común es un production tenant bloqueado más un sandbox tenant completamente aislado — mundos de identidad separados donde nada de lo que hagas en uno puede afectar al otro. No hay un equivalente en AWS a "un segundo universo de identidades completamente separado bajo la misma empresa".
- Los usuarios tienen un home tenant y pueden ser guests (B2B) en otros lugares. Un guest obtiene un ID de objeto local en el guest tenant mientras mantiene su identidad home. AWS no tiene un concepto de primera clase de "un guest user de otro directorio de la organización".
La analogía más imprecisa de AWS: un tenant es aproximadamente "una AWS Organization fusionada con su directorio de Identity Center" — excepto que las subscriptions se adjuntan a un tenant solo para la identidad, mientras que el pago se adjunta a una billing account, y los cross-org guests son un concepto nativo.
Resource groups: el contenedor que AWS no tiene
Un resource group (RG) es un contenedor obligatorio dentro de una subscription — cada recurso vive exactamente en uno. Esta es la pieza sin equivalente en AWS (los "resource groups" de AWS son solo saved tag queries; ignora la colisión de nombres).
Un RG es cuatro cosas a la vez:
- Un RBAC scope — concede Reader en un RG y habrás limitado el acceso exactamente a esa carga de trabajo.
- Un policy scope — adjunta governance rules a nivel de RG.
- Una lifecycle unit — elimina el RG y todo lo que contiene desaparece con él.
- Un cost boundary — una partida natural para el gasto.
El patrón idiomático es un RG por carga de trabajo (a menudo por región), por lo que un RG se convierte en "la carpeta para esta aplicación en esta región". Un RG tiene una ubicación, pero eso solo dice dónde reside su metadata — sus recursos pueden estar en otras regiones, así que no te obsesiones con la ubicación del RG.
Los Resource IDs llevan contexto, así que los nombres no tienen por qué
Cada recurso de Azure tiene un Resource ID completo como
/subscriptions/<sub>/resourceGroups/<rg>/providers/Microsoft.App/containerApps/<name>. La subscription y el RG viajan
con cada log record, audit event y API call — la misma tarea que el account y region de un ARN hacen en AWS.
La consecuencia de la denominación es lo opuesto a tu hábito en AWS. En AWS, el nombre es a menudo el único contexto que obtienes, así que
lo metes todo en él. En Azure, los nombres deben omitir lo que el scope ya codifica: un cluster llamado aks-quest
dentro de rg-quest dentro de la subscription qa ya está completamente desambiguado, y los mismos nombres de RG/recurso pueden
repetirse de forma segura en las subscriptions de dev/qa/prod. Solo los tipos de recursos globally unique (storage accounts, container registries,
Key Vaults) obligan a volver a incluir org/env/region en el nombre — y estos vienen con estrictos límites de longitud y caracteres, por
lo que verás nombres comprimidos como stcwtfstateplatformcus.
(Por cierto, ese sufijo cus no es inventado — es el geo-code propio de Microsoft para Central US, de la misma tabla oficial que
Azure usa para construir zonas DNS de private-endpoint. eus/eus2 son East US y East US 2. Aprender la tabla de geo-codes
pronto vale la pena).
El mapa rápido de AWS → Azure
Ten esto cerca durante el primer mes:
- Organization → un tenant de Entra más management groups. La identidad (el tenant) y la estructura (management groups) son cosas separadas en Azure, no una.
- Account → subscription. Se aloja en un tenant para la identidad; facturada por una billing account separada.
- SCP (guardrail) → Azure Policy en un management-group scope — con efectos más ricos que solo denegar (audit, deny, modify, deployIfNotExists).
- IAM role/policy → RBAC role assignment — (principal, role, scope). Recuerda: no hay identity-attached policies.
- Root-account superpowers → divididos en tres: Global Admin (identidad) + elevateAccess (recursos) + billing owner (dinero). Ningún principal único comienza con los tres.
- Organizations
CreateAccount→ la subscription aliases API + un billing scope — y solo en los tipos de billing agreement que lo permiten. - IRSA (IAM Roles for Service Accounts) → workload identity federation — la misma idea OIDC.
- Tag-based grouping → el resource group — estructural y obligatorio, no una tag query.
- ARN in logs → el Resource ID (columna
_ResourceId) — el contexto del scope está estructurado, no codificado en el nombre.
Iniciando el estado de Terraform, traducido
Aquí hay un lugar donde tu runbook de AWS casi funciona, y luego falla en el paso cero.
El arranque de AWS que conoces: inicia en frío un state backend en la management account (estado local, luego migra el backend hacia sí mismo), mantén el estado de los backends por OU en ese root backend, y crea member accounts usando sus propios backends. El invariante que lo hace limpio es que siempre puedes iniciar desde la root account, porque siempre existe y puede contener un S3 bucket.
Azure rompe ese invariante en el génesis. El objeto que siempre existe es el tenant, pero un tenant no puede contener recursos. Las storage accounts viven en subscriptions, y las subscriptions nacen del billing plane. Así que la "root account" de Azure es cualquier subscription que coronas como root, y tienes que coronar una conscientemente. En la práctica, la mayoría de los tenants obtienen una subscription al registrarse, por lo que el paralelo se mantiene en su mayoría: AWS te da una management account, Azure te da una primera subscription.
El flujo traducido, cuando las subscriptions ya existen (el caso común):
- Un solo arranque en frío, para siempre: implementa el state backend en tu root subscription designada con local state, luego
init -migrate-statehacia sí mismo. - Backends por subscription, estado almacenado en el root backend: el componente backend de cada subscription adicional ancla su propio estado al root backend, por lo que ponerlos en marcha es un apply normal — no más arranques en frío.
- Todo lo demás en cada subscription utiliza el propio backend de esa subscription.
Desde cero absoluto (creando subscriptions con código), el orden es forzado — root subscription primero, root backend
segundo — porque un backend es una storage account y una storage account necesita una subscription para vivir. Ten en cuenta una
particularidad del "huevo o la gallina": el propio proveedor azurerm exige un subscription context, por lo que con cero subscriptions
creas esa primera subscription con una llamada imperativa (la CLI o el proveedor azapi), y luego la importas a
Terraform.
Y aquí es donde Azure es genuinamente más simple que la memoria muscular de AWS: el backend-en-el-root más los recursos-en-el-miembro no necesitan
ninguna de la maquinaria de confianza hub-and-spoke de AWS — sin role_arn en el backend, sin assume_role del proveedor, sin
two-sided trust policies. El Owner en el tenant root management group hereda en cada subscription, por lo que un token funciona en todo el tenant;
el proveedor "salta" entre subscriptions simplemente configurando subscription_id; y el backend es solo acceso a blobs del data-plane
autorizado por una concesión de Storage Blob Data Contributor. El acceso entre subscriptions es un parámetro, no una negociación de confianza.
(Esto lo ajustarás más tarde con custom roles, PIM e identidades de CI dedicadas, pero incluso entonces son role assignments en scopes,
nunca un handshake de trust-policy). Si quieres profundizar en la codificación de cualquiera de los dos lados,
el examen HashiCorp Terraform Authoring & Operations Pro está diseñado precisamente en torno a estos patrones de estado y proveedor.
Los cuatro puntos donde tus instintos de AWS te engañarán activamente
Si olvidas todo lo demás, recuerda esto:
- "Admin" no es global. Global Administrator es solo identidad; no puede leer una subscription hasta que alguien le concede un resource role. No existe un único principal "root".
- Los permisos se adjuntan a los scopes, no a las identidades. Deja de buscar la policy en el usuario — busca el role assignment en el management group, subscription, resource group o recurso.
- La facturación es un universo separado de los recursos. "Puedo implementar cualquier cosa" no te dice nada sobre "puedo
crear una subscription". Plano diferente, roles diferentes, invisible para
az role assignment list. - El resource group es fundamental. No es una etiqueta — es un RBAC scope, un policy scope y un límite de eliminación. Diseña tu disposición de RG a propósito.
Qué certificaciones cubren cada lado
La gobernanza en la nube — jerarquía, identidad, guardrails y estado — es la columna vertebral de los exámenes de arquitectura y administración en ambas nubes, por lo que estudiarlos es también la forma más rápida de asimilar los conceptos anteriores. Si ya tienes la credencial de AWS, la de Azure en la misma fila es tu siguiente paso natural.
En el lado de AWS (el conocimiento que estás traduciendo desde):
- AWS Certified Cloud Practitioner (CLF-C02) — los fundamentos de accounts, IAM y Organizations.
- AWS Certified Solutions Architect – Associate (SAA-C03) — IAM, multi-account structure y core architecture.
- AWS Certified Solutions Architect – Professional (SAP-C02) — multi-account Organizations, SCPs, y cross-account access a escala.
- AWS Certified Security – Specialty (SCS-C03) — profundidad en IAM, SCPs y key management.
En el lado de Azure (el conocimiento al que estás traduciendo a):
- Microsoft Certified: Azure Fundamentals (AZ-900) — tenants, subscriptions, resource groups y los conceptos básicos de RBAC.
- Microsoft Certified: Azure Administrator Associate (AZ-104) — el plano del día a día: RBAC, resource groups, subscriptions y conceptos básicos de Entra.
- Microsoft Certified: Azure Solutions Architect Expert (AZ-305) — management groups, governance, y diseño de landing-zone.
- Microsoft Certified: Azure Security Engineer Associate (AZ-500) — Entra ID, RBAC, Azure Policy, Conditional Access y Key Vault.
Un camino pragmático si hoy estás certificado en AWS: comienza con AZ-900 para mapear el vocabulario, luego salta a AZ-104 (que reside en el plano de recursos que usarás más), y añade AZ-305 o AZ-500 dependiendo de si tu trabajo se inclina más hacia la arquitectura o la seguridad.
La conclusión
Azure no es más difícil que AWS, está factorizado de manera diferente. AWS colapsa la autoridad de identidad, recursos y facturación en un solo plano y te entrega una management account que puede hacerlo todo. Azure separa esas tres preocupaciones a propósito, lo que se siente como fricción el primer día y como límites claros al tercer mes. Traduce los conceptos una vez — un plano se convierte en tres, las accounts se convierten en subscriptions facturadas en otro lugar, las policies se adjuntan a scopes en lugar de a identidades, y el resource group es una estructura real — y el resto es vocabulario. Practícalo con las certificaciones anteriores, y las partes que parecían denegaciones arbitrarias comenzarán a leerse como un diseño coherente y deliberado.