Getting Started with Microsoft Entra ID
Entra ID is the identity plane for everything Azure. Before networking, before policy, before workloads — the tenant configuration shapes what's possible everywhere else. I've spent a disproportionate amount of time in engagements fixing identity decisions made early that nobody thought would matter. Getting the foundation right here pays dividends for years.
Initial tenant setup
Every subscription has a tenant. My first steps:
- Navigate to Microsoft Entra ID in Azure Portal
- Note your Tenant ID and Primary Domain (e.g., contoso.onmicrosoft.com)
- Optionally add a custom domain (requires DNS verification)
Managing Users and Groups
Create Users via Azure Portal
- Go to Microsoft Entra ID > Users
- Click + New user
- Choose Create user or Invite external user
- Fill in user details (name, username, password)
- Assign licenses and roles
Using Azure CLI
# Create a new user
az ad user create \
--display-name "Jane Doe" \
--user-principal-name jane.doe@contoso.com \
--password "TempP@ssw0rd!" \
--force-change-password-next-sign-in true
# Create a security group
az ad group create \
--display-name "DevOps Engineers" \
--mail-nickname devops-engineers \
--description "DevOps team members"
# Add user to group
az ad group member add \
--group "DevOps Engineers" \
--member-id <user-object-id>
Configuring Multi-Factor Authentication (MFA)
Enable MFA for All Users (Recommended)
- Go to Microsoft Entra ID > Security > MFA
- Click Additional cloud-based MFA settings
- Select users or create Conditional Access policy (modern approach)
Modern Approach: Conditional Access Policy
# Requires Azure AD Premium P1 or P2
# Create via Portal:
# Entra ID > Security > Conditional Access > New Policy
Policy Example:
- Users: All users
- Cloud apps: All cloud apps
- Conditions: Any location
- Grant: Require MFA
Implementing Conditional Access
Conditional Access policies provide intelligent access control based on signals:
Common Policies:
-
Require MFA for Administrators
- Users: Directory role = Global Administrator
- Grant: Require MFA
-
Block Access from Untrusted Locations
- Users: All users
- Locations: Not in "Corporate Network" named location
- Apps: Office 365
- Block access
-
Require Compliant Device
- Users: All users
- Apps: All cloud apps
- Grant: Require device to be marked as compliant (Intune)
Terraform Example
# Entra ID is managed via AzureAD provider (not azurerm)
terraform {
required_providers {
azuread = {
source = "hashicorp/azuread"
version = "~> 2.47"
}
}
}
# Create a security group
resource "azuread_group" "developers" {
display_name = "Developers"
description = "Developer team members"
security_enabled = true
members = [
azuread_user.developer1.object_id,
azuread_user.developer2.object_id,
]
}
# Create a user
resource "azuread_user" "developer1" {
user_principal_name = "john.developer@contoso.com"
display_name = "John Developer"
mail_nickname = "john.developer"
password = "SecureP@ssw0rd123!"
force_password_change = true
}
# Register an application
resource "azuread_application" "app" {
display_name = "my-api-app"
web {
redirect_uris = ["https://app.contoso.com/auth/callback"]
implicit_grant {
access_token_issuance_enabled = true
id_token_issuance_enabled = true
}
}
required_resource_access {
resource_app_id = "00000003-0000-0000-c000-000000000000" # Microsoft Graph
resource_access {
id = "e1fe6dd8-ba31-4d61-89e7-88639da4683d" # User.Read
type = "Scope"
}
}
}
# Create service principal for the app
resource "azuread_service_principal" "app" {
application_id = azuread_application.app.application_id
}
CI/CD Integration
Application Registration for Service Principals
# Create app registration
az ad app create \
--display-name "github-actions-sp" \
--sign-in-audience AzureADMyOrg
# Create service principal
az ad sp create \
--id <app-id-from-above>
# Create credentials (client secret)
az ad app credential reset \
--id <app-id> \
--append \
--years 1
GitHub Actions with Entra ID
name: Deploy to Azure
on: [push]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Azure Login with Service Principal
uses: azure/login@v1
with:
creds: ${{ secrets.AZURE_CREDENTIALS }}
# AZURE_CREDENTIALS format:
# {
# "clientId": "<service-principal-app-id>",
# "clientSecret": "<service-principal-password>",
# "subscriptionId": "<subscription-id>",
# "tenantId": "<tenant-id>"
# }
- name: Deploy resources
run: |
az group create --name rg-app --location eastus
Using Managed Identities (Preferred over Service Principals)
For Azure-hosted workloads, use managed identities instead of service principals:
# Azure DevOps with Managed Identity
pool:
vmImage: 'ubuntu-latest'
steps:
- task: AzureCLI@2
inputs:
azureSubscription: 'ManagedIdentityConnection'
scriptType: 'bash'
scriptLocation: 'inlineScript'
inlineScript: |
az account show
addSpnToEnvironment: false
useGlobalConfig: true
Best Practices
Use Conditional Access Policies
❌ I avoid: Per-user MFA settings (legacy method) ✅ I use: Conditional Access policies for centralized, context-aware access control
Benefits:
- Risk-based authentication
- Location-based access
- Device compliance requirements
- Sign-in risk detection
Implement Least Privilege with Azure RBAC
# Assign minimal required role
az role assignment create \
--role "Reader" \
--assignee user@contoso.com \
--scope /subscriptions/{subscription-id}/resourceGroups/rg-prod
Enable Identity Protection
Requires Azure AD Premium P2:
- User risk policy: Detect compromised credentials
- Sign-in risk policy: Detect suspicious sign-in attempts
- MFA registration policy: Ensure all users register for MFA
Use Security Defaults (For Small Organizations)
If I don't have Azure AD Premium, I enable Security Defaults:
- Go to Entra ID > Properties
- Click Manage Security defaults
- Enable
Security Defaults provide:
- MFA for all users
- Block legacy authentication
- Require MFA for administrative tasks
Regularly Review Guest Users
# List all guest users
az ad user list --filter "userType eq 'Guest'" -o table
# Remove inactive guests
az ad user delete --id <user-object-id>
Monitor Sign-in Logs
- Review failed sign-ins weekly
- Investigate unfamiliar locations
- Check for legacy authentication attempts
- Monitor service principal sign-ins
Things to Avoid
❌ I don't use the global administrator role for daily tasks ❌ I never allow password-only authentication for admin accounts ❌ I don't grant "User Access Administrator" role unnecessarily ❌ I don't leave unused app registrations and service principals around ❌ I never use long-lived secrets (>1 year) for service principals ❌ I never skip emergency access accounts ("break glass") ❌ I never allow legacy authentication protocols (SMTP, IMAP, POP3) ❌ I never ignore risky sign-ins and user risk detections
✅ I use Privileged Identity Management (PIM) for admin roles ✅ I implement Conditional Access policies ✅ I use managed identities instead of service principals when possible ✅ I enforce MFA for all users ✅ I regularly audit app permissions and consents ✅ I create 2-3 emergency access accounts ✅ I monitor and investigate Identity Protection alerts ✅ I use Azure AD Premium features for enhanced security
Common Use Cases
- Employee Identity Management: Centralized directory for all employees
- B2B Collaboration: Invite external partners while maintaining security
- Application SSO: Single sign-on to SaaS apps (Salesforce, Google Workspace, etc.)
- API Protection: Secure APIs with OAuth 2.0 and OpenID Connect
- Hybrid Identity: Sync on-premises AD with Azure AD using Azure AD Connect
- Customer Facing Apps: Use Azure AD B2C for customer identities
Licensing Tiers
The licensing question comes up in every engagement. Here's the breakdown I use:
| Feature | Free | P1 | P2 |
|---|---|---|---|
| Users and Groups | ✅ | ✅ | ✅ |
| SSO (Unlimited apps) | ✅ | ✅ | ✅ |
| Self-service password reset | ❌ | ✅ | ✅ |
| Conditional Access | ❌ | ✅ | ✅ |
| Identity Protection | ❌ | ❌ | ✅ |
| Privileged Identity Management | ❌ | ❌ | ✅ |
| Price (per user/month) | Free | ~$6 | ~$9 |
Monitoring & Troubleshooting
Key Logs to Monitor
- Sign-in logs: Track user and service principal authentications
- Audit logs: Changes to users, groups, and applications
- Provisioning logs: User provisioning to SaaS apps
- Risk detections: Identity Protection findings
Export Logs to SIEM
# Create diagnostic settings
az monitor diagnostic-settings create \
--name EntraIDLogs \
--resource /providers/Microsoft.aadiam/diagnosticSettings/EntraIDLogs \
--logs '[
{"category": "SignInLogs", "enabled": true},
{"category": "AuditLogs", "enabled": true},
{"category": "RiskyUsers", "enabled": true}
]' \
--workspace <log-analytics-workspace-id>