Microsoft Entra ID
Users, groups, MFA, Conditional Access, PIM.
A passport office and a border checkpoint do two different jobs. The office checks who you are and hands you a document. The checkpoint never re-reads your birth certificate; it reads the document. Microsoft Entra ID is the passport office for your cloud. Your virtual machines (VMs), storage accounts and databases are the checkpoints, and they never see your password. What they see is a token: a signed, time-limited document issued by Entra ID that says who you are and what you proved to get it (a password, a second factor, a healthy laptop). Entra ID is the identity service behind Azure, Microsoft 365 and thousands of other apps. It was renamed from *Azure Active Directory* in 2023, though the CLI (command-line interface) still spells it az ad. Get identity wrong and nothing else you build matters. Whoever is holding a valid token walks straight past every firewall you put up later.
The tenant: whose directory are you standing in?
A tenant is your organization's own copy of the directory, the way a company keeps its own employee register rather than sharing one with the firm next door. It holds users, groups, devices and registered apps. It is identified by a GUID (globally unique identifier, a long random-looking id) and by a domain name like contoso.onmicrosoft.com. Here is the part that trips people up. Subscriptions hold resources; tenants hold identities. Every Azure subscription trusts exactly one tenant to say who you are. One tenant can be trusted by many subscriptions, and one human can exist in several tenants at once, a member in yours and a guest in a partner's. So before you touch anything, check which tenant your CLI session is actually pointed at. Creating a user in the wrong directory is an ordinary Tuesday mistake, and an awkward one to undo.
# Which tenant, subscription, and identity is this CLI session using?az account show --query "{tenant: tenantId, subscription: name, user: user.name}" -o jsonc{"tenant": "e8b7c2a4-3f5d-4b6e-9a1c-2d8f7e6a5b4c","subscription": "prod-sub-01","user": "[email protected]"}# List every tenant your account can reach (member or guest).# First run auto-installs the experimental "account" extension (CLI 2.38+).az account tenant list --query "[].{TenantId:tenantId, DisplayName:displayName}" -o tableTenantId DisplayName------------------------------------ -------------e8b7c2a4-3f5d-4b6e-9a1c-2d8f7e6a5b4c Contoso9a1f42c0-5c1d-4b8e-9d3a-77e0c1b2aa10 Fabrikam Ltd
Users and groups: stop managing people one at a time
Users differ along two axes, and both show up on the exam. First, where the account came from. Cloud-only users are created directly in Entra. Synced users are copied up from an on-premises Windows Server Active Directory by Entra Connect, or by the lighter agent-based *Cloud Sync*. A synced user has to be edited on-premises, where the original record lives, because the cloud copy is read-only for the attributes that flow up from Active Directory. That one catches people out constantly. Second, what kind of relationship the person has with you. A Member works for your organization. A Guest is an outside collaborator invited by email under B2B (business-to-business) sharing, and they still type their password into *their own* company's tenant, never yours. Then comes the rule that separates tidy tenants from painful ones: never grant access or licenses to a person. Grant them to a group and let membership do the work, so access appears and disappears as people join and leave teams. Two details before you run the commands below. The domain after the @ in a user principal name has to be verified in your tenant already. And a password typed on the command line is written to your shell history in clear text, so in automation you read it out of Key Vault instead.
# Create a cloud-only user (forced to change password at first sign-in)az ad user create \--display-name "Avery Chen" \--user-principal-name [email protected] \--password 'P@ssw0rd-rotate-me!' \--force-change-password-next-sign-in true# returns the new Graph user object (trimmed):{"displayName": "Avery Chen","id": "b1c94f2e-8a30-4d2b-9c1e-6f5a3d8e0b77","userPrincipalName": "[email protected]"}# Create a security group and add the user by object idaz ad group create --display-name "eng-oncall" --mail-nickname eng-oncallaz ad group member add --group eng-oncall \--member-id b1c94f2e-8a30-4d2b-9c1e-6f5a3d8e0b77# Verify membership — silence is not confirmation, check explicitlyaz ad group member check --group eng-oncall \--member-id b1c94f2e-8a30-4d2b-9c1e-6f5a3d8e0b77{"value": true}
The group you made is assigned, which means you add and remove people by hand, the way you would keep a paper club roster. A dynamic group works from a rule instead. You write a condition over user attributes (department, jobTitle, device properties) and Entra adds or removes people on its own as those attributes change. Dynamic groups need an Entra ID P1 license. There is no az ad group flag for the rule, because membership rules live in Microsoft Graph, the API (application programming interface, the door programs knock on instead of clicking around the portal) that every Entra tool talks to underneath. Your way in is az rest, which borrows the token from your existing CLI login and calls Graph directly:
az rest --method POST --url https://graph.microsoft.com/v1.0/groups --body '{"displayName": "eng-all-dynamic","mailEnabled": false,"mailNickname": "eng-all-dynamic","securityEnabled": true,"groupTypes": ["DynamicMembership"],"membershipRule": "(user.department -eq \"Engineering\")","membershipRuleProcessingState": "On"}'# Returns the new group object. Membership then populates asynchronously as# the rule engine evaluates user attributes — minutes in a small tenant,# potentially longer in a large one.
What actually happens when you sign in
Run az login, or open the portal, and the app hands you off to login.microsoftonline.com. There Entra ID runs an OpenID Connect flow, the standard choreography for "prove it, then take this document." It checks your credential (password, passkey or certificate), evaluates any Conditional Access policies, then mints a JWT access token (JSON Web Token, a small blob of JSON that has been cryptographically signed). The token states who you are, which tenant you belong to and what you may ask for, and it is good for roughly 60 to 90 minutes. Now the part that surprises people. When you call a resource, say Azure Resource Manager (ARM, the front door to every Azure resource) or a storage account, that service checks the *signature* on your token locally using Entra's published signing keys, which it fetched and cached earlier. It does not call Entra on every request. That statelessness is why disabling a compromised account does not throw the attacker out on the spot. Their existing token keeps working until it expires, unless the service supports *Continuous Access Evaluation*, which lets Entra push a revocation within minutes. So do both. Disable the account (az ad user update --id <upn> --account-enabled false), then revoke that user's sign-in sessions through Graph.
Conditional Access: the rules at the front door
A good doorman does not ask everyone the same question. The regular arriving at 9am walks in; a stranger at 3am gets asked for ID. Conditional Access (CA for short) is that doorman written down as if-then rules, evaluated inside the sign-in flow above. *If* this user, from this country, on this device, into this app, at this risk level, *then* let them in, or ask for MFA (multi-factor authentication, a second proof such as a phone approval or a tap on a security key), or demand a managed and compliant device, or refuse outright. It is what turns MFA from a blanket prompt into a question that fires when the situation warrants it. Two facts every admin is expected to know, and the AZ-104 exam (the Azure Administrator Associate certification) asks about both. CA needs an Entra ID P1 license. The free alternative is security defaults, one switch that forces MFA registration across the whole tenant, and the two are mutually exclusive, so you turn one off to use the other. Start every new policy in report-only mode, which records in the sign-in logs what the policy *would* have done and enforces nothing. CA has no dedicated az commands, since it lives in the portal and in Graph, but you can read your policies from the CLI with az rest if you hold an Entra role such as Security Reader:
az rest --method GET \--url "https://graph.microsoft.com/v1.0/identity/conditionalAccess/policies" \--query "value[].{name:displayName, state:state}" -o tableName State----------------------------- ---------------------------------Require MFA for admins enabledBlock legacy authentication enabledRequire compliant device enabledForReportingButNotEnforced
.onmicrosoft.com domain, signing in with a phishing-resistant credential such as a FIDO2 security key or a certificate rather than a password, excluded from every blocking CA policy, and wired to an alert on any sign-in). Run the policy in report-only mode for a week. Then read the sign-in logs and count who would have been blocked.PIM, SSPR, and the licensing lines people trip over
Standing privilege is the biggest identity risk in most tenants: a dozen people holding Global Administrator every hour of every day, including while they read email. Privileged Identity Management (PIM) fixes that by keeping the key in a signout book instead of giving everyone a copy. An admin is marked *eligible* rather than *active*, and has to activate the role when the work demands it, passing MFA, sometimes an approval from a colleague, and always a clock that expires after a few hours. Every activation leaves an audit trail. Self-service password reset (SSPR) covers the ordinary end of the same problem by letting people reset their own password at 2am without waiting on a helpdesk ticket. Exam questions love the license boundaries, so learn them cold. Free gives you users, groups and security defaults. P1 adds Conditional Access, dynamic groups, and SSPR with writeback to on-premises Active Directory. P2 adds PIM, Identity Protection (risk-based policies) and access reviews. If a question mentions just-in-time activation or risk-based sign-in, it is pointing at P2.
One distinction sets up everything that follows. The roles named in this lesson, Global Administrator and User Administrator, are Entra ID roles, and they govern the *directory*: users, groups, policies, app registrations. They grant zero access to a virtual machine, a storage account or a network. Resources are governed by a separate system called Azure RBAC (role-based access control), with its own role names (Owner, Contributor, Reader) handed out at subscription, resource group or individual resource scope. A Global Administrator cannot list your VMs until somebody grants them an RBAC role, or until they flip the emergency *elevate access* switch. Two keyrings, two sets of locks. How the RBAC keyring works is the next lesson.
The portal makes identity look like a settings page: a few blades, some toggles, a list of names. It is really the control plane for everything else you do. Every API call, every role assignment, every Conditional Access decision starts with a token minted by Entra ID. Wrong tenant, wrong audience, wrong user, and no amount of hardening further down the stack rescues you. That is why az account show is the first command of a shift. It answers one question before you create a user or hand out a role: which directory am I about to change?
MFA and Conditional Access ride the same path, and people mix them up constantly. MFA is the challenge itself, the phone approval or the key tap. Conditional Access is the policy engine that decides *when* a challenge, or a compliant device, or an approved location, is required at all. PIM then shortens how long a powerful Entra or Azure role stays switched on. Put together, they turn "Global Admin, forever" into "eligible admin, two hours, after approval, with a log entry." Verify, challenge, elevate briefly, expire. The AZ-104 exam expects you to operate that pattern, not recite it.
Try this
Open a throwaway Entra tenant or a sandbox subscription, and prove which directory you are talking to before you create a single thing. Then list a few users and check whether an account you control is still enabled.
# Who am I, and which tenant?az account show --query "{user:user.name, tenant:tenantId, sub:name}" -o json# List a few users (needs User.Read.All or Directory permissions)az ad user list --query "[0:3].{upn:userPrincipalName, enabled:accountEnabled}" -o table
$ az account show --query "{user:user.name, tenant:tenantId, sub:name}" -o json{"user": "[email protected]","tenant": "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee","sub": "Contoso-Lab"}# Sample output$ az ad user list --query "[0:3].{upn:userPrincipalName, enabled:accountEnabled}" -o tableUPN Enabled-------------------------------- -------[email protected] True[email protected] True
Takeaway
Hold on to one line. Entra ID is the directory plane, where users, groups, MFA, Conditional Access and PIM live. Azure RBAC is a separate plane that decides what those identities are allowed to do to resources. Same tenant, two permission systems.
Next up: cut standing admin down with PIM, then write one Conditional Access policy that requires MFA for every interactive sign-in to the Azure portal.