AZ-104: Azure Administrator — Exam Overview
What Is This Exam?
AZ-104 certifies you as an Azure Administrator — the person who deploys, manages, and monitors Azure resources day-to-day. This is a practitioner exam, not an architect exam. You are tested on how to operate Azure, not what pattern to choose.
Think like an IT admin with Azure hands, not like a cloud architect.
Exam At a Glance
| Attribute | Detail |
|---|---|
| Exam code | AZ-104 |
| Duration | 150 minutes |
| Questions | 40–60 (varies per attempt) |
| Passing score | 700 / 1000 |
| Price | $165 USD |
| Renewal | Every year (free online assessment — no re-exam) |
| Prerequisites | None (AZ-900 recommended but not required) |
Question Types
Understanding the format is half the battle.
1. Multiple Choice (most common)
Pick one of four. Read all options before answering — Microsoft loves to make two answers "almost right." The wrong options are usually right in a different context.
2. Multiple Select
"Select all that apply" or "select two." No penalty for wrong answers — never leave blanks.
3. Drag and Drop / Order
Match concepts to categories or arrange steps. Common for replication type comparisons, backup tiers, or deployment sequences.
4. Hot Area
Click the correct region of a screenshot or diagram. Usually tests which portal blade or button to use.
5. Case Studies
A scenario followed by several related questions. Read the scenario once carefully before answering. All questions in a case study share the same context — earlier answers don't lock in your choices.
6. Live Lab Tasks (hardest section)
You get a real Azure environment and must complete hands-on tasks:
- Example: "Create a storage account named
stprod001in West US with Zone-Redundant Storage." - Tasks are pass/fail per task. Partial work doesn't score.
- This section is at the end of the exam and cannot be skipped once started.
- Allocate at least 30 minutes for labs.
⚠️ You cannot return to earlier multiple-choice sections once you start the lab section.
Domain Weights
| # | Domain | Exam Weight |
|---|---|---|
| 1 | Manage Azure identities and governance | 15–20% |
| 2 | Implement and manage storage | 15–20% |
| 3 | Deploy and manage Azure compute resources | 20–25% |
| 4 | Implement and manage virtual networking | 15–20% |
| 5 | Monitor and maintain Azure resources | 10–15% |
Compute is the highest-weight domain. Networking is the trickiest. Identities has the most common conceptual trap.
Scoring
Microsoft uses scaled scoring — harder questions are worth more points. You need 700/1000, which is roughly 70%, but because of scaling, targeting 80%+ correct is the realistic safety margin.
There is no penalty for wrong answers — always guess if unsure.
How to Approach the Exam
- Read the question stem twice. Identify: what resource, what action, what constraint.
- Eliminate two obviously wrong answers first. You'll usually be choosing between two plausible options — this doubles your focus.
- Watch for scope qualifiers. Many wrong answers are correct in a different scope (e.g., works for VMs but not App Service, works at subscription but not resource group).
- "Cheapest / least administrative effort" is usually correct. Microsoft favors the simplest solution that meets the stated requirement.
- Flag and move. Don't spend more than 2 minutes on any single question during pass 1.
- Save 30 minutes for live labs. They require real portal navigation and CLI commands.
Domain Quick Map
Domain 1: Identities & Governance
└─ Entra ID, users/groups, RBAC, Management Groups, Policy, Locks
Domain 2: Storage
└─ Storage accounts, replication (LRS/GRS/ZRS), tiers, SAS, lifecycle, File Sync
Domain 3: Compute
└─ VMs, VMSS, availability sets/zones, App Service, ACI, ARM/Bicep, Bastion
Domain 4: Networking
└─ VNet/NSG/ASG, VNet Peering, VPN/ER, DNS, Load Balancer, App Gateway, Firewall, UDR
Domain 5: Monitor & Maintain
└─ Azure Monitor, Log Analytics, Alerts, Backup, Site Recovery, Update Manager
3-Month Study Plan
| Week | Focus |
|---|---|
| 1 | Domain 1: Identities & Governance — read concepts + complete Lab 01 |
| 2 | Domain 2: Storage — read concepts + complete Lab 02 |
| 3 | Domain 3: Compute — read concepts + complete Lab 03 |
| 4 | Domain 4: Networking — read concepts + complete Lab 04 |
| 5 | Domain 5: Monitor & Maintain + complete Lab 05 |
| 6 | Full mock exam — score domains and identify gaps |
| 7 | Weak domain deep dive + second mock exam |
| 8 | Portal speed drills — simulate live lab tasks with a timer |
Rule of thumb: If you can't complete a lab task in the portal in under 5 minutes, you need more repetition. Live lab tasks in the real exam have no guide — just memory.
Key Resources
| Resource | Purpose |
|---|---|
| Microsoft Learn AZ-104 path | Official free modules — covers every domain |
| John Savill AZ-104 Study Cram (YouTube) | Best single 4-hour video review — watch before your mock exam |
| MeasureUp AZ-104 | Closest to real exam questions; buy 1–2 weeks before exam |
| Azure free account | $200 credit + free services for 12 months — required for all labs |
| Whizlabs AZ-104 | Good backup practice test source |
| AZ-104 Exam Skills Outline (PDF) | Official list of every testable skill — use as checklist |
Start your Azure free account today. Reading alone will not pass the live lab section. You need hands-on repetition.
Before Your Exam Day
- Ensure your government ID name exactly matches your Pearson VUE account name
- Test your environment (webcam, mic, desk space) if taking online — do the system check 24 hours before
- Arrive (or open the online check-in) 15 minutes early
- No notes, no second monitors, no phones
- Water is allowed in a clear container at most testing centers
Domain 1: Manage Azure Identities and Governance
Exam weight: 15–20%
This domain tests whether you can manage who has access to what in Azure and enforce organization-wide rules on resources. It contains the single most common exam trap: Entra ID roles vs Azure RBAC roles — they are completely separate systems.
1.1 Microsoft Entra ID (formerly Azure AD)
Entra ID is Azure's cloud-based identity directory. Every Azure subscription is associated with exactly one Entra ID tenant. The tenant is the trust boundary for all identities.
Tenant vs Subscription
| Concept | What it is |
|---|---|
| Tenant | The Entra ID directory (identity store) |
| Subscription | A billing and resource container |
| Relationship | One tenant → many subscriptions possible |
A subscription belongs to exactly one tenant. A tenant can own many subscriptions.
User Types
| Type | Created how | Default access |
|---|---|---|
| Member | Created inside this tenant | Can read most directory objects |
| Guest | Invited from another org (B2B) | Restricted — sees only what they're explicitly given |
Group Types
| Type | Purpose |
|---|---|
| Security group | Used for Azure RBAC and app access |
| Microsoft 365 group | Collaboration (Teams, SharePoint, Exchange mailbox) |
Group Membership
| Membership type | How members are added | License required |
|---|---|---|
| Assigned | Manually by admin | None |
| Dynamic User | Auto, based on user attribute rules (department eq "Finance") | Entra ID P1 |
| Dynamic Device | Auto, based on device attributes | Entra ID P1 |
Exam trap: Dynamic groups require Entra ID P1 license. Any question that says "automatically add users based on attributes with no manual effort" implies dynamic groups and P1 licensing.
Managed Identities
A managed identity is a service principal automatically managed by Azure — no credentials to store or rotate.
| Type | Lifecycle | Shared across resources? |
|---|---|---|
| System-assigned | Tied to the resource — deleted when the resource is deleted | No — one resource only |
| User-assigned | Standalone resource — persists independently | Yes — attach to multiple resources |
Exam trap: If a question asks "the VM is recreated and must retain its existing role assignments," the answer is user-assigned managed identity because system-assigned gets a new Object ID on recreation.
1.2 Azure RBAC
Azure Role-Based Access Control governs what Azure actions a principal can perform on Azure resources. It is completely separate from Entra ID roles.
RBAC Answers Three Questions
- Who? — Security principal (user, group, service principal, managed identity)
- What? — Role definition (a named set of permitted
Actions) - Where? — Scope
Scope Hierarchy
Root Management Group (tenant root)
└─ Management Group
└─ Subscription
└─ Resource Group
└─ Resource
- RBAC assignments are inherited downward.
- Assignments are additive — a user gets the union of all role assignments at all scopes.
- There is no implicit deny — only explicit role assignments or deny assignments block access.
Key Built-in Roles
| Role | Can do | Cannot do |
|---|---|---|
| Owner | Everything, including manage access | — |
| Contributor | Create and manage all resources | Assign roles, manage locks |
| Reader | View all resources | Any write or delete action |
| User Access Administrator | Manage RBAC assignments at this scope | Create or manage resources |
Exam trap: A Contributor cannot assign roles. If a question asks who can grant the Contributor role to another user, the answer is Owner or User Access Administrator — not Contributor.
Exam trap: A Contributor cannot create or delete resource locks. Managing locks requires
Microsoft.Authorization/locks/*, which Contributor explicitly excludes.
Deny Assignments
- Cannot be created manually by users.
- Created by Azure Blueprints and Managed Applications.
- Take precedence over role assignments — they block even Owners.
Custom Roles
- Define
Actions,NotActions,DataActions,NotDataActions. - Scope is set per-subscription or per-management-group.
- The
NotActionsfield removes actions from whatActionsallows — it is not a deny, just a subtraction.
1.3 Entra Roles vs Azure RBAC Roles — The #1 Exam Trap
These are two completely separate systems that just happen to live in the same Azure portal.
| Attribute | Entra ID Roles | Azure RBAC Roles |
|---|---|---|
| Controls | The Entra directory (users, groups, apps, devices) | Azure resources (VMs, storage, networks, etc.) |
| Examples | Global Administrator, User Administrator, Billing Reader | Owner, Contributor, Reader, Storage Blob Data Contributor |
| Assigned in | Entra ID admin center | Azure portal / ARM / CLI / RBAC blade |
| Scope | Tenant-wide (or specific Entra objects) | Management group → Subscription → RG → Resource |
Global Admin can elevate to Azure: In Entra settings, a Global Administrator can grant themselves the User Access Administrator Azure RBAC role on all subscriptions (one-time toggle). This is not automatic — it must be explicitly done.
Exam scenario: "A user is the Global Administrator in Entra ID. They try to create a VM. It fails." → Reason: Global Admin has no Azure RBAC permissions unless explicitly granted. They need at minimum Contributor on the target scope.
1.4 Management Groups
Hierarchy
Root Management Group (auto-created, represents the tenant)
├─ Management Group: Corp
│ ├─ Subscription: Prod
│ └─ Subscription: Dev
└─ Management Group: External
└─ Subscription: Partner
- Up to 6 levels of nesting (not counting root).
- A subscription can be in only one management group at a time.
- RBAC and Policy assignments inherit to all child subscriptions and resources.
- Moving a subscription between management groups transfers the inherited assignments.
Moving Resources Between Subscriptions
- Most resources can be moved with
az resource move. - Restrictions: target subscription must be in the same Entra tenant.
- Resource IDs change after a move — update automation scripts and monitoring rules.
- Some resources cannot be moved: Azure AD Domain Services, ExpressRoute circuits with VNet links.
1.5 Azure Policy
Azure Policy enforces organizational standards on resources independently of RBAC. A user with Contributor can be blocked by a Policy.
Effect Types — Must Know All
| Effect | What it does | When it runs |
|---|---|---|
| Deny | Blocks the non-compliant operation | At creation or modification |
| Audit | Logs non-compliance — allows it | At creation or modification |
| Append | Adds properties/tags to the request | At creation or modification |
| Modify | Adds, replaces, or removes tags/properties | At creation or modification |
| DeployIfNotExists | Deploys a related resource if it doesn't exist | After the resource is created |
| AuditIfNotExists | Audits if a related resource is missing | After the resource is created |
| Disabled | Policy is off — no evaluation | — |
Exam trap — DeployIfNotExists: It runs after resource creation for new resources, but for existing non-compliant resources you must manually trigger a Remediation Task. It does not retroactively fix existing resources automatically.
Exam trap — Append vs Modify: Use Append to add new properties (like tags). Use Modify to change or remove existing properties. In practice, Modify is replacing Append for tag scenarios.
Initiatives (Policy Sets)
An initiative (policy set) bundles multiple policies into one assignable unit. Example: the "Enable Microsoft Defender for Cloud" initiative bundles 20+ individual policies.
Policy vs RBAC — How They Interact
- Request arrives → RBAC is evaluated first.
- If RBAC allows it → Policy is evaluated.
- If Policy says Deny → request is rejected, even for Owners.
1.6 Resource Locks
Locks prevent accidental deletion or modification. Applied at resource, resource group, or subscription — inherited downward.
| Lock type | Blocks | Allows |
|---|---|---|
| CanNotDelete | Delete | Read + all modifications |
| ReadOnly | Delete + all modifications | Read only |
ReadOnly Gotchas
ReadOnly sounds simple but it blocks any ARM write action on the management plane, including:
- Listing storage account access keys (
listKeysis classified as a write) - Starting or stopping a VM (start/deallocate are write operations)
- Scaling an App Service plan
Exam trap: A ReadOnly lock on a storage account prevents listing access keys, even for an Owner. This is one of the most common exam questions.
Who Can Manage Locks
Requires Microsoft.Authorization/locks/* — included in Owner and User Access Administrator only. Contributor cannot create or delete locks.
Section Takeaways
| Topic | Key Point |
|---|---|
| Tenant vs Subscription | One tenant owns many subscriptions; one subscription belongs to one tenant |
| Dynamic groups | Require Entra ID P1 license |
| RBAC scope | Additive, inherited downward, no implicit deny |
| Contributor limits | Cannot assign roles, cannot manage locks |
| Entra roles vs Azure RBAC | Completely separate — biggest exam trap in Domain 1 |
| Global Admin | Has no Azure resource access unless explicitly granted via RBAC |
| Policy vs RBAC | Policy can block even an Owner; evaluated after RBAC |
| DeployIfNotExists | Needs manual Remediation Task for existing resources |
| ReadOnly lock | Blocks listKeys on storage, blocks VM start/stop |
| User-assigned MI | Persists across resource recreation; system-assigned does not |
Confusing Points — Clarified
Q: Does assigning Owner at a Management Group make the user Owner of all subscriptions under it? A: Yes. RBAC inherits downward through the full hierarchy — management group → subscription → resource group → resource.
Q: Can Azure Policy block a Global Administrator from creating a resource? A: From an Azure resource perspective, yes — if the Policy has a Deny effect. The Global Admin has no special bypass for Azure Policy. (They could remove the policy assignment if they also have the right Azure RBAC, but that's a different action.)
Q: What's the difference between NotActions and a Deny assignment?
A: NotActions in a custom role is subtraction from Actions — it removes permissions from the allow list. A Deny assignment is an explicit block that overrides all role assignments, even Owner.
Q: Can a Contributor delete a resource that has a CanNotDelete lock? A: No. The lock blocks deletion regardless of RBAC role. The Contributor also cannot remove the lock (requires Owner/UAA). Both vectors are blocked.
Lab 01: RBAC, Policies, and Resource Locks
Estimated time: 45–60 minutes Difficulty: ⭐⭐☆☆☆ Environment: Azure free account — portal + Azure CLI
Prerequisites
- Azure free account with an active subscription
- Azure CLI ≥ 2.50 (
az --version) - Logged in:
az login
Set your default subscription:
az account set --subscription "<your-subscription-id>"
az account show --query "{name:name, id:id}" -o table
Lab Objectives
By the end you will have:
- Created two Entra ID users and a security group
- Assigned scoped RBAC roles (Contributor to group, Reader to user)
- Verified access boundaries — what Contributor can and cannot do
- Created a Deny policy blocking a specific resource type
- Applied a CanNotDelete lock and confirmed Contributor cannot remove it
Step 1: Create the Lab Resource Group
az group create \
--name rg-az104-lab01 \
--location eastus
echo "Resource group created."
All resources in this lab are scoped to this RG. This contains blast radius.
Step 2: Create Two Entra ID Users
Requires User Administrator or Global Administrator in Entra ID. On a personal free Azure account you typically have Global Admin.
# Discover your tenant's default domain
DOMAIN=$(az rest \
--method GET \
--url "https://graph.microsoft.com/v1.0/organization" \
--query "value[0].verifiedDomains[?isDefault].name | [0]" \
--output tsv)
echo "Tenant domain: $DOMAIN"
# Create Alice (will get Contributor via group)
az ad user create \
--display-name "Alice Storage" \
--user-principal-name "alice@$DOMAIN" \
--password "P@ssw0rd!Azure104" \
--force-change-password-next-sign-in false
# Create Bob (will get Reader directly)
az ad user create \
--display-name "Bob ReadOnly" \
--user-principal-name "bob@$DOMAIN" \
--password "P@ssw0rd!Azure104" \
--force-change-password-next-sign-in false
# Capture Object IDs — required for all subsequent operations
ALICE_ID=$(az ad user show --id "alice@$DOMAIN" --query id --output tsv)
BOB_ID=$(az ad user show --id "bob@$DOMAIN" --query id --output tsv)
echo "Alice OID: $ALICE_ID"
echo "Bob OID: $BOB_ID"
⚠️ Tricky spot:
--assigneeinaz role assignment createaccepts UPN, Object ID, or display name — but in federated tenants (AAD Connect, ADFS), UPN-based lookup can fail silently or resolve to the wrong user. Always use Object ID in production and exam automation scripts.
Step 3: Create a Security Group and Add Alice
# Create the group
GROUP_ID=$(az ad group create \
--display-name "Storage-Admins" \
--mail-nickname "Storage-Admins" \
--query id --output tsv)
echo "Group OID: $GROUP_ID"
# Add Alice to the group
az ad group member add \
--group "Storage-Admins" \
--member-id $ALICE_ID
# Verify
az ad group member list --group "Storage-Admins" --query "[].displayName" -o tsv
Step 4: Assign RBAC Roles
RG_ID=$(az group show --name rg-az104-lab01 --query id --output tsv)
# Contributor to the Storage-Admins group (scoped to RG)
az role assignment create \
--assignee-object-id $GROUP_ID \
--assignee-principal-type Group \
--role "Contributor" \
--scope $RG_ID
# Reader to Bob directly (scoped to RG)
az role assignment create \
--assignee-object-id $BOB_ID \
--assignee-principal-type User \
--role "Reader" \
--scope $RG_ID
# Verify both assignments
az role assignment list \
--resource-group rg-az104-lab01 \
--query "[].{Principal:principalName, Role:roleDefinitionName, Scope:scope}" \
-o table
Why use
--assignee-principal-type? It skips an extra Graph API lookup and prevents errors in tenants with strict Graph API permissions. Always use it when you have the Object ID.
Step 5: Test What Contributor Can and Cannot Do
Create a storage account as Alice's action (you're still the admin here, but simulate the outcome):
# Create a storage account — a Contributor CAN do this
SA_NAME="staz104$(openssl rand -hex 4)"
az storage account create \
--name $SA_NAME \
--resource-group rg-az104-lab01 \
--location eastus \
--sku Standard_LRS
echo "Storage account: $SA_NAME"
Now test what Contributor cannot do — try to create a role assignment:
# This SHOULD fail if run as Alice (Contributor)
# Running as admin here to demonstrate the concept
az role assignment create \
--assignee-object-id $BOB_ID \
--assignee-principal-type User \
--role "Reader" \
--scope $RG_ID
# → AuthorizationFailed: Contributor does not have Microsoft.Authorization/roleAssignments/write
Takeaway: Contributor sees and manages resources, but role management is reserved for Owner and User Access Administrator. The exam will test this boundary multiple times.
Step 6: Create a Custom Deny Policy
Create a policy that denies creation of public IP addresses in this resource group — simulating a "no public internet exposure" governance rule.
SUB_ID=$(az account show --query id --output tsv)
# Define the policy
az policy definition create \
--name "deny-public-ip" \
--display-name "Deny Public IP Creation" \
--description "Blocks creation of Public IP resources" \
--rules '{
"if": {
"field": "type",
"equals": "Microsoft.Network/publicIPAddresses"
},
"then": {
"effect": "deny"
}
}' \
--mode All \
--subscription $SUB_ID
# Assign the policy to the resource group
az policy assignment create \
--name "deny-public-ip-rg" \
--display-name "Deny Public IP in Lab RG" \
--policy "deny-public-ip" \
--scope $RG_ID
Test the policy — this should fail:
# Wait 2-3 minutes for policy to propagate, then test
az network public-ip create \
--name pip-blocked \
--resource-group rg-az104-lab01 \
--location eastus \
--sku Standard
# Expected error: RequestDisallowedByPolicy
# Error code: PolicyViolation
⚠️ Tricky spot: Policy assignments have a 5–10 minute propagation delay in real Azure tenants. If the creation succeeds immediately, wait a few minutes and retry. In the exam's live lab environment the propagation is faster.
⚠️ Tricky spot: If you have an existing public IP resource already in the RG (created before the policy), the policy does NOT delete it —
Denyeffect only blocks future creation/modification. To report existing non-compliance, useAuditeffect or check compliance under the policy assignment.
Step 7: Apply a Resource Lock
# Apply CanNotDelete lock on the resource group
az lock create \
--name "protect-lab01" \
--resource-group rg-az104-lab01 \
--lock-type CanNotDelete \
--notes "Exam lab protection lock"
# Verify
az lock list --resource-group rg-az104-lab01 -o table
Test the lock — try to delete the RG (will fail):
az group delete --name rg-az104-lab01 --yes
# Expected: ScopeLocked — cannot delete a resource group with a CanNotDelete lock
Now test that Contributor CANNOT remove the lock:
Even though Alice has Contributor on the RG, she cannot delete the lock:
# As Alice (Contributor), this would fail:
az lock delete \
--name "protect-lab01" \
--resource-group rg-az104-lab01
# Expected: AuthorizationFailed — Contributor lacks Microsoft.Authorization/locks/delete
Only Owner or User Access Admin can delete the lock:
# As admin (Owner), this succeeds:
az lock delete \
--name "protect-lab01" \
--resource-group rg-az104-lab01
Step 8: Clean Up
Cleanup order matters — remove assignments and policies before deleting the RG.
# 1. Remove policy assignment (policy blocks cleanup otherwise)
az policy assignment delete \
--name "deny-public-ip-rg" \
--scope $RG_ID
# 2. Delete the resource group (no lock now, so this works)
az group delete --name rg-az104-lab01 --yes --no-wait
# 3. Remove Entra ID users and group
az ad user delete --id $ALICE_ID
az ad user delete --id $BOB_ID
az ad group delete --group "Storage-Admins"
# 4. Remove the policy definition (optional — clean namespace)
az policy definition delete --name "deny-public-ip" --subscription $SUB_ID
Lab Tricky Spots Summary
| Trap | What goes wrong | Correct approach |
|---|---|---|
Using --assignee with UPN in federated tenants | Resolves to wrong user or fails silently | Always use --assignee-object-id + --assignee-principal-type |
| Testing policy immediately after assignment | Policy not yet propagated — creation succeeds | Wait 5–10 minutes before testing |
| Contributor trying to remove a lock | 403 AuthorizationFailed | Only Owner or User Access Admin can manage locks |
| Deleting RG before removing policy assignment | Policy conflicts with cleanup | Always remove policy assignments before deleting the scoped resource |
| Dynamic group empty after creation | Entra ID P1 not assigned to users | Assign P1 license to users for dynamic membership to evaluate |
Lab Takeaways
- Assign RBAC to groups, not individuals — scales better; adding a new admin just means adding to the group.
- Object IDs over UPNs in CLI scripts — federated tenants make UPN lookups unreliable.
- Policy lag is real in production — always account for 5–10 minutes propagation.
- Lock management ≠ resource management — Contributor can create resources but cannot protect or unprotect them with locks.
- Cleanup has an order — remove policy assignments first, locks second, then resources, then the RG.
Domain 1: Practice Q&A — Identities & Governance
Answer each question before expanding the solution. Aim for under 2 minutes per question.
Q1
Your organization requires that all Azure resources have a CostCenter tag. You want to automatically add the tag (value: Unassigned) to any resource deployed without it — without blocking the deployment.
Which Azure Policy effect should you use?
- A. Deny
- B. Audit
- C. Append
- D. DeployIfNotExists
Answer + Explanation
Correct: C — Append
Why C: Append adds properties (including tags) to a resource request during creation or update, without blocking it. The deployment goes through; the tag is automatically included.
Why not A: Deny would block any deployment missing the tag — that contradicts the "without blocking" requirement.
Why not B: Audit only logs non-compliance. It doesn't add the tag.
Why not D: DeployIfNotExists deploys a separate related resource if it doesn't exist — it's for things like deploying a diagnostic settings resource alongside a VM, not for adding properties to the resource being created.
Exam tip: "Add a tag automatically without blocking" = Append. If the requirement is to block deployments without the tag, use Deny (possibly combined with Modify for remediation of existing resources).
Q2
A user has the Contributor role assigned at the subscription level. They attempt to delete a resource lock on a resource group. The operation fails with a 403 error. What is the reason?
- A. The lock was created by a Policy, which cannot be deleted via RBAC
- B. The Contributor role does not include
Microsoft.Authorization/locks/* - C. Subscription-level RBAC does not inherit to resource groups
- D. The user must have the Global Administrator role in Entra ID to delete locks
Answer + Explanation
Correct: B — Contributor lacks Microsoft.Authorization/locks/*
Why B: The Contributor role explicitly excludes any Microsoft.Authorization/* actions. Deleting a lock requires Microsoft.Authorization/locks/delete, which belongs to Owner and User Access Administrator only.
Why not A: Locks are not created or managed by Policy — they are a separate feature (Microsoft.Authorization/locks). Policy manages Microsoft.Authorization/policyAssignments.
Why not C: Subscription-level RBAC absolutely inherits downward to RGs and resources. That's how RBAC scope hierarchy works.
Why not D: Global Administrator is an Entra ID role, not an Azure RBAC role. It doesn't grant any Azure resource permissions unless explicitly elevated.
Q3
A VM is regularly deleted and recreated as part of a blue-green deployment pipeline. The VM needs to access Azure Key Vault using a managed identity, and its Key Vault access policy must remain intact across recreations.
Which identity type should you configure?
- A. System-assigned managed identity
- B. User-assigned managed identity
- C. Service principal with a client certificate
- D. Service principal with a client secret
Answer + Explanation
Correct: B — User-assigned managed identity
Why B: A user-assigned managed identity has its own lifecycle, independent of any VM. When the VM is deleted and recreated, you attach the same user-assigned identity — its Object ID never changes, so Key Vault access policies referencing it remain valid.
Why not A: System-assigned identity is tied to the VM's lifecycle. When the VM is deleted, the identity is deleted, and a new Object ID is created on recreation. All Key Vault access policies referencing the old Object ID must be manually re-added.
Why not C/D: Service principals require credential management (certificate expiry, secret rotation). Managed identities are Azure-managed — no credentials to handle.
Exam tip: "Survives resource recreation" or "shared across multiple VMs/services" = user-assigned managed identity.
Q4
Your company has three Azure subscriptions: Dev, Staging, and Production. You must enforce a policy preventing creation of any VM with more than 4 vCPUs in all three subscriptions with minimum administrative effort.
What is the most efficient approach?
- A. Create a policy assignment in each of the three subscriptions
- B. Move all subscriptions into a management group and assign the policy once to the management group
- C. Create a custom RBAC role that prevents VM creation and assign it to all subscriptions
- D. Use Azure Blueprints to create one blueprint per subscription
Answer + Explanation
Correct: B — Management group with a single policy assignment
Why B: Policy assignments at a management group scope inherit to all subscriptions underneath. One assignment covers all three — and any future subscriptions added to the group automatically inherit it.
Why not A: Technically correct but inefficient — three separate assignments to maintain. Adding a fourth subscription requires another manual assignment.
Why not C: RBAC is not the tool for enforcing resource properties like VM size. Custom RBAC roles cannot filter on resource attributes (size, SKU, etc.) — that's what Policy does.
Why not D: Blueprints can assign policies but are designed for full environment setup (RBAC + Policy + ARM templates together). Using Blueprints just to assign one policy to three subscriptions is over-engineering.
Exam tip: "Enforce across multiple subscriptions with minimum effort" = management group + policy assignment.
Q5
A developer has the Contributor role on a resource group. They need to grant a new contractor the Reader role on the same resource group. What is the minimum additional permission required?
- A. Owner at the subscription level
- B. User Access Administrator at the resource group level
- C. Security Administrator in Entra ID
- D. The Contributor role is sufficient — they can assign any role within their scope
Answer + Explanation
Correct: B — User Access Administrator at the resource group level
Why B: Assigning roles requires Microsoft.Authorization/roleAssignments/write. The minimum role that includes this is User Access Administrator — and since the assignment only needs to happen at the RG level, the RG scope is sufficient (least privilege).
Why not A: Owner at the subscription level would work, but it grants far more than necessary (Owner access to the entire subscription, not just the RG). The question asks for minimum permission.
Why not C: Security Administrator is an Entra ID role — it has no Azure RBAC assignment rights.
Why not D: Contributor explicitly excludes Microsoft.Authorization/* actions — it cannot assign roles. This is the most common wrong answer chosen by candidates.
Q6
A ReadOnly lock is applied to a storage account. A user with the Owner RBAC role attempts to list the storage account's access keys. The operation fails. Why?
- A. Owners cannot list access keys — they need the Storage Account Key Operator Service Role
- B. Listing access keys is classified as a write operation, which ReadOnly locks block
- C. Access keys are managed by Entra ID, not by Azure RBAC
- D. The ReadOnly lock was applied at a higher scope and cascades down
Answer + Explanation
Correct: B — listKeys is classified as a write operation on the management plane
Why B: The listKeys action (Microsoft.Storage/storageAccounts/listKeys/action) is classified as a write operation because it retrieves credentials that grant full data-plane access. A ReadOnly lock blocks all write actions on the management plane — including listKeys, even for Owners.
Why not A: Owners can list access keys under normal circumstances (no lock). The Storage Account Key Operator Service Role is a real role but is not relevant here.
Why not C: Access keys are Azure resource management objects, not Entra ID objects.
Why not D: The question says the lock is applied directly on the storage account — no cascade needed. But even if inherited, the result is the same.
Exam tip: ReadOnly lock on storage = cannot list keys. ReadOnly lock on VM = cannot start/stop the VM. ReadOnly is more restrictive than it sounds.
Q7
Which of the following statements about the relationship between Azure Policy and Azure RBAC is TRUE?
- A. A Deny Policy is overridden by an Owner RBAC role assignment
- B. RBAC controls what a principal can attempt; Policy controls whether the attempt succeeds
- C. Azure Policy and Azure RBAC are the same underlying system with different UIs
- D. You must be a Global Administrator in Entra ID to create Policy assignments
Answer + Explanation
Correct: B — RBAC and Policy are complementary, sequential systems
Why B: The request flow is:
- RBAC check — does the principal have permission to attempt this action? If not → denied.
- Policy check — does the resource configuration comply with policies? If a Deny policy matches → denied.
Both must pass. Policy can block even an Owner.
Why not A: Policy Deny effect is not overridden by any RBAC role — not even Owner. They are separate systems; RBAC cannot bypass Policy.
Why not C: They are completely different systems with different APIs, resources, and scope models.
Why not D: Creating Policy assignments requires the Resource Policy Contributor Azure RBAC role (or Owner) — not Entra Global Admin.
Q8
You have an Entra ID user with the User Administrator role. This user has no Azure RBAC assignments. They attempt to create a new virtual machine in a subscription. What happens?
- A. They succeed — User Administrator is a high-privilege Entra role
- B. They fail — Entra ID roles do not grant any Azure resource permissions
- C. They succeed — Entra roles automatically grant Contributor to all subscriptions
- D. They fail — they need to be a Subscription Owner, which requires Global Admin approval
Answer + Explanation
Correct: B — Entra ID roles have no Azure resource permissions
Why B: User Administrator is an Entra ID role — it grants permission to manage directory objects (users, groups, passwords). It has zero Azure resource permissions. Creating a VM requires at minimum the Contributor Azure RBAC role on the target subscription or resource group.
Why not A/C: Entra roles and Azure RBAC roles are completely separate. No Entra role automatically grants any Azure RBAC permission (unless the Global Admin uses the Entra elevation toggle, which gives User Access Administrator on Azure subscriptions).
Why not D: There is no "Global Admin approval" process for subscription ownership — it's just an Azure RBAC assignment.
This is the #1 exam trap in Domain 1. Whenever a question presents an Entra ID role and asks about Azure resource access, the Entra role provides nothing unless an Azure RBAC role is also assigned.
Q9 — Scenario
Your organization is acquiring a company. You need to give their IT team read-only access to all resources in your three production subscriptions with minimum effort. You also want any new production subscriptions created in the future to automatically have this access.
Which combination of steps achieves this?
- A. Assign Reader role to the IT team group in each of the three subscriptions; manually repeat for future subscriptions
- B. Create a management group containing all production subscriptions; assign the Reader role to the IT team group at the management group scope
- C. Add the IT team users as Guest users and assign them Subscription Reader in Entra ID
- D. Create an Azure Blueprint that assigns the Reader role and assign it to each subscription
Answer + Explanation
Correct: B — Management group + Reader at management group scope
Why B: Management group RBAC inherits to all current and future subscriptions placed under it. One assignment covers all three subscriptions today and any new production subscriptions added tomorrow.
Why not A: Works but requires manual re-assignment for every new subscription. Doesn't satisfy "automatically included future subscriptions."
Why not C: "Subscription Reader in Entra ID" doesn't exist — Entra roles don't map to Azure subscription access. Guest users still need Azure RBAC assignments.
Why not D: Blueprints work but are heavier than needed for a single RBAC assignment. Also, Blueprint assignments are per-subscription, not inherited automatically for future subscriptions added later.
Q10 — Tricky
You assign a Deny policy at the subscription level that blocks creation of public IP addresses. A user with Owner role on a resource group tries to create a VM with a public IP. What is the result?
- A. The VM and public IP are both created — Owner overrides Policy
- B. Both the VM and public IP creation fail
- C. The public IP creation is blocked, but the VM is created without a public IP
- D. The VM creation fails; the public IP creation succeeds
Answer + Explanation
Correct: C — Public IP is blocked; VM creation succeeds without it
Why C: The Deny policy targets Microsoft.Network/publicIPAddresses — only that resource type is blocked. The VM itself is Microsoft.Compute/virtualMachines, which is not covered by this policy. Azure Resource Manager evaluates each resource deployment separately — the VM succeeds; the public IP fails.
Why not A: Owner does not override Policy. Policy and RBAC are independent systems; RBAC allows the attempt, Policy evaluates the resource.
Why not B: The VM itself is not a public IP — it's a separate resource type. The policy only blocks publicIPAddresses.
Why not D: The VM deployment succeeds (it's not covered by the policy). The IP fails because it is directly targeted.
Exam tip: Azure Policy targets specific
"type"values. A policy targetingpublicIPAddressesdoesn't block the VM — it only blocks the public IP resource itself. The VM just won't have a public IP attached.
Domain 2: Implement and Manage Storage
Exam weight: 15–20%
Storage tests your ability to provision and operate Azure's data services. The trickiest parts are replication type trade-offs, SAS token mechanics, and access tier transitions — all of which appear repeatedly in exam questions and live lab tasks.
2.1 Storage Account Types
All Azure storage services (Blob, Files, Queues, Tables) live inside a storage account. The account type determines which services and performance tiers are available.
| Account kind | Services | Performance |
|---|---|---|
| General Purpose v2 (GPv2) | Blob, Files, Queues, Tables | Standard or Premium |
| Blob Storage (legacy) | Blob only | Standard — upgrade to GPv2 instead |
| Premium Block Blobs | Block blobs only | Premium SSD |
| Premium File Shares | Azure Files only | Premium SSD |
| Premium Page Blobs | Page blobs only (VM disks) | Premium SSD |
Exam tip: For any new deployment, use GPv2. The exam will sometimes offer "Blob Storage account" as an option — it's a legacy type that you should not choose unless the question specifically requires it.
2.2 Redundancy (Replication)
This is the highest-frequency storage topic in the exam. Know every acronym, what it protects against, and whether reads can be made from the secondary.
| Replication | Full name | Copies | Protects against | Read from secondary? |
|---|---|---|---|---|
| LRS | Locally Redundant Storage | 3 in 1 datacenter | Hardware failure | No |
| ZRS | Zone-Redundant Storage | 3 in 3 zones, 1 region | Zone (datacenter) failure | No |
| GRS | Geo-Redundant Storage | 3 LRS primary + 3 LRS secondary region | Regional failure | No (unless RA-GRS) |
| GZRS | Geo-Zone-Redundant Storage | 3 ZRS primary + 3 LRS secondary region | Zone + regional failure | No (unless RA-GZRS) |
| RA-GRS | Read-Access GRS | Same as GRS | Regional failure | Yes — secondary endpoint |
| RA-GZRS | Read-Access GZRS | Same as GZRS | Zone + regional failure | Yes — secondary endpoint |
Secondary Endpoint Format
For RA-GRS/RA-GZRS, the secondary read endpoint is:
https://<account>-secondary.blob.core.windows.net
Exam trap: GRS replicates data to a secondary region but you cannot read from the secondary by default. Only RA-GRS (and RA-GZRS) enable reads from the secondary. Questions that say "users in a secondary region must be able to read data even during a primary region outage" → RA-GRS or RA-GZRS.
Exam trap: You can only failover a GRS account to the secondary region if Microsoft declares the primary unavailable — or you manually initiate customer-managed failover. After failover, replication is broken; you must re-enable it.
2.3 Access Tiers
Access tiers apply to Blob storage and control the cost balance between storage cost and access cost.
| Tier | Storage cost | Access cost | Minimum storage duration | Use case |
|---|---|---|---|---|
| Hot | Highest | Lowest | None | Frequently accessed data |
| Cool | Lower | Higher | 30 days | Infrequent access, kept ≥30 days |
| Cold | Lower than Cool | Higher than Cool | 90 days | Infrequent access, kept ≥90 days |
| Archive | Lowest | Highest + rehydration time | 180 days | Rarely accessed, long-term |
Archive Rehydration
Blobs in Archive tier are offline — you cannot read them directly. You must rehydrate first:
- Priority: Standard — up to 15 hours
- Priority: High — under 1 hour (higher cost)
Rehydration options:
- Change the blob tier to Hot or Cool (
Set Blob Tier) - Copy the blob to a Hot/Cool destination
Exam trap: Archive blobs cannot be read without rehydration. Questions about "immediate read access" → answer must not use Archive tier.
Lifecycle Management Policies
Automate tier transitions and deletions based on rules:
{
"rules": [{
"name": "move-to-cool",
"type": "Lifecycle",
"definition": {
"filters": { "blobTypes": ["blockBlob"], "prefixMatch": ["logs/"] },
"actions": {
"baseBlob": {
"tierToCool": { "daysAfterModificationGreaterThan": 30 },
"tierToArchive": { "daysAfterModificationGreaterThan": 90 },
"delete": { "daysAfterModificationGreaterThan": 365 }
}
}
}
}]
}
2.4 Blob Types
| Type | Description | Use case |
|---|---|---|
| Block blob | Optimized for large objects uploaded in blocks | Files, media, backups |
| Append blob | Optimized for append-only operations | Logs, event streams |
| Page blob | Random read/write in 512-byte pages | Azure VM disks (VHDs) |
Exam tip: VM unmanaged disks = Page blobs. You cannot change blob type after creation.
2.5 Access Control Options
Three ways to authorize access to storage — each with different trade-offs:
1. Access Keys (Account Keys)
- Two keys per account (Key1, Key2) — rotate without downtime.
- Full access to everything in the account — no scoping possible.
- Should be stored in Azure Key Vault, not in code.
- Listing keys is blocked by a ReadOnly lock.
2. Shared Access Signatures (SAS)
A SAS is a URI that grants scoped, time-limited access.
| SAS type | Signs with | Revoke how |
|---|---|---|
| Account SAS | Account access key | Rotate the key (affects all SAS signed with it) |
| Service SAS | Account access key | Rotate the key |
| User Delegation SAS | Entra ID credentials | Revoke via az storage account revoke-delegation-keys |
Exam tip: User delegation SAS is the most secure type — it uses Entra identity, not the account key, so rotating keys doesn't affect it. It's scoped to Blob or Data Lake only.
Stored Access Policy
A Stored Access Policy (SAP) is defined on a container (not the account). SAS tokens can reference a SAP by name, which allows you to revoke the SAS without rotating the key — just delete or modify the SAP.
Exam trap: You can only revoke a standalone SAS (not linked to a SAP) by rotating the signing key. If a question says "revoke specific SAS without affecting other SAS tokens" → the answer involves a Stored Access Policy.
3. Managed Identity + Role Assignment
Assign a storage data role to the managed identity:
Storage Blob Data Reader— read blobsStorage Blob Data Contributor— read/write/delete blobsStorage Blob Data Owner— full control including POSIX ACLs
Exam tip: For service-to-storage auth, managed identity + RBAC data role is the recommended approach. It eliminates credentials entirely.
2.6 Azure Files
Azure Files provides SMB and NFS file shares in the cloud — a lift-and-shift replacement for on-prem file servers.
| Protocol | Port | Auth options |
|---|---|---|
| SMB 3.0 | 445 | AD DS, Entra ID, Storage Account Key |
| NFS 4.1 | 2049 | VNet integration (no public access) |
Exam trap: Port 445 (SMB) is blocked by many ISPs and corporate firewalls. If users can't mount a file share from home, the fix is to use Azure VPN or Azure File Sync to cache files locally, not to change the port.
Azure File Sync
Extends Azure Files to on-premises servers:
- Install the Azure File Sync agent on Windows Server.
- Enables cloud tiering: frequently accessed files stay local; cold files are tiered to Azure (appear as stubs).
- Multiple servers can sync to the same share — replacing DFS.
2.7 Storage Security
Encryption
- At rest: All data is encrypted by default using Microsoft-managed keys (256-bit AES).
- Customer-managed keys (CMK): Bring your own key stored in Azure Key Vault — you control rotation and revocation.
- In transit: HTTPS is enforced by default (
Secure transfer requiredis on).
Versioning and Soft Delete
| Feature | What it does | Scope |
|---|---|---|
| Blob versioning | Keeps every previous version of a blob on overwrite | Per storage account |
| Blob soft delete | Retains deleted blobs for a configurable retention period | Per storage account |
| Container soft delete | Retains deleted containers | Per storage account |
Immutability (WORM)
WORM (Write Once Read Many) policies prevent deletion or modification for a set period:
- Time-based retention: Data cannot be modified or deleted for a defined interval.
- Legal hold: Data locked until the hold is explicitly removed.
Used for compliance scenarios (financial records, healthcare). Even storage account admins cannot delete data under an active WORM lock.
Section Takeaways
| Topic | Key Point |
|---|---|
| GPv2 | Default choice for all new storage accounts |
| LRS vs ZRS vs GRS | LRS = 1 DC; ZRS = 3 zones; GRS = 2 regions |
| RA-GRS vs GRS | Only RA-GRS allows reading from secondary |
| Archive tier | Must rehydrate before reading — up to 15 hours standard |
| SAS revocation | Standalone SAS = rotate key; SAP-linked SAS = delete/modify SAP |
| User delegation SAS | Most secure — uses Entra ID, not account key |
| Managed identity for storage | Best practice — no credentials to manage |
| ReadOnly lock + storage | Blocks listKeys — even for Owners |
| SMB port 445 | Often blocked by ISPs — use VPN or File Sync as workaround |
| WORM policy | Even admins cannot delete data under active retention/hold |
Confusing Points — Clarified
Q: If GRS replicates to a second region, why can't I read from it? A: Replication is asynchronous and the secondary is a failover target, not a read replica. Microsoft wants to avoid you building apps that depend on eventual consistency without realizing it. You must opt into RA-GRS explicitly to get read access to the secondary.
Q: What happens to SAS tokens if I rotate the account key? A: Any SAS signed with that key immediately becomes invalid. This is why SAP-linked SAS tokens are better — you can invalidate just the policy without rotating the key.
Q: Can I change a blob's access tier at any time? A: Yes, but early deletion fees apply if you move out of Cool (before 30 days), Cold (before 90 days), or Archive (before 180 days).
Q: What's the difference between Storage Blob Data Contributor and Contributor?
A: Contributor is an Azure RBAC management-plane role — it can manage the storage account (create containers, change settings) but cannot read/write blob data without also having a data plane role. Storage Blob Data Contributor grants data-plane access (read/write blob content). Both are often needed together.
Lab 02: Storage Account, SAS Tokens, and Lifecycle Policies
Estimated time: 45–60 minutes Difficulty: ⭐⭐☆☆☆ Environment: Azure free account — portal + Azure CLI
Prerequisites
- Azure CLI ≥ 2.50 with
az logincomplete az storageextension available (bundled with core CLI)
az account show --query "{name:name, id:id}" -o table
Lab Objectives
- Create a GPv2 storage account with specific redundancy and access tier
- Upload blobs and change access tiers manually
- Configure a lifecycle management policy for automatic tiering
- Generate a Service SAS token with limited permissions
- Create a Stored Access Policy and link a SAS to it
- Revoke the SAP-linked SAS without touching the account key
- Mount an Azure File share on macOS/Linux (bonus)
Step 1: Create the Storage Account
RG="rg-az104-lab02"
LOCATION="eastus"
# Storage account names: 3-24 chars, lowercase letters and numbers only
SA="staz104lab$(openssl rand -hex 3)"
az group create --name $RG --location $LOCATION
az storage account create \
--name $SA \
--resource-group $RG \
--location $LOCATION \
--sku Standard_GRS \
--kind StorageV2 \
--access-tier Hot \
--https-only true \
--min-tls-version TLS1_2
echo "Storage account: $SA"
# Verify
az storage account show \
--name $SA \
--resource-group $RG \
--query "{sku:sku.name, tier:accessTier, kind:kind, tls:minimumTlsVersion}" \
-o table
Why
--https-only trueand--min-tls-version TLS1_2? These are exam-common hardening settings and required for most compliance frameworks. Both are defaults in new accounts but worth knowing how to set explicitly.
Step 2: Create a Container and Upload Blobs
# Get the account key for subsequent operations
ACCT_KEY=$(az storage account keys list \
--account-name $SA \
--resource-group $RG \
--query "[0].value" -o tsv)
# Create a container (private access — no anonymous reads)
az storage container create \
--name "logs" \
--account-name $SA \
--account-key $ACCT_KEY \
--public-access off
# Create some test files and upload
echo "Log entry $(date)" > log1.txt
echo "Log entry $(date)" > log2.txt
echo "Archive data" > archive.txt
az storage blob upload \
--account-name $SA \
--account-key $ACCT_KEY \
--container-name "logs" \
--name "2024/jan/log1.txt" \
--file log1.txt \
--tier Hot
az storage blob upload \
--account-name $SA \
--account-key $ACCT_KEY \
--container-name "logs" \
--name "2024/jan/log2.txt" \
--file log2.txt \
--tier Hot
az storage blob upload \
--account-name $SA \
--account-key $ACCT_KEY \
--container-name "logs" \
--name "2023/archive.txt" \
--file archive.txt \
--tier Hot
# List blobs and verify tiers
az storage blob list \
--account-name $SA \
--account-key $ACCT_KEY \
--container-name "logs" \
--query "[].{name:name, tier:properties.blobTier}" \
-o table
Step 3: Manually Change a Blob's Access Tier
Change the archive blob to Cool tier:
az storage blob set-tier \
--account-name $SA \
--account-key $ACCT_KEY \
--container-name "logs" \
--name "2023/archive.txt" \
--tier Cool
# Verify
az storage blob show \
--account-name $SA \
--account-key $ACCT_KEY \
--container-name "logs" \
--name "2023/archive.txt" \
--query "properties.blobTier" -o tsv
⚠️ Tricky spot: Setting a blob to Archive makes it offline immediately. If you set it to Archive by mistake, you must rehydrate before you can read it — this takes up to 15 hours on Standard priority.
Step 4: Configure a Lifecycle Management Policy
Create a policy that:
- Moves blobs in the
logs/container to Cool after 30 days - Moves them to Archive after 90 days
- Deletes them after 365 days
cat > lifecycle-policy.json << 'EOF'
{
"rules": [
{
"name": "log-lifecycle",
"enabled": true,
"type": "Lifecycle",
"definition": {
"filters": {
"blobTypes": ["blockBlob"],
"prefixMatch": ["logs/2024/"]
},
"actions": {
"baseBlob": {
"tierToCool": {
"daysAfterModificationGreaterThan": 30
},
"tierToArchive": {
"daysAfterModificationGreaterThan": 90
},
"delete": {
"daysAfterModificationGreaterThan": 365
}
}
}
}
}
]
}
EOF
az storage account management-policy create \
--account-name $SA \
--resource-group $RG \
--policy @lifecycle-policy.json
# Verify the policy was applied
az storage account management-policy show \
--account-name $SA \
--resource-group $RG \
--query "policy.rules[].{name:name, prefix:definition.filters.prefixMatch}" \
-o table
Lifecycle policies run once per day. You won't see tier changes instantly in the lab — but you will be tested on the JSON structure and the
daysAfterModificationGreaterThanlogic in the exam.
Step 5: Create a Service SAS Token
Generate a SAS token scoped to the logs container with read-only permission, expiring in 1 hour:
# SAS expiry: 1 hour from now
EXPIRY=$(date -u -v+1H "+%Y-%m-%dT%H:%MZ" 2>/dev/null || date -u -d "+1 hour" "+%Y-%m-%dT%H:%MZ")
SAS_TOKEN=$(az storage container generate-sas \
--account-name $SA \
--account-key $ACCT_KEY \
--name "logs" \
--permissions "rl" \
--expiry $EXPIRY \
--https-only \
--output tsv)
echo "SAS Token: $SAS_TOKEN"
# Construct the full URL for a specific blob
BLOB_URL="https://$SA.blob.core.windows.net/logs/2024/jan/log1.txt?$SAS_TOKEN"
echo "Full URL: $BLOB_URL"
# Test read access using the SAS
curl -s "$BLOB_URL"
Test that write is denied:
# Try to upload with a read-only SAS — should fail with 403
az storage blob upload \
--account-name $SA \
--sas-token $SAS_TOKEN \
--container-name "logs" \
--name "unauthorized-write.txt" \
--file log1.txt
# Expected: AuthorizationPermissionMismatch
⚠️ Tricky spot: SAS permissions are a string of letters (
r=read,w=write,d=delete,l=list,a=add,c=create). They are not validated for logic conflicts — you can accidentally give too many permissions if you're not careful.
Step 6: Create a Stored Access Policy and Revoke It
A Stored Access Policy (SAP) lets you revoke SAS tokens by modifying the policy — without rotating the account key.
# Create a Stored Access Policy on the container
az storage container policy create \
--account-name $SA \
--account-key $ACCT_KEY \
--container-name "logs" \
--name "read-policy" \
--permissions "rl" \
--expiry $EXPIRY
# Create a SAS that references this policy
SAP_SAS=$(az storage container generate-sas \
--account-name $SA \
--account-key $ACCT_KEY \
--name "logs" \
--policy-name "read-policy" \
--https-only \
--output tsv)
echo "SAP-linked SAS: $SAP_SAS"
# Test read access works
curl -s "https://$SA.blob.core.windows.net/logs/2024/jan/log1.txt?$SAP_SAS"
Revoke by deleting the Stored Access Policy:
# Delete the SAP — this immediately invalidates all SAS tokens linked to it
az storage container policy delete \
--account-name $SA \
--account-key $ACCT_KEY \
--container-name "logs" \
--name "read-policy"
# Test: the SAP-linked SAS should now return 403
curl -I "https://$SA.blob.core.windows.net/logs/2024/jan/log1.txt?$SAP_SAS"
# Expected: 403 Forbidden — AuthorizationPermissionMismatch or similar
This is the key exam distinction: SAP-linked SAS → revoke by deleting the SAP. Standalone SAS → can only invalidate by rotating the account key (affects ALL SAS signed with that key).
Step 7: Enable Soft Delete (Bonus)
# Enable blob soft delete with 7-day retention
az storage account blob-service-properties update \
--account-name $SA \
--resource-group $RG \
--enable-delete-retention true \
--delete-retention-days 7
# Delete a blob
az storage blob delete \
--account-name $SA \
--account-key $ACCT_KEY \
--container-name "logs" \
--name "2024/jan/log1.txt"
# List deleted blobs (only visible with --include d)
az storage blob list \
--account-name $SA \
--account-key $ACCT_KEY \
--container-name "logs" \
--include d \
--query "[?deleted==\`true\`].{name:name, deleted:deleted}" \
-o table
# Undelete (restore)
az storage blob undelete \
--account-name $SA \
--account-key $ACCT_KEY \
--container-name "logs" \
--name "2024/jan/log1.txt"
Step 8: Clean Up
az group delete --name $RG --yes --no-wait
rm -f log1.txt log2.txt archive.txt lifecycle-policy.json
Lab Tricky Spots Summary
| Trap | Effect | Fix |
|---|---|---|
| Setting a blob to Archive immediately | Blob becomes unreadable until rehydrated (up to 15h) | Use Cool instead for data you need to access again soon |
| Standalone SAS is hard to revoke | Must rotate account key, which breaks all SAS signed with it | Always use SAP-linked SAS for any long-lived or shared token |
--permissions string typos | Silent wrong access — too many or too few permissions granted | Test SAS access immediately after generating |
| Lifecycle policy not applying | Policy runs once daily, not instantly | In the exam, you're tested on configuration, not on observing live results |
Standard_GRS account cannot use ZRS blobs | Replication type is set at account creation | Choose the right SKU at account creation — you cannot change LRS→ZRS in-place on existing accounts |
Lab Takeaways
- Account key = total access — always prefer SAS or Managed Identity over keys in production.
- SAP-linked SAS is the only revocable SAS without rotating the account key.
- Archive tier makes blobs offline — model your data before archiving.
- Lifecycle policies are declarative — write the policy, let Azure execute it daily.
- Soft delete + versioning provide a safety net but add storage costs — enable for production, disable for temporary lab accounts.
Domain 2: Practice Q&A — Storage
Answer each question before expanding the solution. Aim for under 2 minutes per question.
Q1
Your company stores compliance records in Azure Blob Storage. After 90 days, the blobs must be moved to Archive tier. After 3 years, they must be deleted. No manual intervention is acceptable.
Which feature should you configure?
- A. Azure Backup policies
- B. Blob lifecycle management policies
- C. Blob versioning with retention rules
- D. A logic app that runs daily and checks blob modification dates
Answer + Explanation
Correct: B — Blob lifecycle management policies
Why B: Lifecycle management policies are declarative rules that automatically transition blobs between tiers and delete them based on conditions like daysAfterModificationGreaterThan. No code, no manual action.
Why not A: Azure Backup policies are for protecting resources — they don't tier or delete blobs.
Why not C: Blob versioning preserves previous versions but doesn't automatically move or delete by age.
Why not D: A logic app would work technically but is unnecessary complexity when lifecycle policies do exactly this natively.
Q2
A storage account uses GRS replication. A regional outage affects the primary region. Users report they cannot read data. The secondary region is healthy.
Which action allows reads from the secondary region immediately without initiating a failover?
- A. Change the replication to RA-GRS
- B. Manually initiate a failover to the secondary region
- C. Create a read replica in the secondary region
- D. This is not possible with GRS — failover is required
Answer + Explanation
Correct: D — GRS does not allow reads from secondary; A would fix the problem going forward but not immediately
Most precise correct answer depends on exact question wording:
- If the question asks "what should you have done to prevent this?" → A (RA-GRS)
- If it asks "what can you do right now?" → B (initiate failover) — though this is destructive
- If GRS is already in place and the outage is ongoing → you cannot read the secondary without failover or changing to RA-GRS (which also has lag)
The exam usually frames this as: "To allow reads from the secondary during an outage without failover, which replication type should you have used?" → RA-GRS or RA-GZRS.
Key rule: GRS = no secondary reads. RA-GRS = secondary reads allowed at
https://<account>-secondary.blob.core.windows.net.
Q3
You generate a Service SAS token for a container with read/list permissions, valid for 24 hours. After 2 hours, a security incident requires you to immediately revoke the SAS without affecting other SAS tokens that grant access to other containers.
What is the fastest way to revoke only this SAS?
- A. Delete the storage container
- B. Rotate the storage account key used to sign the SAS
- C. Delete the Stored Access Policy associated with this SAS
- D. You cannot revoke a standalone SAS — wait for it to expire
Answer + Explanation
Correct: C — Delete the Stored Access Policy (if the SAS was linked to one)
OR
D is correct if the SAS was standalone (not linked to a SAP)
This question tests if you designed correctly: A standalone SAS (no SAP) can only be invalidated by:
- Letting it expire
- Rotating the signing key (but this breaks ALL SAS tokens signed with that key)
A SAP-linked SAS can be revoked by deleting or modifying the SAP — without rotating the key and without affecting other SAS tokens on other containers.
The correct design for revocable SAS: Always link SAS tokens to Stored Access Policies.
Exam tip: The question is really asking: "Did you know to use a SAP?" If the scenario says you need to revoke a single SAS without side effects, the answer implies a SAP-linked SAS and option C.
Q4
A developer wants to access blob data in a storage account from an Azure VM. You want to follow the principle of least privilege and avoid storing any credentials in the VM or its code.
Which approach should you use?
- A. Store the storage account access key in an environment variable on the VM
- B. Assign a system-assigned managed identity to the VM and grant it the
Storage Blob Data Readerrole on the storage account - C. Generate a long-lived SAS token with read permissions and store it in the VM's configuration
- D. Create a service principal with a client secret and store the secret in Azure Key Vault
Answer + Explanation
Correct: B — Managed identity + Storage Blob Data Reader
Why B: Managed identities are credential-free by design — the VM automatically obtains tokens from the Azure Instance Metadata Service (IMDS). No secret to store, rotate, or leak. Granting Storage Blob Data Reader provides exactly the data-plane access needed.
Why not A: Storing the account key (which has full access) in an env var is insecure and violates least privilege.
Why not C: Long-lived SAS tokens in config files are essentially the same problem as hardcoded credentials — they can be extracted and misused.
Why not D: Service principal + Key Vault is a legitimate pattern, but it's more complex than managed identity and still requires code to fetch the secret. Managed identity is simpler and preferred.
Exam tip: "No credentials to manage" or "no credentials stored in code" on an Azure VM = managed identity.
Q5
A storage account has a ReadOnly lock applied. An administrator with the Owner RBAC role attempts to list the storage account's access keys. The operation fails. What is the correct explanation?
- A. Owner does not have permission to list keys — they need the Key Vault Secrets Officer role
- B. The
listKeysoperation is classified as a write action on the management plane, which ReadOnly locks block - C. Access keys can only be listed by users with the Storage Account Contributor role
- D. The ReadOnly lock prevents all operations, including reads, when applied to storage accounts
Answer + Explanation
Correct: B — listKeys is a write action blocked by ReadOnly locks
Why B: The ARM action Microsoft.Storage/storageAccounts/listKeys/action is classified as a write because retrieving keys grants write-equivalent access to all data in the account. ReadOnly locks block all management-plane write actions — including listKeys — even for Owners.
Why not A: Key Vault Secrets Officer is irrelevant — storage account keys are not stored in Key Vault unless you explicitly put them there.
Why not C: Storage Account Contributor is a valid role, but the issue here is the lock, not RBAC permissions.
Why not D: ReadOnly locks allow read operations — they block writes and listKeys (classified as write). They don't block all operations.
Q6
You need to store VM disk VHD files in Azure Blob Storage. Which blob type must you use?
- A. Block blob
- B. Append blob
- C. Page blob
- D. Any blob type — the storage account handles the type automatically
Answer + Explanation
Correct: C — Page blob
Why C: Azure VM unmanaged disk VHDs are stored as page blobs because page blobs support random read/write access in 512-byte pages — exactly what a virtual disk requires for random I/O.
Why not A: Block blobs are optimized for streaming large sequential uploads — suitable for files, backups, media. Not for random-access disk I/O.
Why not B: Append blobs only support append operations — no in-place writes. Unusable for VM disks.
Why not D: Blob type must be specified — it doesn't auto-select. You cannot change blob type after creation.
Exam tip: VHD files → page blobs. Log files / event streams → append blobs. Everything else → block blobs.
Q7
You need to store log files that are written to constantly for 30 days, then accessed rarely for the next 60 days, then never accessed again. Cost optimization is the primary goal. Minimum access time must be under 1 hour for any log within its first 90 days.
Which configuration best meets these requirements?
- A. Hot tier for first 30 days, then Archive for days 30–90, then delete after 90 days
- B. Hot tier for first 30 days, then Cool tier for days 30–90, then delete after 90 days
- C. Hot tier for first 30 days, then Cold tier for days 30–90, then delete after 90 days
- D. Hot tier for entire 90 days, then delete
Answer + Explanation
Correct: B or C — both are valid depending on cost preference, but Archive tier (A) violates the access time requirement.
Why not A: Archive tier requires up to 15 hours for rehydration. The requirement says "under 1 hour" — Archive is immediately disqualified.
Why B (Cool): Cool tier provides immediate access. It's cheaper than Hot for storage cost, more expensive for access. Minimum storage duration is 30 days — which aligns with the transition happening exactly at day 30.
Why C (Cold): Cold tier is cheaper than Cool for storage but more expensive for access. Minimum storage duration is 90 days — transitioning blobs to Cold at day 30 means you're committed for 60 more days, matching the 90-day total. Cold was added in 2023 and is appearing in newer exam versions.
Exam tip: Archive tier = offline, rehydration required. If the question says "must be readable within hours" → Archive is never the answer.
Q8
A company needs to prevent any modification or deletion of financial records stored in Azure Blob Storage for exactly 7 years due to regulatory requirements. Even storage administrators must not be able to delete the data.
Which feature should you configure?
- A. Blob soft delete with 7-year retention
- B. Azure Backup with long-term retention policy
- C. Time-based WORM retention policy (immutability policy)
- D. ReadOnly resource lock on the container
Answer + Explanation
Correct: C — Time-based WORM (immutability) policy
Why C: A time-based retention policy on a container enforces WORM — Write Once, Read Many. For the duration of the retention period, no one (not even storage admins or owners) can delete or overwrite data. This is the only feature that satisfies the "even admins cannot delete" requirement.
Why not A: Soft delete prevents permanent deletion for a period, but an admin with the right RBAC can bypass soft delete by permanently deleting the soft-deleted blobs. It doesn't block admins.
Why not B: Azure Backup doesn't provide immutability on the original storage data.
Why not D: A ReadOnly lock blocks modifications but can be removed by an Owner or User Access Admin. It's not audit-proof for regulatory compliance.
Exam tip: "Even admins cannot delete" + "regulatory compliance" + "fixed retention period" = WORM immutability policy.
Domain 3: Deploy and Manage Azure Compute Resources
Exam weight: 20–25% — the highest-weight domain
Compute tests your ability to deploy and operate Azure's virtual machines, scale sets, App Service, and understand ARM templates. The live lab tasks most frequently involve compute operations — deploying VMs, configuring availability, and scaling.
3.1 Virtual Machines
VM Size Families
You don't need to memorize every VM size, but you need to know the families:
| Family | Optimized for | Example sizes |
|---|---|---|
| D-series (Dv5, Dsv5) | General purpose — balanced CPU/memory | D2s_v5, D4s_v5 |
| E-series | Memory-optimized — high RAM/CPU ratio | E4s_v5, E8s_v5 |
| F-series | Compute-optimized — high CPU/memory ratio | F4s_v2, F8s_v2 |
| B-series | Burstable — cheap, low sustained CPU with credits | B1s, B2s |
| L-series | Storage-optimized — high disk throughput/IOPS | L8s_v3 |
| N-series | GPU — ML training, graphics rendering | NC6, NV6 |
Exam tip: If a question says "cost-effective for workloads with variable CPU that don't run at 100% constantly," the answer is B-series (burstable).
VM Disks
| Disk type | Attached to | Performance | Persists? |
|---|---|---|---|
| OS disk | Every VM | Depends on disk SKU | Yes |
| Temporary (temp) disk | Every VM | Fast local SSD | No — lost on reallocation |
| Data disks | Optional, up to 64 | Depends on disk SKU | Yes |
Managed disk SKUs:
| SKU | IOPS | Use case |
|---|---|---|
| Standard HDD | Up to 500 | Dev/test, low-cost archival |
| Standard SSD | Up to 6,000 | Web servers, lightly used apps |
| Premium SSD | Up to 20,000 | Production databases, high-throughput |
| Ultra Disk | Up to 160,000 | Highest performance; zone-locked; must be pre-allocated |
Exam trap: The temporary disk is lost when a VM is stopped (deallocated), resized, or the underlying host is patched. Never store anything important on the temp disk. The D: drive (Windows) or
/dev/sdb(Linux) is typically the temp disk.
VM Extensions
Extensions run post-deployment scripts or install agents. Common ones:
- Custom Script Extension — run a shell/PowerShell script after deployment
- Azure Monitor Agent — collect metrics and logs
- Azure AD / SSH login — passwordless login with Entra credentials
3.2 VM Availability
This is the most confusing part of Domain 3. Three mechanisms, very different guarantees.
Availability Sets
Groups VMs across Fault Domains (FDs) and Update Domains (UDs) within a single datacenter.
| Concept | What it protects against | Default count |
|---|---|---|
| Fault Domain | Hardware failure (same rack/power/network) | 2–3 FDs |
| Update Domain | Azure platform maintenance (rolling restarts) | 5 UDs |
Guarantee: 99.95% SLA. Does NOT protect against datacenter-level failure (fire, flood, power outage for the entire DC).
Exam trap: Availability sets are configured at VM creation — you cannot add a running VM to an availability set. A VM in an availability set cannot use Ultra Disk or Premium SSD v2.
Availability Zones
Physically separate datacenters within a region, each with independent power, cooling, and networking.
- 3 zones per region (where available).
- VMs in different zones are protected against datacenter-level failures.
- SLA: 99.99% (higher than availability sets).
Exam trap: Availability zones and availability sets are mutually exclusive for a given VM — choose one or the other.
Virtual Machine Scale Sets (VMSS)
Automatically deploy and manage a group of identical VMs, scaling in/out based on demand.
| Feature | Detail |
|---|---|
| Scaling modes | Manual, scheduled, metric-based (autoscale) |
| Orchestration modes | Uniform (all identical) or Flexible (mix sizes) |
| Rolling upgrades | Update VMs in batches without downtime |
| Overprovisioning | Spins up extra VMs to reduce time; excess are deleted |
Exam trap: VMSS with Uniform orchestration requires all VMs to use the same image and size. Flexible orchestration allows heterogeneous VMs and is the recommended mode for new deployments.
Comparison
| Feature | Availability Set | Availability Zone | VMSS |
|---|---|---|---|
| Protects against | Hardware/maintenance | Datacenter failure | Scale + maintenance |
| SLA | 99.95% | 99.99% | Depends on configuration |
| Location | Single datacenter | Multiple datacenters in region | Either |
| Auto-scaling | No | No | Yes |
3.3 Azure Bastion
Azure Bastion provides browser-based SSH/RDP access to VMs without a public IP on the VM.
- Deployed into a dedicated subnet named exactly
AzureBastionSubnetwith a minimum /26 CIDR. - Requires a Standard SKU Public IP.
- No VPN, no public IP on the VM, no NSG changes needed on the VM subnet.
Exam trap: The subnet must be named exactly
AzureBastionSubnet— any other name causes deployment to fail.
Bastion SKUs:
| SKU | Features |
|---|---|
| Basic | Browser-based RDP/SSH only |
| Standard | Copy/paste, file transfer, native client support, IP-based connections |
3.4 ARM Templates
ARM templates are JSON files that declare Azure resources. They enable Infrastructure as Code (IaC) for repeatable deployments.
Template Structure
{
"$schema": "...",
"contentVersion": "1.0.0.0",
"parameters": { // User inputs at deploy time
"vmName": {
"type": "string",
"defaultValue": "myVM"
}
},
"variables": { // Computed values reused within the template
"nicName": "[concat(parameters('vmName'), '-nic')]"
},
"resources": [ // The actual resources to deploy
{
"type": "Microsoft.Compute/virtualMachines",
"apiVersion": "2023-03-01",
"name": "[parameters('vmName')]",
"location": "[resourceGroup().location]",
"properties": { ... }
}
],
"outputs": { // Values returned after deployment
"vmId": {
"type": "string",
"value": "[resourceId('Microsoft.Compute/virtualMachines', parameters('vmName'))]"
}
}
}
Key ARM Functions (exam-tested)
| Function | Example | Returns |
|---|---|---|
resourceGroup().location | [resourceGroup().location] | RG's location |
concat() | [concat('st', parameters('suffix'))] | Joined string |
resourceId() | [resourceId('Microsoft.Network/virtualNetworks', 'myVnet')] | ARM resource ID |
uniqueString() | [uniqueString(resourceGroup().id)] | 13-char deterministic hash |
parameters() | [parameters('vmName')] | Parameter value |
variables() | [variables('nicName')] | Variable value |
Deployment Commands
# Deploy to a resource group
az deployment group create \
--resource-group rg-prod \
--template-file azuredeploy.json \
--parameters @azuredeploy.parameters.json
# What-if (preview changes without deploying)
az deployment group what-if \
--resource-group rg-prod \
--template-file azuredeploy.json
# Validate (syntax check only)
az deployment group validate \
--resource-group rg-prod \
--template-file azuredeploy.json
3.5 Bicep
Bicep is Azure's domain-specific language for IaC — it compiles to ARM JSON. It's simpler syntax, better IntelliSense, and the recommended approach for new deployments.
param location string = resourceGroup().location
param vmName string = 'myVM'
resource vm 'Microsoft.Compute/virtualMachines@2023-03-01' = {
name: vmName
location: location
properties: {
// ...
}
}
Key commands:
az bicep build --file main.bicep # Compile to ARM JSON
az deployment group create \
--resource-group rg-prod \
--template-file main.bicep # Deploy Bicep directly (CLI handles compilation)
Exam tip: The exam may show both ARM JSON and Bicep snippets. Know what each section does (parameters, variables, resources, outputs) and how to reference parameter values with
[parameters('name')](ARM) or justparamName(Bicep).
3.6 Azure App Service
App Service is a fully managed PaaS for web apps, REST APIs, and mobile backends.
App Service Plans
The plan defines the compute resources for all apps hosted on it.
| Tier group | Tiers | Key features |
|---|---|---|
| Free/Shared | F1, D1 | Shared VMs, no SLA, no custom domains |
| Basic | B1, B2, B3 | Dedicated VMs, manual scale, custom domains, TLS |
| Standard | S1, S2, S3 | Auto-scale, staging slots (5), daily backups |
| Premium | P1v3, P2v3 | More scale, VNet integration, up to 30 slots |
| Isolated | I1v2, I2v2 | Dedicated VNet/hardware (App Service Environment) |
Exam trap: Deployment slots (blue/green) require Standard tier or above. Free and Basic plans do not support slots.
Exam trap: Auto-scaling requires Standard tier or above. Basic only supports manual scaling.
Deployment Methods
| Method | Use case |
|---|---|
az webapp deployment source config-zip | ZIP deploy from local file |
| GitHub Actions / Azure DevOps | CI/CD pipeline |
az webapp deploy | Flexible deployment (WAR, JAR, ZIP, etc.) |
| FTP/FTPS | Legacy — not recommended |
| Local Git | Push directly to App Service's Git endpoint |
Deployment Slots
A staging slot is a separate running instance of your app — deploy to staging, test, then swap to production. Swap is near-instant with no downtime.
# Create a staging slot
az webapp deployment slot create \
--name myapp \
--resource-group rg-prod \
--slot staging
# Swap staging → production
az webapp deployment slot swap \
--name myapp \
--resource-group rg-prod \
--slot staging \
--target-slot production
3.7 Azure Container Instances (ACI)
ACI runs containers without managing VMs — the simplest way to run a container in Azure.
- No cluster management, no orchestration
- Billed per second of CPU/memory used
- Supports Linux and Windows containers
- Can mount Azure File shares as volumes
- Suitable for: CI/CD jobs, batch tasks, simple stateless APIs
Exam tip: The exam often presents a scenario with a short-lived container workload (data processing job, nightly batch) and asks which compute service to use. ACI is the answer for simple container tasks; AKS for long-running containerized apps at scale.
Section Takeaways
| Topic | Key Point |
|---|---|
| Temp disk | Lost on deallocate/resize — never store important data |
| Availability set | FDs + UDs; same datacenter; 99.95% SLA |
| Availability zone | Different DCs in region; 99.99% SLA; mutually exclusive with availability sets |
| VMSS | Auto-scale; Uniform vs Flexible orchestration modes |
| Azure Bastion subnet | Must be named exactly AzureBastionSubnet; minimum /26 |
ARM what-if | Preview changes without deploying |
| App Service slots | Standard tier minimum |
| App Service autoscale | Standard tier minimum |
| ACI | Best for short-lived, simple container tasks without cluster management |
| Bicep | Compiles to ARM JSON; preferred for new IaC |
Confusing Points — Clarified
Q: Can I move a VM from one availability set to another? A: No. Availability set membership is set at VM creation and cannot be changed. You'd need to delete and recreate the VM.
Q: What's the difference between stopping (deallocated) and stopping (stopped/not deallocated)? A: A deallocated VM releases the underlying hardware — you are not billed for compute. The public IP (if dynamic) is released. A stopped (not deallocated) VM keeps the hardware reserved — you still pay. In the portal, clicking "Stop" deallocates by default.
Q: Does a VMSS automatically scale in (remove instances) as well as out? A: Yes, if you configure autoscale rules for both scale-out and scale-in. By default, you can set a minimum instance count so it never scales in below that threshold.
Q: When I swap a deployment slot, does the connection string also swap? A: By default, yes — all settings swap. But settings marked as slot settings (sticky) stay with their slot and don't swap. Use sticky settings for things like connection strings pointing to each environment's specific database.
Lab 03: Virtual Machines, VMSS, and ARM Templates
Estimated time: 60–75 minutes Difficulty: ⭐⭐⭐☆☆ Environment: Azure free account — portal + Azure CLI
Prerequisites
- Azure CLI ≥ 2.50 with
az login - A subscription with available quota for B-series VMs
az account show --query "{name:name, id:id}" -o table
Lab Objectives
- Deploy a VM using an ARM template with parameters
- Add a data disk and verify it
- Configure a VM Scale Set with autoscale
- Deploy an App Service with a staging slot and perform a slot swap
- Create an Azure Bastion host and test browser-based SSH
Step 1: Create the Resource Group
RG="rg-az104-lab03"
LOCATION="eastus"
az group create --name $RG --location $LOCATION
Step 2: Deploy a VM via ARM Template
Create the ARM template file:
cat > vm-template.json << 'EOF'
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"vmName": {
"type": "string",
"defaultValue": "vm-lab03",
"metadata": { "description": "Name of the virtual machine" }
},
"adminUsername": {
"type": "string",
"defaultValue": "azureuser"
},
"adminPassword": {
"type": "securestring"
},
"location": {
"type": "string",
"defaultValue": "[resourceGroup().location]"
}
},
"variables": {
"vnetName": "vnet-lab03",
"subnetName": "default",
"nicName": "[concat(parameters('vmName'), '-nic')]",
"osDiskName": "[concat(parameters('vmName'), '-osdisk')]"
},
"resources": [
{
"type": "Microsoft.Network/virtualNetworks",
"apiVersion": "2023-05-01",
"name": "[variables('vnetName')]",
"location": "[parameters('location')]",
"properties": {
"addressSpace": { "addressPrefixes": ["10.0.0.0/16"] },
"subnets": [{
"name": "[variables('subnetName')]",
"properties": { "addressPrefix": "10.0.1.0/24" }
}]
}
},
{
"type": "Microsoft.Network/networkInterfaces",
"apiVersion": "2023-05-01",
"name": "[variables('nicName')]",
"location": "[parameters('location')]",
"dependsOn": ["[variables('vnetName')]"],
"properties": {
"ipConfigurations": [{
"name": "ipconfig1",
"properties": {
"privateIPAllocationMethod": "Dynamic",
"subnet": {
"id": "[resourceId('Microsoft.Network/virtualNetworks/subnets', variables('vnetName'), variables('subnetName'))]"
}
}
}]
}
},
{
"type": "Microsoft.Compute/virtualMachines",
"apiVersion": "2023-03-01",
"name": "[parameters('vmName')]",
"location": "[parameters('location')]",
"dependsOn": ["[variables('nicName')]"],
"properties": {
"hardwareProfile": { "vmSize": "Standard_B2s" },
"storageProfile": {
"imageReference": {
"publisher": "Canonical",
"offer": "0001-com-ubuntu-server-jammy",
"sku": "22_04-lts-gen2",
"version": "latest"
},
"osDisk": {
"name": "[variables('osDiskName')]",
"createOption": "FromImage",
"managedDisk": { "storageAccountType": "Standard_SSD_LRS" }
}
},
"osProfile": {
"computerName": "[parameters('vmName')]",
"adminUsername": "[parameters('adminUsername')]",
"adminPassword": "[parameters('adminPassword')]"
},
"networkProfile": {
"networkInterfaces": [{
"id": "[resourceId('Microsoft.Network/networkInterfaces', variables('nicName'))]"
}]
}
}
}
],
"outputs": {
"vmId": {
"type": "string",
"value": "[resourceId('Microsoft.Compute/virtualMachines', parameters('vmName'))]"
},
"privateIp": {
"type": "string",
"value": "[reference(variables('nicName')).ipConfigurations[0].properties.privateIPAddress]"
}
}
}
EOF
Run what-if first (preview changes without deploying):
az deployment group what-if \
--resource-group $RG \
--template-file vm-template.json \
--parameters adminPassword="P@ssw0rd!Azure104"
Review the output — it shows every resource that will be created, modified, or deleted.
Deploy the template:
az deployment group create \
--resource-group $RG \
--template-file vm-template.json \
--parameters adminPassword="P@ssw0rd!Azure104" \
--query "properties.outputs" \
-o table
⚠️ Tricky spot: The ARM template uses
"dependsOn"to control deployment order. The NIC depends on the VNet (needs the subnet ID), and the VM depends on the NIC. If you omitdependsOn, resources may try to deploy in parallel before their dependencies exist.
Step 3: Add a Data Disk to the VM
# Create a managed disk
az disk create \
--resource-group $RG \
--name "vm-lab03-datadisk01" \
--size-gb 32 \
--sku Standard_SSD_LRS \
--location $LOCATION
# Attach the disk to the VM
az vm disk attach \
--resource-group $RG \
--vm-name "vm-lab03" \
--name "vm-lab03-datadisk01"
# Verify the disk is attached
az vm show \
--resource-group $RG \
--name "vm-lab03" \
--query "storageProfile.dataDisks[].{name:name, lun:lun, sizeGb:diskSizeGb}" \
-o table
⚠️ Tricky spot: Attaching a disk does NOT format or mount it inside the OS. You still need to SSH in and run
fdisk+mkfs+mountto use the disk. In the exam, "attach" and "format/mount" are separate concepts.
Step 4: Configure a VM Scale Set with Autoscale
# Create a VMSS in Flexible orchestration mode
az vmss create \
--resource-group $RG \
--name "vmss-lab03" \
--image Ubuntu2204 \
--admin-username azureuser \
--admin-password "P@ssw0rd!Azure104" \
--instance-count 2 \
--vm-sku Standard_B2s \
--orchestration-mode Flexible \
--platform-fault-domain-count 1 \
--location $LOCATION
# Add autoscale profile
VMSS_ID=$(az vmss show \
--resource-group $RG \
--name "vmss-lab03" \
--query id -o tsv)
az monitor autoscale create \
--resource $VMSS_ID \
--resource-group $RG \
--name "autoscale-lab03" \
--min-count 2 \
--max-count 5 \
--count 2
# Add scale-out rule: scale out when CPU > 70% for 5 minutes
az monitor autoscale rule create \
--resource-group $RG \
--autoscale-name "autoscale-lab03" \
--condition "Percentage CPU > 70 avg 5m" \
--scale out 1
# Add scale-in rule: scale in when CPU < 30% for 5 minutes
az monitor autoscale rule create \
--resource-group $RG \
--autoscale-name "autoscale-lab03" \
--condition "Percentage CPU < 30 avg 5m" \
--scale in 1
# Verify
az monitor autoscale show \
--resource-group $RG \
--name "autoscale-lab03" \
--query "{min:profiles[0].capacity.minimum, max:profiles[0].capacity.maximum, default:profiles[0].capacity.default}" \
-o table
⚠️ Tricky spot:
--min-countand--max-countdefine the bounds for autoscale, not actual instance counts. The current instance count is--count. Autoscale will never go below min or above max.
Step 5: Deploy an App Service with Deployment Slots
# Create App Service Plan (Standard required for slots)
az appservice plan create \
--name "plan-lab03" \
--resource-group $RG \
--sku S1 \
--is-linux
# Create the web app
APP_NAME="webapp-lab03-$(openssl rand -hex 3)"
az webapp create \
--resource-group $RG \
--plan "plan-lab03" \
--name $APP_NAME \
--runtime "NODE:20-lts"
echo "App URL: https://$APP_NAME.azurewebsites.net"
# Create a staging deployment slot
az webapp deployment slot create \
--name $APP_NAME \
--resource-group $RG \
--slot staging
echo "Staging URL: https://$APP_NAME-staging.azurewebsites.net"
# Deploy a simple HTML app to staging
mkdir -p /tmp/webapp && cat > /tmp/webapp/index.html << 'HTMLEOF'
<!DOCTYPE html>
<html><body><h1>STAGING SLOT — Build v2</h1></body></html>
HTMLEOF
cd /tmp && zip -j webapp.zip webapp/index.html
az webapp deployment source config-zip \
--resource-group $RG \
--name $APP_NAME \
--slot staging \
--src /tmp/webapp.zip
# Test staging before swap
curl -s "https://$APP_NAME-staging.azurewebsites.net" | grep "STAGING"
Perform the slot swap:
az webapp deployment slot swap \
--resource-group $RG \
--name $APP_NAME \
--slot staging \
--target-slot production
# Verify production now shows the staging content
curl -s "https://$APP_NAME.azurewebsites.net" | grep "STAGING"
⚠️ Tricky spot: Slot swap is near-instant but app settings (unless marked sticky) swap too. If your production slot uses a different database connection string than staging, you must mark that setting as a slot setting (sticky) or the swap will point production at the staging database.
Step 6: Azure Bastion (Bonus — Portal Steps)
Bastion requires a Standard Public IP and a dedicated subnet — easier to do via portal for this lab:
- In the portal, open the VNet
vnet-lab03→ Subnets → + Gateway Subnet — NO, for Bastion you add: + Subnet → Name it exactlyAzureBastionSubnet→ Address range/26(minimum) - Search for Bastion in the portal → Create → Select
vnet-lab03and theAzureBastionSubnet - Create a new Standard Public IP for Bastion
- After deployment (takes ~5 min), go to
vm-lab03→ Connect → Bastion → enter credentials → browser-based SSH opens
⚠️ Tricky spot: The subnet name must be
AzureBastionSubnet— spelled exactly, case-sensitive. Any deviation causes deployment validation to fail immediately.
Step 7: Clean Up
az group delete --name $RG --yes --no-wait
rm -f vm-template.json /tmp/webapp.zip
rm -rf /tmp/webapp
Lab Tricky Spots Summary
| Trap | Effect | Fix |
|---|---|---|
Missing dependsOn in ARM template | Resources deploy in wrong order, causing failures | Explicitly declare dependencies or use reference() function (implicit dependency) |
| Attaching disk without formatting inside OS | Disk visible in Azure but unusable in VM | SSH in, run fdisk/mkfs/mount or use cloud-init |
| Autoscale with no scale-in rule | Scale set grows but never shrinks | Always add both scale-out and scale-in rules |
| Slot swap with non-sticky app settings | Production points to staging's database/config | Mark environment-specific settings as slot settings |
AzureBastionSubnet name typo | Bastion deployment validation fails | Copy-paste the name exactly — case-sensitive |
Lab Takeaways
what-ifbefore deploying is a critical exam skill — it previews changes without risk.- ARM outputs (
"outputs"section) let you capture resource properties (IPs, IDs) for post-deployment use. - Data disks are Azure resources but also need OS-level setup — attaching in Azure and mounting in the OS are separate steps.
- Autoscale rules come in pairs — scale-out trigger and scale-in trigger. One without the other creates an unbalanced system.
- Deployment slots are the cleanest zero-downtime deployment strategy for App Service.
Domain 3: Practice Q&A — Compute
Answer each question before expanding the solution. Aim for under 2 minutes per question.
Q1
You have a web application running on two VMs. You need to protect against planned Azure maintenance (platform updates) while also protecting against hardware failures on the same rack. Single-datacenter tolerance is acceptable — multi-region is not required.
Which availability option should you configure?
- A. Availability zones
- B. Availability set
- C. VM Scale Set with manual scaling
- D. Azure Site Recovery
Answer + Explanation
Correct: B — Availability set
Why B: Availability sets distribute VMs across Fault Domains (protect against rack/hardware failure) and Update Domains (protect against planned maintenance rolling restarts). Both requirements are satisfied within a single datacenter.
Why not A: Availability zones protect against datacenter-level failures (separate power/cooling/networking). The question says single-datacenter tolerance is acceptable and doesn't require multi-datacenter protection. Zones are overkill and more expensive.
Why not C: VMSS with manual scaling doesn't inherently provide the same FD/UD distribution guarantees as an availability set (it can, but that's not the primary purpose of manual scaling mode).
Why not D: Azure Site Recovery is a disaster recovery tool for replicating VMs to another region — not for local hardware/maintenance protection.
Q2
A VM is stopped (deallocated) and restarted. After the restart, a developer reports that data written to the D: drive is gone. What is the explanation?
- A. The D: drive was formatted as part of the OS restart process
- B. The D: drive is the temporary disk — it does not persist across deallocations
- C. A CanNotDelete lock prevented the data from being saved
- D. The disk was Standard HDD and was automatically upgraded on restart
Answer + Explanation
Correct: B — The D: drive is the temporary disk
Why B: On Windows Azure VMs, the D: drive (and /dev/sdb on Linux) is the temporary disk — a local SSD on the physical host. It is reset (data lost) when a VM is deallocated (stopped), resized, or migrated to a new physical host during maintenance. It is not a persistent managed disk.
Why not A: The OS restart doesn't touch the D: drive unless a disk formatting script was intentionally run.
Why not C: Locks operate on the Azure management plane — they don't affect data written inside the OS.
Why not D: Disk SKUs don't change on restart.
Exam tip: The temp disk is fast and cheap but non-persistent. Use it only for scratch data, swap, and temp files. Never for application data.
Q3
You deploy an App Service web app and need to use deployment slots to test a new version before promoting to production. Which App Service plan is the minimum required?
- A. Free (F1)
- B. Basic (B1)
- C. Standard (S1)
- D. Premium (P1v3)
Answer + Explanation
Correct: C — Standard (S1)
Why C: Deployment slots require Standard tier or above. Standard plans support up to 5 slots.
Why not A/B: Free and Basic plans support neither deployment slots nor autoscaling.
Why not D: Premium supports up to 30 slots and is a valid answer, but it is not the minimum — Standard is sufficient.
Exam tip: Standard tier unlocks: deployment slots, autoscale, custom domains with TLS, daily backups. Memorize this tier as the "production-ready" minimum for App Service.
Q4
You need to deploy infrastructure using a repeatable, version-controlled approach. You write an ARM template. Before deploying to production, you want to preview the exact changes the template will make without actually deploying anything.
Which command should you run?
- A.
az deployment group validate - B.
az deployment group create --dry-run - C.
az deployment group what-if - D.
az deployment group preview
Answer + Explanation
Correct: C — az deployment group what-if
Why C: The what-if command shows exactly which resources will be created, modified, or deleted — a pre-deployment preview with color-coded output. No actual changes are made.
Why not A: validate only checks the template for syntax and basic structural errors — it does not compare against existing resources to show delta changes.
Why not B: --dry-run is not a valid flag for az deployment group create.
Why not D: preview is not a valid subcommand.
Exam tip: Know these three commands and their purpose:
validate= syntax/schema checkwhat-if= preview changes vs current statecreate= actually deploy
Q5
You have an Azure VM Scale Set configured with an autoscale rule: scale out by 1 instance when CPU > 75% for 5 minutes. No scale-in rule is configured. What is the behavior over time?
- A. The scale set scales out and then automatically scales in when CPU drops
- B. The scale set scales out but never scales in — instances accumulate until the maximum is reached
- C. The scale set oscillates between min and max instances based on a default cooldown period
- D. The autoscale configuration is invalid without a scale-in rule and is ignored
Answer + Explanation
Correct: B — Without a scale-in rule, the scale set only grows
Why B: Autoscale rules are independent — scale-out and scale-in are separate rules you define. If you only define scale-out, the system adds instances when load is high but never removes them. Instances accumulate until the maximum count is reached.
Why not A: There is no default scale-in behavior. Azure does not assume you want to scale in at a symmetric CPU threshold.
Why not C: Cooldown periods control the frequency of scaling actions, not the direction.
Why not D: The configuration is valid — it just has no scale-in rule, which is a logical gap, not a configuration error.
Exam tip: Always configure autoscale in pairs — a scale-out rule and a corresponding scale-in rule with a lower threshold.
Q6
You deploy Azure Bastion in a VNet. The deployment fails with a validation error. Which is the most likely reason?
- A. The VNet does not have a public IP address
- B. The subnet is named
bastion-subnetinstead ofAzureBastionSubnet - C. The VNet uses a /24 address space, which is too small for Bastion
- D. Bastion requires an NSG on the target VMs' subnet to allow port 3389
Answer + Explanation
Correct: B — Incorrect subnet name
Why B: Azure Bastion requires the subnet to be named exactly AzureBastionSubnet — case-sensitive, no spaces, no variations. Any other name causes immediate validation failure at deployment time.
Why not A: Bastion itself gets the public IP (Standard SKU required on the Bastion resource) — the VNet doesn't need a public IP. VMs behind Bastion specifically do NOT need public IPs.
Why not C: The /24 VNet isn't the issue — Bastion's dedicated subnet needs a minimum /26 CIDR, but the VNet size is separate.
Why not D: Bastion connects to VMs over their private IPs — NSG on the VM subnet is not required (Bastion handles the RDP/SSH termination). Though good practice, it's not a deployment blocker.
Q7
You have a VM Scale Set (VMSS) running in Uniform orchestration mode. You need to update the OS image used by all instances. What happens to existing instances when you change the image and apply the update?
- A. Existing instances are immediately deleted and recreated with the new image
- B. The update is staged across Update Domains — instances are updated in rolling batches without all going down simultaneously
- C. Only new instances created after the change use the new image; existing instances keep the old image
- D. The image update fails — Uniform VMSS does not support image updates
Answer + Explanation
Correct: B — Rolling update across Update Domains
Why B: VMSS supports rolling upgrade policies. In rolling mode, instances are updated in batches (by Update Domain) to maintain availability. In automatic mode, all instances are updated as quickly as possible. In manual mode, you control when each instance is updated using az vmss update-instances.
Why not A: Immediate deletion of all instances would cause downtime — that's the "Automatic" upgrade policy with no batching configured.
Why not C: Image changes apply to all instances based on the upgrade policy — they don't only affect new instances (that would be a new VM from a different image, not a scale set image update).
Why not D: VMSS fully supports image updates.
Exam tip: Know the three VMSS upgrade policies: Automatic (fast, less control), Rolling (batched, maintains availability), Manual (you control timing per instance).
Q8 — Scenario
Your company runs a batch processing application that processes financial data overnight. The processing takes 2–3 hours and then the app shuts down until the next night. The team wants to containerize the app and run it in Azure. Cost optimization is the top priority — paying for idle capacity is unacceptable.
Which compute service is most appropriate?
- A. Azure Kubernetes Service (AKS)
- B. Azure Virtual Machine Scale Set
- C. Azure Container Instances (ACI)
- D. Azure App Service with autoscale to zero
Answer + Explanation
Correct: C — Azure Container Instances (ACI)
Why C: ACI bills per second of CPU and memory consumed. When the container finishes and stops, billing stops completely. No cluster to pay for, no idle VMs. For a short-lived, scheduled container workload with no need for orchestration, ACI is the most cost-effective choice.
Why not A: AKS requires a node pool running continuously (you pay for the VMs in the node pool even when no pods are scheduled). Unless you configure virtual nodes (ACI integration), there's always idle cost.
Why not B: VMSS always has a minimum instance count incurring cost, even in autoscale configurations.
Why not D: App Service "scale to zero" is available only on Consumption and Elastic Premium App Service plans, not standard App Service. Also, App Service is optimized for web apps, not batch container workloads.
Domain 4: Implement and Manage Virtual Networking
Exam weight: 15–20%
Networking is the trickiest domain in AZ-104. The concepts are interconnected — getting one wrong (e.g., NSG vs UDR) cascades into wrong answers on multiple questions. Master the flow of traffic through Azure's network stack.
4.1 Virtual Networks (VNets)
A VNet is Azure's isolated network environment — the foundation of all Azure networking.
Key Rules
- VNet address space uses CIDR notation (e.g.,
10.0.0.0/16). - A VNet lives in one region and one subscription.
- Subnets partition the VNet. Each subnet must fall within the VNet's address space.
- Azure reserves 5 IPs in every subnet:
.0(network),.1(default gateway),.2and.3(Azure DNS),.255(broadcast). - For a
/28subnet (16 addresses), you only get 11 usable host IPs.
Subnet Planning
| VNet CIDR | Max hosts (approx) |
|---|---|
| /16 | 65,531 usable |
| /24 | 251 usable |
| /27 | 27 usable |
| /28 | 11 usable |
| /29 | 3 usable (minimum practical) |
4.2 Network Security Groups (NSGs)
An NSG is a stateful packet filter — the primary traffic control mechanism in Azure.
How Rules Work
| Field | Values |
|---|---|
| Priority | 100–4096 — lower number = evaluated first |
| Source/Dest | IP, CIDR, service tag, or ASG |
| Protocol | TCP, UDP, ICMP, * (any) |
| Port | Specific port, range (80-443), or * |
| Action | Allow or Deny |
Default (always-present) Rules
Inbound defaults:
| Priority | Name | Effect |
|---|---|---|
| 65000 | AllowVnetInBound | Allow VNet-to-VNet |
| 65001 | AllowAzureLoadBalancerInBound | Allow LB health probes |
| 65500 | DenyAllInBound | Deny everything else |
Outbound defaults:
| Priority | Name | Effect |
|---|---|---|
| 65000 | AllowVnetOutBound | Allow VNet-to-VNet |
| 65001 | AllowInternetOutBound | Allow internet outbound |
| 65500 | DenyAllOutBound | Deny everything else |
Exam trap: NSGs are stateful — if you allow inbound traffic on port 80, the return traffic is automatically allowed without a matching outbound rule.
NSG Attachment Points
An NSG can be associated with:
- A subnet — applies to all resources in the subnet
- A NIC — applies only to that specific VM's network interface
When associated to both, both NSGs are evaluated. For inbound: subnet NSG first, then NIC NSG. For outbound: NIC NSG first, then subnet NSG.
Exam trap: If a VM can't reach a destination, check both the subnet NSG and the NIC NSG. Both must allow the traffic.
Application Security Groups (ASGs)
ASGs are logical groupings of VMs that can be used as source/destination in NSG rules. Instead of IP-based rules, use ASG-based rules:
NSG Rule: Allow AppServers → DBServers on port 1433
This lets you add new app servers to the AppServers ASG without touching the NSG rules.
4.3 VNet Peering
VNet Peering connects two VNets — traffic flows over Microsoft's backbone network (private, low latency, not internet).
Key Characteristics
- Non-transitive by default. If VNet A is peered with B, and B is peered with C, then A cannot reach C directly. You need an explicit A↔C peering, or a transit hub with forwarding enabled.
- Peering is directional — you create two peering connections (A→B and B→A). The portal/CLI creates both automatically.
- Global peering: Peering across regions is supported.
- Address spaces cannot overlap.
Peering Settings
| Setting | Effect |
|---|---|
allowVirtualNetworkAccess | Allow traffic between VNets (default: true) |
allowForwardedTraffic | Allow traffic forwarded from outside the source VNet |
allowGatewayTransit | Allow this VNet to share its VPN Gateway with the peer |
useRemoteGateways | Use the peer's VPN Gateway (requires allowGatewayTransit on peer) |
Exam trap: For a hub-spoke topology where spokes share the hub's VPN Gateway: enable
allowGatewayTransiton the hub peering, anduseRemoteGatewayson the spoke peering. If these are reversed, transit doesn't work.
4.4 VPN Gateway
A VPN Gateway connects your Azure VNet to on-premises networks or other VNets over encrypted IPsec/IKE tunnels.
Connection Types
| Type | Connects | Use case |
|---|---|---|
| Site-to-Site (S2S) | Azure VNet ↔ on-premises VPN device | Persistent on-prem connectivity |
| Point-to-Site (P2S) | Azure VNet ↔ individual client devices | Remote workers VPN |
| VNet-to-VNet | Azure VNet ↔ Azure VNet (cross-region) | Alternative to peering |
VPN Gateway SKUs
| SKU | Max throughput | Active-Active | BGP |
|---|---|---|---|
| Basic | 100 Mbps | No | No |
| VpnGw1 | 650 Mbps | Yes | Yes |
| VpnGw2 | 1 Gbps | Yes | Yes |
| VpnGw3 | 1.25 Gbps | Yes | Yes |
Exam trap: VPN Gateway requires a dedicated GatewaySubnet (named exactly
GatewaySubnet, /27 minimum recommended).
Route-Based vs Policy-Based VPN
| Type | Routing | IKE version | Use case |
|---|---|---|---|
| Route-based | Dynamic routing tables | IKEv1 + IKEv2 | Most scenarios; required for P2S, active-active |
| Policy-based | Static policies (traffic selectors) | IKEv1 only | Legacy on-prem devices; limited scenarios |
Exam tip: When in doubt, choose route-based. Policy-based is only needed for compatibility with very old VPN devices.
4.5 ExpressRoute
ExpressRoute provides a private, dedicated connection from on-premises to Azure — not over the internet.
| Feature | VPN Gateway | ExpressRoute |
|---|---|---|
| Path | Public internet (encrypted) | Private network (provider) |
| Bandwidth | Up to ~1.25 Gbps | Up to 100 Gbps |
| Latency | Variable (internet) | Low, consistent |
| SLA | 99.9% | 99.95% |
| Cost | Lower | Higher |
| Setup time | Hours | Weeks/months |
Exam tip: "Consistent low latency" or "dedicated private connection" = ExpressRoute. "Fast to set up" or "cost-effective" = VPN Gateway.
ExpressRoute Peering Types
| Type | Connects to |
|---|---|
| Azure private peering | Azure VNet (VMs, internal services) |
| Microsoft peering | Microsoft 365 and Azure public services |
4.6 Azure DNS
Public DNS Zones
Host DNS records for internet-facing domains. Authoritative name servers are on Azure's global anycast network.
# Create a public DNS zone
az network dns zone create \
--resource-group rg-net \
--name contoso.com
# Add an A record
az network dns record-set a add-record \
--resource-group rg-net \
--zone-name contoso.com \
--record-set-name "www" \
--ipv4-address "203.0.113.1"
Private DNS Zones
Resolve private hostnames within VNets. VMs get automatic DNS records when auto-registration is enabled.
# Create a private DNS zone
az network private-dns zone create \
--resource-group rg-net \
--name "internal.contoso.com"
# Link it to a VNet (with auto-registration)
az network private-dns link vnet create \
--resource-group rg-net \
--zone-name "internal.contoso.com" \
--name "link-to-prod-vnet" \
--virtual-network "/subscriptions/.../virtualNetworks/prod-vnet" \
--registration-enabled true
Exam trap: Azure DNS (public) does not support
DNSSECsigning (as of AZ-104 curriculum). Private DNS zones must be linked to a VNet to be resolvable from within that VNet.
4.7 Load Balancer
Azure Load Balancer operates at Layer 4 (TCP/UDP) — it doesn't inspect HTTP content.
SKU Comparison
| Feature | Basic | Standard |
|---|---|---|
| Backend pool | Availability set or single VNet | Any VMs in a VNet |
| Health probes | HTTP, TCP | HTTP, HTTPS, TCP |
| Availability zones | No | Yes (zone-redundant) |
| SLA | None | 99.99% |
| NSG required | No | Yes — must explicitly allow traffic |
| Outbound rules | No | Yes |
Exam trap: Standard Load Balancer + NSG. With Standard LB, you must have an NSG on the backend subnet or NIC explicitly allowing the traffic. Without it, backend VMs are unreachable even if the LB is configured correctly. Basic LB doesn't require this.
Load Balancer Rules
- Load balancing rules: Distribute traffic across backend pool
- NAT rules: Map a specific port on the LB to a specific VM port (e.g., LB:50001 → VM1:22)
- Health probes: LB periodically checks backend VM health; removes unhealthy instances
4.8 Application Gateway
Application Gateway is a Layer 7 (HTTP/HTTPS) load balancer with WAF capabilities.
| Feature | Load Balancer | Application Gateway |
|---|---|---|
| Layer | L4 (TCP/UDP) | L7 (HTTP/HTTPS) |
| SSL offload | No | Yes |
| URL-based routing | No | Yes |
| WAF | No | Yes (WAF v2) |
| Cookie-based affinity | No | Yes |
| Autoscaling | No | Yes (v2 SKU) |
URL-Based Routing Example
/images/* → Backend Pool: image-servers
/api/* → Backend Pool: api-servers
/* → Backend Pool: web-servers
Exam tip: If a question involves routing different URL paths to different backends, WAF, or SSL termination → Application Gateway. If it's just TCP load balancing → Azure Load Balancer.
4.9 Route Tables (User-Defined Routes)
Route tables override Azure's default routing and direct traffic to a specific next hop.
Next Hop Types
| Next hop | Traffic goes to |
|---|---|
VirtualNetworkGateway | VPN/ER gateway |
VirtualNetwork | Within the VNet |
Internet | Direct to internet |
VirtualAppliance | Custom NVA (e.g., Azure Firewall, third-party) |
None | Drops the traffic (black hole) |
Common Pattern: Force Traffic Through Azure Firewall
Route: 0.0.0.0/0 → Next hop: VirtualAppliance → 10.0.1.4 (Firewall IP)
This forces all outbound traffic through the firewall for inspection.
Exam trap: UDR overrides BGP routes from VPN/ExpressRoute. If you have a route learned via BGP for
10.1.0.0/24but also a UDR for10.1.0.0/24, the UDR wins (more specific or explicitly defined routes take precedence).
NSG vs UDR — When to Use Which
| Tool | What it does |
|---|---|
| NSG | Allow/deny traffic based on source, dest, port, protocol |
| UDR | Redirect traffic to a different next hop |
They solve different problems. NSG is a filter; UDR is a redirect. They can be used together.
4.10 Private Endpoints vs Service Endpoints
Both provide private connectivity to Azure PaaS services — but they work differently.
| Feature | Service Endpoint | Private Endpoint |
|---|---|---|
| Network path | Traffic stays on Azure backbone but exits VNet | Stays entirely within VNet |
| Resource gets private IP | No — PaaS service still has public IP | Yes — private IP in your VNet |
| DNS resolution | Still resolves to public IP | Resolves to private IP |
| On-premises access | No (requires specific routing) | Yes — works over VPN/ER |
| Cost | Free | ~$7.30/month per endpoint |
Exam trap: Service endpoints don't give the PaaS service a private IP — traffic still goes to the public endpoint, just optimized routing. Only Private Endpoints give the service a private IP in your VNet and make it fully accessible over VPN/ExpressRoute.
Section Takeaways
| Topic | Key Point |
|---|---|
| NSG stateful | Return traffic allowed automatically — you don't need a return rule |
| NSG + NIC + subnet | Both evaluated — both must allow traffic |
| VNet peering | Non-transitive by default; no overlapping address spaces |
| Hub-spoke VPN transit | allowGatewayTransit on hub, useRemoteGateways on spoke |
| VPN Gateway subnet | Must be named exactly GatewaySubnet |
| Route-based vs policy VPN | Always prefer route-based |
| Standard LB + NSG | NSG must explicitly allow traffic on backend subnet |
| App Gateway | L7 — SSL termination, WAF, URL routing |
| UDR overrides BGP | UDR wins over BGP-learned routes |
| Private Endpoint | Gives PaaS a private IP — accessible over VPN/ER |
Confusing Points — Clarified
Q: Can I have both an NSG and a UDR on the same subnet? A: Yes. NSG filters traffic (allow/deny). UDR redirects traffic to a next hop. They operate independently and together — UDR first redirects, then NSG evaluates.
Q: What's the difference between a Load Balancer health probe and an NSG? A: An NSG is a security filter. A health probe is how the Load Balancer determines if a backend VM is healthy enough to receive traffic. A VM can be "healthy" per the probe but still have an NSG blocking traffic — these are independent.
Q: If VNet A peers with VNet B and VNet B peers with VNet C, can VNet A communicate with VNet C? A: Not by default — peering is non-transitive. Either create a direct A↔C peering or configure VNet B as a transit hub with Azure Firewall or NVA and enable forwarded traffic.
Q: Does VNet peering work across Azure regions? A: Yes — this is called global VNet peering. The SLA and characteristics are the same as regional peering.
Lab 04: VNet, NSG, VNet Peering, and Load Balancer
Estimated time: 60–90 minutes Difficulty: ⭐⭐⭐⭐☆ Environment: Azure free account — Azure CLI
Prerequisites
az account show --query "{name:name, id:id}" -o table
Lab Objectives
- Create two VNets and peer them
- Verify non-transitive peering behavior
- Configure NSG rules and test traffic filtering
- Deploy a Standard Load Balancer with two backend VMs
- Create a User-Defined Route to direct traffic through a next hop
- Test that UDR overrides default routing
Step 1: Create Resource Group and Two VNets
RG="rg-az104-lab04"
LOCATION="eastus"
az group create --name $RG --location $LOCATION
# VNet A — production
az network vnet create \
--resource-group $RG \
--name "vnet-prod" \
--address-prefix "10.1.0.0/16" \
--subnet-name "snet-web" \
--subnet-prefix "10.1.1.0/24"
# VNet B — shared services
az network vnet create \
--resource-group $RG \
--name "vnet-shared" \
--address-prefix "10.2.0.0/16" \
--subnet-name "snet-services" \
--subnet-prefix "10.2.1.0/24"
# VNet C — isolated (to test non-transitivity)
az network vnet create \
--resource-group $RG \
--name "vnet-isolated" \
--address-prefix "10.3.0.0/16" \
--subnet-name "snet-isolated" \
--subnet-prefix "10.3.1.0/24"
Step 2: Configure VNet Peering (A↔B and B↔C, but NOT A↔C)
# Peer vnet-prod ↔ vnet-shared (bidirectional)
az network vnet peering create \
--resource-group $RG \
--name "prod-to-shared" \
--vnet-name "vnet-prod" \
--remote-vnet "vnet-shared" \
--allow-vnet-access true \
--allow-forwarded-traffic true
az network vnet peering create \
--resource-group $RG \
--name "shared-to-prod" \
--vnet-name "vnet-shared" \
--remote-vnet "vnet-prod" \
--allow-vnet-access true \
--allow-forwarded-traffic true
# Peer vnet-shared ↔ vnet-isolated (bidirectional)
az network vnet peering create \
--resource-group $RG \
--name "shared-to-isolated" \
--vnet-name "vnet-shared" \
--remote-vnet "vnet-isolated" \
--allow-vnet-access true
az network vnet peering create \
--resource-group $RG \
--name "isolated-to-shared" \
--vnet-name "vnet-isolated" \
--remote-vnet "vnet-shared" \
--allow-vnet-access true
# Verify peering state
az network vnet peering list \
--resource-group $RG \
--vnet-name "vnet-shared" \
--query "[].{name:name, state:peeringState, remoteVnet:remoteVirtualNetwork.id}" \
-o table
VNet-prod can reach VNet-shared, and VNet-shared can reach VNet-isolated — but VNet-prod CANNOT reach VNet-isolated directly. This is non-transitivity. To allow A↔C, you must create an explicit A↔C peering.
Step 3: Create an NSG and Apply Rules
# Create NSG
az network nsg create \
--resource-group $RG \
--name "nsg-web"
# Allow HTTP (port 80) inbound from internet
az network nsg rule create \
--resource-group $RG \
--nsg-name "nsg-web" \
--name "Allow-HTTP" \
--priority 100 \
--direction Inbound \
--source-address-prefixes Internet \
--source-port-ranges "*" \
--destination-address-prefixes "*" \
--destination-port-ranges 80 \
--protocol Tcp \
--access Allow
# Allow SSH (port 22) from specific IP only
MY_IP=$(curl -s https://ifconfig.me)
az network nsg rule create \
--resource-group $RG \
--nsg-name "nsg-web" \
--name "Allow-SSH-MyIP" \
--priority 110 \
--direction Inbound \
--source-address-prefixes $MY_IP \
--source-port-ranges "*" \
--destination-address-prefixes "*" \
--destination-port-ranges 22 \
--protocol Tcp \
--access Allow
# Explicitly deny all other inbound (redundant with default, but good practice for visibility)
az network nsg rule create \
--resource-group $RG \
--nsg-name "nsg-web" \
--name "Deny-All-Inbound" \
--priority 4000 \
--direction Inbound \
--source-address-prefixes "*" \
--source-port-ranges "*" \
--destination-address-prefixes "*" \
--destination-port-ranges "*" \
--protocol "*" \
--access Deny
# Associate NSG with the web subnet
az network vnet subnet update \
--resource-group $RG \
--vnet-name "vnet-prod" \
--name "snet-web" \
--network-security-group "nsg-web"
# View effective rules
az network nsg show \
--resource-group $RG \
--name "nsg-web" \
--query "securityRules[].{name:name, priority:priority, direction:direction, access:access, port:destinationPortRange}" \
-o table
⚠️ Tricky spot: NSG rules are evaluated by priority — lowest number first. If you have Allow-HTTP at priority 100 and Deny-All at priority 90, HTTP will be denied because 90 < 100. Always ensure Allow rules have lower priority numbers than Deny rules for the same port.
Step 4: Deploy a Standard Load Balancer
# Create a public IP for the LB
az network public-ip create \
--resource-group $RG \
--name "pip-lb" \
--sku Standard \
--allocation-method Static \
--location $LOCATION
LB_PIP=$(az network public-ip show \
--resource-group $RG \
--name "pip-lb" \
--query ipAddress -o tsv)
echo "LB Public IP: $LB_PIP"
# Create the Standard Load Balancer
az network lb create \
--resource-group $RG \
--name "lb-web" \
--sku Standard \
--public-ip-address "pip-lb" \
--frontend-ip-name "fe-config" \
--backend-pool-name "be-pool"
# Create health probe (HTTP on port 80)
az network lb probe create \
--resource-group $RG \
--lb-name "lb-web" \
--name "http-probe" \
--protocol Http \
--port 80 \
--path "/"
# Create load balancing rule
az network lb rule create \
--resource-group $RG \
--lb-name "lb-web" \
--name "http-rule" \
--protocol Tcp \
--frontend-port 80 \
--backend-port 80 \
--frontend-ip-name "fe-config" \
--backend-pool-name "be-pool" \
--probe-name "http-probe"
Create two backend VMs and add them to the pool:
for i in 1 2; do
# NIC for each VM
az network nic create \
--resource-group $RG \
--name "nic-web$i" \
--vnet-name "vnet-prod" \
--subnet "snet-web" \
--lb-name "lb-web" \
--lb-address-pool "be-pool"
# VM
az vm create \
--resource-group $RG \
--name "vm-web$i" \
--nics "nic-web$i" \
--image Ubuntu2204 \
--admin-username azureuser \
--admin-password "P@ssw0rd!Azure104" \
--size Standard_B1s \
--no-wait
done
echo "VMs deploying in background..."
⚠️ Critical tricky spot — Standard LB + NSG: Standard Load Balancer requires an NSG on the backend subnet that explicitly allows the load-balanced traffic. Without it, backend VMs are unreachable even with a perfectly configured LB. The
nsg-webwe created in Step 3 (Allow port 80) satisfies this requirement. Basic LB doesn't have this requirement.
Step 5: Create a User-Defined Route
Simulate forcing all outbound internet traffic through a "firewall" appliance (using a placeholder IP):
# Create a route table
az network route-table create \
--resource-group $RG \
--name "rt-web" \
--location $LOCATION \
--disable-bgp-route-propagation false
# Add a route: all internet traffic → virtual appliance (firewall)
# In a real scenario, this would be Azure Firewall's private IP
az network route-table route create \
--resource-group $RG \
--route-table-name "rt-web" \
--name "force-internet-to-fw" \
--address-prefix "0.0.0.0/0" \
--next-hop-type VirtualAppliance \
--next-hop-ip-address "10.1.99.4" # placeholder NVA IP
# Add a specific route: traffic to Azure Monitor bypass the firewall
az network route-table route create \
--resource-group $RG \
--route-table-name "rt-web" \
--name "azure-monitor-direct" \
--address-prefix "AzureMonitor" \
--next-hop-type Internet
# Associate the route table with the web subnet
az network vnet subnet update \
--resource-group $RG \
--vnet-name "vnet-prod" \
--name "snet-web" \
--route-table "rt-web"
# Verify effective routes on a VM's NIC
az network nic show-effective-route-table \
--resource-group $RG \
--name "nic-web1" \
-o table
⚠️ Tricky spot: With
--disable-bgp-route-propagation false, routes learned from a VPN/ExpressRoute gateway are added to the route table. With it set totrue, BGP routes are suppressed and only your UDRs apply. The UDR always wins over a BGP route for the same prefix.
Step 6: Clean Up
az group delete --name $RG --yes --no-wait
Lab Tricky Spots Summary
| Trap | Effect | Fix |
|---|---|---|
| NSG Allow rule priority higher than Deny rule for same port | Deny rule evaluated first — traffic blocked | Use lower priority numbers for Allow rules that should take precedence |
| Standard LB with no NSG on backend subnet | Backend VMs unreachable despite correct LB config | Create NSG with Allow rule for the load-balanced port on backend subnet |
VNet peering without allow-forwarded-traffic | Traffic from outside the VNet can't traverse the peer | Enable allowForwardedTraffic on both peering connections |
UDR next-hop-type VirtualAppliance with unreachable NVA | Traffic black-holes — all connectivity breaks | Test NVA reachability before associating UDR; ensure NVA has IP forwarding enabled |
| NSG on NIC AND subnet — forgetting both | Traffic blocked even though one NSG allows it | Check both NSG effective rules using az network nic show-effective-nsg |
Lab Takeaways
- VNet peering is non-transitive — always draw your topology before peering to identify missing direct links.
- Standard LB mandates NSG — the most common reason for "LB is configured but VMs are unreachable" in the exam.
- Effective routes view (
az network nic show-effective-route-table) is the fastest way to diagnose routing issues. - Effective NSG view (
az network nic show-effective-nsg) combines subnet + NIC NSG rules — use it to debug access issues. - UDR overrides BGP — be careful when adding
0.0.0.0/0routes if you have VPN connectivity you want to keep working.
Domain 4: Practice Q&A — Virtual Networking
Answer each question before expanding the solution. Aim for under 2 minutes per question.
Q1
You have three VNets: A, B, and C. VNet A is peered with VNet B. VNet B is peered with VNet C. A VM in VNet A tries to communicate with a VM in VNet C. The communication fails. What is the reason?
- A. Cross-VNet peering is not supported across more than one hop
- B. VNet peering is non-transitive — there is no direct peering between A and C
- C. VMs in different VNets can only communicate through a VPN Gateway
- D. The NSG on VNet C is blocking inbound traffic from VNet A's address space
Answer + Explanation
Correct: B — VNet peering is non-transitive
Why B: Peering only creates direct connectivity between the two peered VNets. A→B and B→C are separate peering relationships. There is no transitive route from A to C through B. To enable A↔C, you must either create a direct A↔C peering OR configure VNet B as a transit hub with an NVA/Azure Firewall and enable forwarded traffic.
Why not A: "Not supported across more than one hop" is a consequence of non-transitivity, not a product limitation you can work around with a feature.
Why not C: VMs in peered VNets communicate directly without a VPN Gateway. VPN is for on-premises connectivity or cross-region when peering isn't used.
Why not D: Possibly true but it's not the reason the question describes — the structural issue is the missing peering.
Q2
A subnet has an NSG associated with it and its VMs have NSGs associated with their NICs. Inbound traffic on port 443 is allowed in the subnet NSG but denied in the NIC NSG. What is the outcome?
- A. Traffic is allowed — subnet NSG is evaluated first and overrides NIC NSG
- B. Traffic is denied — both NSGs must allow traffic for inbound connections
- C. Traffic is allowed — NIC NSG takes precedence on inbound traffic
- D. The configuration is invalid — NSGs cannot be applied to both subnet and NIC simultaneously
Answer + Explanation
Correct: B — Both NSGs must allow traffic
Why B: For inbound traffic, the subnet NSG is evaluated first, then the NIC NSG. Traffic must pass both. If the NIC NSG denies port 443, the traffic is blocked — even though the subnet NSG allows it.
For outbound traffic, the order is reversed: NIC NSG first, then subnet NSG.
Why not A: Subnet NSG doesn't override NIC NSG — they are both enforced. The more restrictive combined result applies.
Why not C: NIC NSG doesn't take precedence on inbound — it's evaluated second, after the subnet NSG.
Why not D: This is a completely valid and common configuration (defense in depth).
Exam tip: Inbound = Subnet NSG → NIC NSG (both must allow). Outbound = NIC NSG → Subnet NSG (both must allow).
Q3
Your organization wants to connect its on-premises datacenter to Azure. The requirements are:
- Consistent sub-5ms latency
- 10 Gbps bandwidth
- Private connection — traffic must not traverse the public internet
Which solution meets all three requirements?
- A. Site-to-Site VPN Gateway (VpnGw3 SKU)
- B. Point-to-Site VPN
- C. Azure ExpressRoute
- D. VNet peering with BGP routing
Answer + Explanation
Correct: C — Azure ExpressRoute
Why C: ExpressRoute provides a dedicated private connection through a connectivity provider, with bandwidth options up to 100 Gbps, consistent low latency, and no traffic over the public internet. It's the only option that satisfies all three requirements simultaneously.
Why not A: VPN Gateway max is ~1.25 Gbps (VpnGw3). It also runs over the public internet (encrypted, but not private). It cannot guarantee sub-5ms latency.
Why not B: Point-to-Site is for individual client devices — not suitable for datacenter-level connectivity.
Why not D: VNet peering connects Azure VNets to each other — it doesn't extend to on-premises networks.
Q4
You have a Standard Azure Load Balancer with two VMs in the backend pool. The LB is correctly configured with a health probe and load balancing rule on port 80. Users report the VMs are unreachable through the LB public IP. What is the most likely cause?
- A. The health probe is checking the wrong port
- B. The backend VMs do not have NSGs allowing inbound traffic on port 80 from the Load Balancer
- C. Standard SKU public IPs cannot be used with Standard Load Balancers
- D. The Load Balancer SKU must match the VM SKU
Answer + Explanation
Correct: B — Standard LB requires NSG to allow traffic
Why B: Unlike Basic Load Balancer, Standard Load Balancer requires backend resources to have an NSG that explicitly allows the load-balanced traffic. By default, Standard LB backend VMs are not reachable unless an NSG allows inbound traffic from AzureLoadBalancer service tag or the specific frontend IP.
Why not A: Possible but not the most likely cause for a "correctly configured" LB scenario the question describes.
Why not C: Standard SKU public IPs are required for Standard Load Balancers — they are compatible, not incompatible.
Why not D: There is no such requirement.
Exam tip: Any question where a Standard LB is configured but VMs are unreachable → check NSG first. This is the #1 Standard LB exam trap.
Q5
You add a User-Defined Route (UDR) to a subnet with:
- Destination:
0.0.0.0/0 - Next hop type:
VirtualAppliance - Next hop IP:
10.0.99.4(Azure Firewall private IP)
A VPN Gateway is also connected to this VNet and advertises a route for 10.1.0.0/16 via BGP. What happens to traffic destined for 10.1.5.200?
- A. Traffic follows the BGP route to the VPN Gateway
- B. Traffic follows the UDR to the Azure Firewall because UDR overrides BGP
- C. Traffic is dropped — conflicting routes cause a routing loop
- D. Both routes are used in a round-robin fashion
Answer + Explanation
Correct: A — BGP route for 10.1.0.0/16 is more specific than the UDR for 0.0.0.0/0
Wait — this is a nuance question:
The UDR is 0.0.0.0/0 (default route — least specific). The BGP route is 10.1.0.0/16 (more specific). Azure routing uses longest prefix match — the more specific route wins. So traffic to 10.1.5.200 matches 10.1.0.0/16 (more specific) and follows the BGP route, not the default UDR.
If the UDR were also 10.1.0.0/16, then the UDR would win over BGP (same prefix, UDR takes precedence).
The key rule: Longest prefix match first. Among equal prefixes, UDR > BGP > system default.
Why not C: Azure doesn't create routing loops — it selects the best route.
Why not D: Azure routing is deterministic, not round-robin.
Exam tip: "UDR overrides BGP" is true only when they have the same prefix length (or UDR is more specific). If BGP has a more specific prefix, BGP wins via longest prefix match.
Q6
You need to allow VMs in a spoke VNet to use the hub VNet's VPN Gateway to connect to on-premises resources. What must you configure?
- A. Enable
allowGatewayTransiton the spoke-to-hub peering - B. Enable
allowGatewayTransiton the hub-to-spoke peering, anduseRemoteGatewayson the spoke-to-hub peering - C. Enable
useRemoteGatewayson both peering connections - D. Create a VPN Gateway in each spoke VNet
Answer + Explanation
Correct: B — allowGatewayTransit on hub side, useRemoteGateways on spoke side
Why B: The settings are:
- Hub-to-spoke peering: Enable
allowGatewayTransit— "I (the hub) allow traffic to transit through my gateway." - Spoke-to-hub peering: Enable
useRemoteGateways— "I (the spoke) want to use the hub's gateway instead of my own."
Both must be set correctly on their respective sides.
Why not A: allowGatewayTransit must be on the hub side (where the gateway lives), not the spoke side.
Why not C: useRemoteGateways only makes sense on the spoke side — setting it on the hub side means the hub would try to use the spoke's gateway (which doesn't exist).
Why not D: The entire point of gateway transit is to share one gateway across spokes — separate gateways defeat the purpose and cost significantly more.
Q7
You are designing private connectivity for an Azure SQL Database. You want the database to have a private IP address in your VNet and be inaccessible from the public internet, including from within Azure's public network.
Which solution should you use?
- A. Service endpoint for
Microsoft.Sql - B. Private endpoint for the SQL server
- C. VNet-integrated App Service connecting to Azure SQL
- D. Azure SQL Managed Instance
Answer + Explanation
Correct: B — Private endpoint
Why B: A Private Endpoint creates a private IP address in your VNet for the Azure SQL server. The DNS name resolves to the private IP. Public access can be completely disabled at the SQL server level. Traffic stays entirely within the VNet — even accessible over VPN/ExpressRoute from on-premises.
Why not A: Service endpoints keep traffic on the Azure backbone but the SQL server still has a public IP — traffic goes to the public endpoint, just with an optimized path. The SQL server is still publicly accessible from other Azure regions or the internet unless specifically firewalled.
Why not C: VNet integration allows the App Service to reach out to VNet resources, but it doesn't make the SQL server have a private IP — that's a different concern.
Why not D: Azure SQL Managed Instance is a different product (full SQL Server compatibility) — it does run within your VNet natively, but it's not the answer for making an existing Azure SQL Database private.
Q8
You configure an NSG inbound rule with priority 200, Allow, port 80. You also have the default DenyAllInBound rule at priority 65500. A VM's NIC has no separate NSG. Traffic on port 443 from the internet arrives at the VM. What happens?
- A. Traffic is allowed because the default
AllowVnetInBoundcovers it - B. Traffic is denied — the explicit Allow rule only covers port 80, and the default deny covers all other ports
- C. Traffic is allowed because there is no explicit deny rule for port 443
- D. Traffic is allowed because the NIC has no separate NSG
Answer + Explanation
Correct: B — Port 443 is denied by the default DenyAllInBound rule
Why B: The NSG has an explicit Allow for port 80 (priority 200). Traffic on port 443 doesn't match any allow rule, so it falls through to the default DenyAllInBound at priority 65500, which denies all unmatched inbound traffic.
Why not A: AllowVnetInBound only applies to traffic with source VirtualNetwork service tag (i.e., traffic from within the same VNet). Traffic from the internet is sourced from Internet, not VirtualNetwork.
Why not C: Not having an explicit Deny doesn't mean Allow. If no Allow rule matches, the default Deny catches it.
Why not D: The NIC having no separate NSG means only the subnet NSG applies. The subnet NSG still denies port 443.
Exam tip: NSG evaluation is: find the lowest priority matching rule, apply it. If no rule matches except the defaults, the default Deny catches all unmatched traffic. There is no "implicit allow" for any traffic from the internet.
Domain 5: Monitor and Maintain Azure Resources
Exam weight: 10–15%
This domain is about knowing that things are working, responding when they're not, backing up data, and planning for disaster recovery. It's more conceptual than the networking domain, but you'll see scenario questions comparing the tools.
5.1 Azure Monitor
Azure Monitor is the central hub for all monitoring in Azure. It collects metrics and logs from almost every Azure resource automatically.
Two Core Data Types
| Type | What it is | Default retention | Storage |
|---|---|---|---|
| Metrics | Numerical time-series data (CPU %, bytes/sec) | 93 days | Azure Monitor Metrics Store |
| Logs | Text/structured records of events | 30 days (configurable up to 730 days) | Log Analytics workspace (required) |
Exam trap: Metrics are stored by default for 93 days in Azure Monitor automatically — no workspace needed. Logs require a Log Analytics workspace and must be explicitly routed there via Diagnostic Settings.
Diagnostic Settings
Diagnostic settings control where resource telemetry flows. Every resource that supports monitoring lets you configure:
- Platform Metrics → Log Analytics workspace (for querying metrics with KQL)
- Resource Logs (e.g., Activity Logs, resource-specific logs) → Log Analytics workspace, Storage Account, Event Hub, or Partner solution
# Enable diagnostic settings: send activity log to a workspace
az monitor diagnostic-settings create \
--name "diag-vm-logs" \
--resource "/subscriptions/.../resourceGroups/rg/providers/Microsoft.Compute/virtualMachines/myvm" \
--workspace "/subscriptions/.../resourceGroups/rg/providers/Microsoft.OperationalInsights/workspaces/my-workspace" \
--logs '[{"category": "Administrative", "enabled": true}]' \
--metrics '[{"category": "AllMetrics", "enabled": true}]'
5.2 Log Analytics
Log Analytics is the query engine for Azure Monitor logs. Queries use KQL (Kusto Query Language).
Creating a Workspace
az monitor log-analytics workspace create \
--resource-group rg-monitor \
--workspace-name "law-prod" \
--location eastus \
--retention-time 90
Essential KQL Patterns
// Count errors in the last hour
AzureActivity
| where TimeGenerated > ago(1h)
| where ActivityStatusValue == "Failed"
| summarize count() by OperationNameValue
// Top 10 VMs by CPU
Perf
| where ObjectName == "Processor" and CounterName == "% Processor Time"
| where TimeGenerated > ago(30m)
| summarize avg(CounterValue) by Computer
| top 10 by avg_CounterValue desc
// Storage account write errors
StorageBlobLogs
| where StatusCode >= 400
| project TimeGenerated, OperationName, StatusCode, Uri
Key KQL Operators (exam-relevant)
| Operator | What it does |
|---|---|
where | Filter rows |
summarize | Aggregate (count, avg, sum, max) |
project | Select specific columns |
order by / sort by | Sort results |
top N by | Return top N rows |
extend | Add computed column |
join | Join two tables |
ago() | Time relative to now (ago(1h), ago(7d)) |
5.3 Alerts
Alerts notify you (or trigger automated actions) when specific conditions are met.
Alert Rule Components
| Component | Description |
|---|---|
| Scope | Which resource(s) to monitor |
| Condition | Signal + threshold (e.g., CPU > 90%) |
| Action group | Who/what gets notified |
| Alert rule | Brings scope + condition + action group together |
Alert Signal Types
| Signal type | Source | Example |
|---|---|---|
| Metric | Real-time numeric value | CPU > 80% for 5 min |
| Log query | KQL query result | Count of errors > 10 in 15 min |
| Activity log | Azure control-plane operations | VM deallocated, resource deleted |
| Resource health | Azure-side platform issues | VM unavailable |
| Service health | Azure-wide incidents/maintenance | Region outage |
Exam tip: "Notify me when someone deletes a resource group" = Activity log alert. "Notify me when CPU exceeds 90%" = Metric alert. "Notify me when more than 5 failed logins appear in logs" = Log query alert.
Action Groups
Action groups define what happens when an alert fires:
| Action type | Use case |
|---|---|
| Email/SMS | Notify an on-call engineer |
| Azure Function | Run custom logic/automation |
| Logic App | Complex automated workflows |
| Webhook | Integrate with third-party systems (PagerDuty, Slack) |
| ITSM | Create an incident in ServiceNow |
| Automation Runbook | Execute an Azure Automation runbook |
# Create an action group
az monitor action-group create \
--resource-group rg-monitor \
--name "ag-ops-team" \
--short-name "ops" \
--action email oncall oncall@contoso.com
# Create a metric alert
az monitor metrics alert create \
--name "alert-high-cpu" \
--resource-group rg-monitor \
--scopes "/subscriptions/.../resourceGroups/rg/providers/Microsoft.Compute/virtualMachines/myvm" \
--condition "avg Percentage CPU > 90" \
--window-size 5m \
--evaluation-frequency 1m \
--action "/subscriptions/.../resourceGroups/rg-monitor/providers/microsoft.insights/actionGroups/ag-ops-team" \
--severity 2
5.4 Azure Backup
Azure Backup is Microsoft's managed backup service. It protects VMs, SQL databases, Azure Files, blobs, and more.
Recovery Services Vault
The Recovery Services Vault is the central container for backup data and backup policies. It's required for VM backup and Azure Site Recovery.
Exam trap: There is also a Backup vault (newer) — used specifically for Azure Disk backup, Azure Database for PostgreSQL, and Azure Blob backup. Recovery Services Vault is used for VM backup and ASR.
VM Backup
- Backup is crash-consistent by default; for VMs running SQL or VSS-aware apps, it can be application-consistent.
- Backup policy defines frequency (daily) and retention (daily, weekly, monthly, yearly).
- Soft delete: Deleted backup data is retained for 14 additional days (default; configurable). This prevents accidental data loss.
# Enable backup on a VM (vault must exist)
az backup protection enable-for-vm \
--vault-name "rsv-prod" \
--resource-group rg-backup \
--vm "/subscriptions/.../resourceGroups/rg/providers/Microsoft.Compute/virtualMachines/myvm" \
--policy-name "DefaultPolicy"
# List backup items
az backup item list \
--vault-name "rsv-prod" \
--resource-group rg-backup \
--backup-management-type AzureIaasVM \
-o table
# Trigger an on-demand backup
az backup protection backup-now \
--vault-name "rsv-prod" \
--resource-group rg-backup \
--item-name "vm;iaasvmcontainer;rg;myvm" \
--container-name "iaasvmcontainer;iaasvmcontainerv2;rg;myvm" \
--backup-management-type AzureIaasVM \
--retain-until "31-12-2025"
Restore Options
| Option | Description |
|---|---|
| Create new VM | Restore full VM from a recovery point |
| Replace existing disk | Replace OS or data disk on an existing VM |
| Restore files | Mount the recovery point as a drive and copy individual files |
5.5 Azure Site Recovery (ASR)
Azure Site Recovery provides disaster recovery (DR) — it replicates VMs continuously to a secondary region. In the event of a regional outage, you can fail over to the replicated VMs.
Key Concepts
| Term | Definition |
|---|---|
| RPO (Recovery Point Objective) | How much data you can afford to lose (e.g., 15 minutes of data) |
| RTO (Recovery Time Objective) | How long you can be offline before failover completes |
| Replication | Continuous block-level replication of VM disks to the target region |
| Test failover | Validates DR without affecting production (spins up in isolated network) |
| Failover | Activates the DR environment as production |
| Failback | Replicates back to primary region and shifts production back |
ASR RPO
ASR replicates continuously and maintains recovery points. Default RPO is 15 minutes (crash-consistent) or up to 4 hours (app-consistent, configurable).
Exam trap: Backup and ASR serve different purposes:
- Azure Backup = protect against accidental deletion, data corruption, ransomware
- ASR = protect against regional outage, datacenter failure (DR scenario)
5.6 Azure Update Manager
Azure Update Manager (formerly Update Management Center) manages OS updates across Azure VMs and Arc-connected on-premises servers.
- Provides a unified view of update compliance across all machines
- Supports scheduled assessment and scheduled patching
- Maintenance windows control when updates are applied
- Works without a Log Analytics agent (uses Azure VM extension)
5.7 Azure Advisor
Azure Advisor analyzes your Azure usage and provides personalized recommendations across five categories:
| Category | Examples |
|---|---|
| Cost | Right-size underutilized VMs, delete unused resources |
| Security | Enable MFA, apply security patches |
| Reliability | Add availability zones, configure backups |
| Operational Excellence | Enable diagnostics, follow best practices |
| Performance | Upgrade VM disks, increase throughput |
Exam tip: Advisor is read-only and advisory — it doesn't make changes. It surfaces recommendations; you act on them.
Section Takeaways
| Topic | Key Point |
|---|---|
| Metrics | 93-day default retention; no workspace needed |
| Logs | Require Log Analytics workspace; 30-day default |
| Diagnostic settings | Route logs and metrics to workspace, storage, Event Hub |
| Activity log alert | When Azure management actions trigger notifications |
| Metric alert | When numeric threshold is crossed |
| Log query alert | When KQL query result meets a condition |
| Recovery Services Vault | Required for VM backup and ASR |
| Backup vault | Used for Disk backup, PostgreSQL, Blob backup |
| ASR RPO | Default 15 minutes (crash-consistent) |
| Soft delete | Deleted backup data retained 14 days |
| Backup vs ASR | Backup = data protection; ASR = regional DR |
Confusing Points — Clarified
Q: What's the difference between Backup vault and Recovery Services vault? A: Recovery Services vault is the original (VM backup, SQL backup, ASR). Backup vault is newer and used for a specific set of newer workloads (Azure Disk backup, Blobs, PostgreSQL). For the AZ-104 exam, Recovery Services vault is what you configure for VM backup and ASR.
Q: Can I query metrics data with KQL?
A: Yes, but you need to first route platform metrics to a Log Analytics workspace via Diagnostic Settings. Once there, you query the Perf table (VM metrics) or the AzureMetrics table. By default, metrics are only in the Metrics Store (queryable via Metrics Explorer, not Log Analytics).
Q: What's the difference between Test Failover and Failover in ASR? A: Test Failover spins up the replicated VM in an isolated virtual network — production is not affected, replication continues. Failover is the real event — production shifts to the DR site. Always test before a real event.
Q: Does Azure Backup require internet connectivity from the VM? A: Azure Backup uses the Azure Backup extension inside the VM and sends backup data to the Recovery Services Vault. By default, this requires internet access (or service endpoints/private endpoints for the vault). You can configure private endpoints for the vault to eliminate internet traffic.
Lab 05: Azure Monitor, Alerts, Backup, and Log Analytics
Estimated time: 50–65 minutes Difficulty: ⭐⭐⭐☆☆ Environment: Azure free account — Azure CLI + portal
Prerequisites
az account show --query "{name:name, id:id}" -o table
Lab Objectives
- Create a Log Analytics workspace
- Enable diagnostic settings on a VM to stream logs and metrics
- Write and run KQL queries
- Create a metric alert with an email action group
- Configure VM backup in a Recovery Services vault
- Perform a file-level restore from a backup
Step 1: Create Resource Group and Supporting Resources
RG="rg-az104-lab05"
LOCATION="eastus"
az group create --name $RG --location $LOCATION
# Create Log Analytics Workspace
az monitor log-analytics workspace create \
--resource-group $RG \
--workspace-name "law-lab05" \
--location $LOCATION \
--retention-time 30
LAW_ID=$(az monitor log-analytics workspace show \
--resource-group $RG \
--workspace-name "law-lab05" \
--query id -o tsv)
echo "Log Analytics Workspace ID: $LAW_ID"
Step 2: Deploy a VM to Monitor
az vm create \
--resource-group $RG \
--name "vm-monitor" \
--image Ubuntu2204 \
--admin-username azureuser \
--admin-password "P@ssw0rd!Azure104" \
--size Standard_B2s \
--location $LOCATION
VM_ID=$(az vm show \
--resource-group $RG \
--name "vm-monitor" \
--query id -o tsv)
echo "VM ID: $VM_ID"
Step 3: Enable Diagnostic Settings
Route VM metrics and logs to the Log Analytics workspace:
az monitor diagnostic-settings create \
--name "diag-vm-to-law" \
--resource "$VM_ID" \
--workspace "$LAW_ID" \
--metrics '[{"category": "AllMetrics", "enabled": true, "retentionPolicy": {"enabled": false, "days": 0}}]'
Install the Azure Monitor Agent (AMA) on the VM to collect OS-level performance counters:
az vm extension set \
--resource-group $RG \
--vm-name "vm-monitor" \
--name AzureMonitorLinuxAgent \
--publisher Microsoft.Azure.Monitor \
--version 1.0 \
--enable-auto-upgrade true
⚠️ Tricky spot: Diagnostic Settings alone send Azure platform metrics (host-level CPU, network). To get OS-level metrics (memory, disk free space, custom app counters), you also need the Azure Monitor Agent installed inside the VM. These are separate data streams.
Step 4: Create an Action Group for Alerts
# Create an action group with email notification
az monitor action-group create \
--resource-group $RG \
--name "ag-lab05" \
--short-name "lab05" \
--action email "lab-admin" "your-email@example.com"
AG_ID=$(az monitor action-group show \
--resource-group $RG \
--name "ag-lab05" \
--query id -o tsv)
echo "Action Group ID: $AG_ID"
Step 5: Create Metric Alerts
# Alert: CPU > 85% for 5 minutes
az monitor metrics alert create \
--name "alert-high-cpu" \
--resource-group $RG \
--scopes "$VM_ID" \
--condition "avg Percentage CPU > 85" \
--window-size 5m \
--evaluation-frequency 1m \
--action "$AG_ID" \
--severity 2 \
--description "CPU exceeded 85% for 5 minutes"
# Alert: Available memory < 500 MB
az monitor metrics alert create \
--name "alert-low-memory" \
--resource-group $RG \
--scopes "$VM_ID" \
--condition "avg Available Memory Bytes < 524288000" \
--window-size 5m \
--evaluation-frequency 1m \
--action "$AG_ID" \
--severity 3 \
--description "Available memory below 500 MB"
# Verify alerts
az monitor metrics alert list \
--resource-group $RG \
--query "[].{name:name, severity:severity, condition:criteria.allOf[0].metricName}" \
-o table
⚠️ Tricky spot: Alert
--window-sizeis the evaluation window (how long the condition must be true).--evaluation-frequencyis how often Azure checks.window-size >= evaluation-frequencyis required. If frequency is 1m and window is 5m, Azure checks every 1 minute whether the 5-minute average exceeded the threshold.
Step 6: Create an Activity Log Alert
Activity log alerts fire on Azure management operations:
SUBSCRIPTION_ID=$(az account show --query id -o tsv)
# Alert when any VM in the subscription is deleted
az monitor activity-log alert create \
--name "alert-vm-deleted" \
--resource-group $RG \
--scope "/subscriptions/$SUBSCRIPTION_ID" \
--condition "category=Administrative and operationName=Microsoft.Compute/virtualMachines/delete and status=Succeeded" \
--action-group "$AG_ID" \
--description "Alert when a VM is deleted anywhere in the subscription"
⚠️ Tricky spot: Activity log alerts use scope at the subscription level (or RG level) — not the individual resource. Metric alerts scope to individual resources or resource groups.
Step 7: Query Logs with KQL
Wait 10–15 minutes for some activity data to flow into the workspace, then:
# Get the workspace name and resource group for portal KQL
echo "Open portal → Log Analytics Workspaces → law-lab05 → Logs"
Run these KQL queries in the Log Analytics workspace portal UI:
// Query 1: Recent Azure activity in this resource group
AzureActivity
| where TimeGenerated > ago(1h)
| where ResourceGroup == "rg-az104-lab05"
| project TimeGenerated, OperationNameValue, ActivityStatusValue, Caller
| order by TimeGenerated desc
// Query 2: Count operations by type
AzureActivity
| where TimeGenerated > ago(24h)
| summarize count() by OperationNameValue
| order by count_ desc
| top 10 by count_
// Query 3: VM heartbeat check
Heartbeat
| where TimeGenerated > ago(30m)
| summarize LastHeartbeat = max(TimeGenerated) by Computer
⚠️ Tricky spot: Data may take 5–10 minutes to appear in Log Analytics after enabling diagnostic settings. If queries return empty results, wait and retry.
Step 8: Configure VM Backup
# Create a Recovery Services Vault
az backup vault create \
--resource-group $RG \
--name "rsv-lab05" \
--location $LOCATION
# View available backup policies
az backup policy list \
--resource-group $RG \
--vault-name "rsv-lab05" \
--query "[].name" \
-o tsv
# Enable backup for the VM using DefaultPolicy
az backup protection enable-for-vm \
--resource-group $RG \
--vault-name "rsv-lab05" \
--vm "vm-monitor" \
--policy-name "DefaultPolicy"
# Trigger an immediate backup (don't wait for scheduled)
az backup protection backup-now \
--resource-group $RG \
--vault-name "rsv-lab05" \
--container-name "IaasVMContainer;iaasvmcontainerv2;rg-az104-lab05;vm-monitor" \
--item-name "VM;iaasvmcontainerv2;rg-az104-lab05;vm-monitor" \
--backup-management-type AzureIaasVM \
--retain-until "01-01-2026"
Wait for the backup job to complete:
# Monitor backup job status
az backup job list \
--resource-group $RG \
--vault-name "rsv-lab05" \
--query "[0].{jobId:name, status:properties.status, operation:properties.operation}" \
-o table
Step 9: List Recovery Points
# List available recovery points (run after backup completes)
az backup recoverypoint list \
--resource-group $RG \
--vault-name "rsv-lab05" \
--container-name "IaasVMContainer;iaasvmcontainerv2;rg-az104-lab05;vm-monitor" \
--item-name "VM;iaasvmcontainerv2;rg-az104-lab05;vm-monitor" \
--backup-management-type AzureIaasVM \
--query "[].{name:name, time:properties.recoveryPointTime, type:properties.recoveryPointType}" \
-o table
⚠️ Tricky spot: Container name and item name use semicolon-separated compound identifiers. The format is:
IaasVMContainer;iaasvmcontainerv2;<resource-group>;<vm-name>. Getting these wrong is the #1 reason backup CLI commands fail. You can get the exact values withaz backup item list.
Step 10: Clean Up
# Disable backup protection first (required before deleting vault)
az backup protection disable \
--resource-group $RG \
--vault-name "rsv-lab05" \
--container-name "IaasVMContainer;iaasvmcontainerv2;rg-az104-lab05;vm-monitor" \
--item-name "VM;iaasvmcontainerv2;rg-az104-lab05;vm-monitor" \
--backup-management-type AzureIaasVM \
--delete-backup-data true \
--yes
# Then delete resource group
az group delete --name $RG --yes --no-wait
⚠️ Tricky spot: You cannot delete a Recovery Services vault if it has active backup items or ASR replication. Always disable protection (with
--delete-backup-data true) before deleting the vault.
Lab Tricky Spots Summary
| Trap | Effect | Fix |
|---|---|---|
| Diagnostic Settings without AMA | Only host-level metrics; no OS metrics (memory, disk) | Install Azure Monitor Agent for full OS telemetry |
| Log data delay | KQL queries return empty immediately after setup | Wait 5–10 minutes for data ingestion |
window-size < evaluation-frequency | Alert creation fails | Set window-size ≥ evaluation-frequency |
| Wrong backup container/item name format | Backup CLI commands fail | Use az backup item list to get exact names |
| Deleting vault with active items | Vault deletion blocked | Disable protection with --delete-backup-data true first |
Lab Takeaways
- Azure Monitor has two data types — metrics (automatic, 93 days) and logs (require workspace, 30 days default). Know which one you're querying.
- Three alert types — metric (threshold on numeric value), log query (KQL result), activity log (Azure management operation). Match the right alert type to the scenario.
- Recovery Services vault is required for VM backup and ASR. The vault must be in the same region as the VM.
- Backup soft delete means deleted backup data persists for 14 days. You cannot delete the vault until all backup data is purged.
- Test your DR — ASR test failover and backup restore drills should be scheduled regularly, not just done once.
Domain 5: Practice Q&A — Monitor and Maintain
Answer each question before expanding the solution. Aim for under 2 minutes per question.
Q1
A VM's CPU percentage data is available in Azure Monitor's Metrics Explorer and shows data for the last 60 days. A security engineer wants to query this same metric data using KQL alongside log data. What must be done first?
- A. Nothing — CPU metric data is automatically available in Log Analytics
- B. Enable Diagnostic Settings on the VM to route platform metrics to a Log Analytics workspace
- C. Install the Azure Monitor Agent on the VM
- D. Create a custom metric namespace in Azure Monitor
Answer + Explanation
Correct: B — Enable Diagnostic Settings to route metrics to a Log Analytics workspace
Why B: Platform metrics (like CPU %) are automatically stored in the Azure Monitor Metrics Store for 93 days. However, to query them with KQL in Log Analytics, you must explicitly configure Diagnostic Settings on the resource to route metrics to a Log Analytics workspace. Once routed, they appear in the AzureMetrics table.
Why not A: Platform metrics are NOT automatically sent to Log Analytics — only to the Metrics Store.
Why not C: The Azure Monitor Agent collects OS-level metrics (memory, disk free space, custom app counters). It doesn't route platform metrics (which come from the Azure hypervisor, not inside the VM).
Why not D: Custom metric namespaces are for custom metrics emitted by applications — not for platform metrics.
Q2
Your team needs to receive an email when any resource in a specific resource group is deleted. Which alert type should you create?
- A. Metric alert scoped to the resource group
- B. Log query alert on the
AzureMetricstable - C. Activity log alert scoped to the resource group
- D. Resource health alert for the resource group
Answer + Explanation
Correct: C — Activity log alert
Why C: Deletion of a resource is an Azure management operation — it appears in the Activity Log (control-plane events). An activity log alert fires when a specific operation (e.g., write or delete) occurs within the scope. This is exactly what activity log alerts are designed for.
Why not A: Metric alerts monitor numeric thresholds (CPU, memory, bytes) — they don't fire on management operations.
Why not B: AzureMetrics contains resource metric data, not management operations. Deletion events appear in AzureActivity in Log Analytics.
Why not D: Resource health alerts fire when Azure detects the resource is degraded/unavailable from the platform side — not when a user deletes a resource.
Q3
You configure an Azure Backup policy for a VM with:
- Daily backups retained for 7 days
- Weekly backups retained for 4 weeks
A junior admin accidentally runs az backup protection disable --delete-backup-data true on the protected VM. What happens to the existing backup data?
- A. All backup data is immediately and permanently deleted
- B. Backup data is moved to soft-delete state and retained for 14 days before permanent deletion
- C. The backup policy prevents deletion — admin must have Backup Contributor role
- D. The vault retains the data according to the original retention policy (7 days daily, 4 weeks weekly)
Answer + Explanation
Correct: B — Soft delete retains data for 14 additional days
Why B: Azure Backup's soft delete feature (enabled by default on Recovery Services vaults) retains deleted backup data for 14 additional days after deletion. During this window, the data can be undeleted (restored back to active protection). After 14 days, it is permanently purged.
Why not A: Immediate permanent deletion only occurs if soft delete is explicitly disabled on the vault (and --delete-backup-data true is specified).
Why not C: The Backup Contributor role can disable protection. Soft delete is a vault-level safety net, not an RBAC restriction.
Why not D: The retention policy applies to scheduled backup points during active protection — it doesn't extend to backup data after protection is disabled.
Exam tip: Soft delete is a safeguard against ransomware and accidental deletion. Know that it's 14 days by default and that you can still undelete within that window.
Q4
You deploy a Standard Load Balancer with a backend pool of VMs. You want to alert your team if the Load Balancer's data path availability drops below 90% for more than 10 minutes. Which alert type is appropriate?
- A. Activity log alert
- B. Metric alert
- C. Log query alert
- D. Service health alert
Answer + Explanation
Correct: B — Metric alert
Why B: Data path availability is a numeric metric emitted by the Load Balancer to Azure Monitor. You create a metric alert with:
- Metric:
Data Path Availability - Condition:
< 90 - Window size:
10m - Aggregation:
average
Why not A: Activity log alerts fire on Azure management operations — not on runtime performance metrics.
Why not C: A log query alert is possible (route metrics to Log Analytics, then write a KQL query), but it's more complex and higher latency than a direct metric alert. For real-time threshold-based alerts on known metrics, metric alerts are the correct and simpler choice.
Why not D: Service health alerts notify you of Azure platform incidents and maintenance — not resource-specific metric thresholds.
Q5
You use Azure Site Recovery to replicate a VM from East US to West US. During a DR drill, you perform a test failover. What is true about the test failover?
- A. The production VM in East US is shut down and traffic shifts to West US
- B. Replication is paused during the test failover
- C. A new VM is started in West US in an isolated virtual network — production is not affected
- D. The test failover permanently fails over the VM — you must fail back manually to restore production
Answer + Explanation
Correct: C — Test failover starts a VM in an isolated VNet; production is unaffected
Why C: Test failover spins up the replicated VM in the target region using an isolated virtual network (no production network connectivity). This lets you validate that the replicated VM boots, applications start, and recovery is successful — without touching production. After the test, you "clean up test failover" to remove the test VM. Replication continues throughout.
Why not A: That describes an actual failover (planned or unplanned), not a test failover.
Why not B: Replication continues normally during a test failover — that's the point.
Why not D: Test failover is always temporary and isolated. Replication continues and you can run another test failover later.
Exam tip: Understand the four ASR operations: Test Failover (isolated, no production impact) → Planned Failover (graceful, coordinated) → Unplanned Failover (emergency) → Failback (return to primary).
Q6
A company has an RTO of 1 hour and an RPO of 15 minutes for a critical Azure VM. Which solution meets BOTH requirements?
- A. Azure Backup with daily backup policy
- B. Azure Site Recovery replicating to a secondary region
- C. Geo-redundant Storage for VM disks
- D. Availability Zones with Standard Load Balancer
Answer + Explanation
Correct: B — Azure Site Recovery
Why B: ASR provides:
- RPO of ~15 minutes (crash-consistent recovery points; ASR replicates continuously with recovery points every 15 minutes by default)
- RTO of < 1 hour (failover can complete in minutes for a pre-tested DR plan with automation)
Both requirements are satisfied.
Why not A: Azure Backup takes daily snapshots — the RPO is up to 24 hours, far exceeding the 15-minute requirement.
Why not C: GRS replicates storage data but doesn't provide VM-level failover automation. You can't "fail over" to GRS — you'd need to manually reconstruct the VM from the replicated disks in the secondary region.
Why not D: Availability zones protect against datacenter failure within the same region — they don't provide cross-region DR. If the entire region fails, AZ-protected VMs fail too.
Q7
Azure Advisor shows a recommendation to "Enable soft delete for your Recovery Services vault." Your vault already has soft delete enabled. Why might Advisor still show this recommendation?
- A. Advisor recommendations are cached and may lag up to 24 hours
- B. Advisor requires a Log Analytics workspace linked to the vault to detect the setting
- C. Soft delete was recently disabled and re-enabled — Advisor needs a manual refresh
- D. Advisor recommendations cannot be dismissed and always appear even when resolved
Answer + Explanation
Correct: A — Advisor recommendations may be cached/delayed up to 24 hours
Why A: Azure Advisor scans resources periodically and caches results. After you make a change, it can take up to 24 hours for the recommendation to disappear. You can also manually Dismiss or Postpone a recommendation in the Advisor portal.
Why not B: Advisor doesn't require Log Analytics to detect vault settings — it reads resource configuration directly.
Why not C: Re-enabling a setting doesn't require a manual refresh beyond the normal scan cycle.
Why not D: Advisor recommendations can be dismissed — there's a "Dismiss" option for each recommendation.
AZ-104 Mock Exam
40 questions — 150 minutes allowed
Simulate real exam conditions: no notes, no hints. Record your answers, then check explanations at the end.
Score guide: 32–40 = pass-ready | 26–31 = review weak domains | < 26 = more study needed
Instructions
- Answer all 40 questions without peeking at explanations
- Note your confidence level (certain / unsure / guessing) next to each answer
- Expand explanations after finishing all questions
Domain 1 — Identities & Governance (~7 questions)
Q1
Your organization uses Microsoft Entra ID. A contractor needs access to a specific Azure virtual machine for 30 days. You must follow the principle of least privilege. Which approach is most appropriate?
- A. Add the contractor to the Global Administrator Entra role
- B. Create a user account and assign the Virtual Machine Contributor RBAC role scoped to the VM's resource group
- C. Create a user account and assign the Owner RBAC role at the subscription scope
- D. Share the subscription admin credentials
Answer + Explanation
Correct: B
Virtual Machine Contributor scoped to the resource group grants the minimum permissions needed to work with the VM. Owner at subscription scope is excessive. Global Administrator is an Entra role with no Azure resource access. Sharing credentials violates accountability and least privilege.
Q2
You assign a Deny policy that prevents creation of public IP addresses in a resource group. A Contributor tries to deploy a VM with a public IP. What happens?
- A. The deployment succeeds because RBAC Contributor overrides Azure Policy
- B. The deployment fails with
RequestDisallowedByPolicy - C. The deployment succeeds but the public IP is automatically removed after creation
- D. The policy only applies to existing resources, not new deployments
Answer + Explanation
Correct: B
Azure Policy with Deny effect blocks non-compliant resource creation at the ARM layer — before the resource is created. RBAC and Policy are independent; Policy takes precedence for what is allowed. Deny effect prevents creation, unlike Audit which just logs.
Q3
A user needs to be able to assign Azure RBAC roles to other users in a resource group, but must NOT be able to modify or delete resources. Which built-in role satisfies this?
- A. Contributor
- B. Owner
- C. User Access Administrator
- D. Role Based Access Control Administrator
Answer + Explanation
Correct: D — Role Based Access Control Administrator
RBAC Administrator can manage role assignments but has no data-plane permissions (cannot modify resources). Owner can manage role assignments AND has full resource access (too broad). User Access Administrator also allows role assignment management but is the older equivalent — both D and C are valid for role assignment, but RBAC Administrator is more scoped. If both appear, prefer D as the more recently introduced least-privilege option.
Note: Some exam versions may accept C. Know both.
Q4
You apply a ReadOnly lock to an Azure storage account. A user with the Owner role tries to list the storage account access keys. What is the result?
- A. The keys are listed successfully — Owner overrides locks
- B. The operation fails — ReadOnly locks prevent
listKeysoperations - C. The keys are listed but not displayed to the user
- D. The lock must be removed by a Global Administrator first
Answer + Explanation
Correct: B
listKeys is classified as a write-equivalent operation (it modifies effective access). ReadOnly locks prevent all operations that aren't read-only, including listKeys. Locks override RBAC — even Owners are blocked. Only someone with management permissions over the lock (Owner or User Access Administrator) can remove the lock first.
Q5
You need to apply the same Azure Policy across all subscriptions in your organization, including subscriptions added in the future. What is the most scalable approach?
- A. Assign the policy to each subscription individually
- B. Use a script to assign the policy to new subscriptions when they're created
- C. Assign the policy at the Management Group scope
- D. Assign the policy at the tenant root subscription
Answer + Explanation
Correct: C
Management Groups provide a scope above subscriptions. Policies assigned at the management group level automatically apply to all current and future child subscriptions. This is the exam-standard answer for "apply consistently across all subscriptions."
Q6
You create a user-assigned managed identity and attach it to a VM. The VM is deleted and recreated. What happens to the managed identity?
- A. The managed identity is deleted with the VM
- B. The managed identity persists independently and can be attached to the new VM
- C. The managed identity must be recreated but retains its role assignments
- D. The managed identity is automatically transferred to the new VM
Answer + Explanation
Correct: B
User-assigned managed identities are standalone Azure resources — their lifecycle is independent of the VMs they're attached to. When the VM is deleted, the identity persists. You attach it to the new VM. System-assigned managed identities (the alternative) are tied to the VM's lifecycle and are deleted when the VM is deleted.
Q7
A Global Administrator assigns themselves the Contributor role on a subscription via Entra ID Privileged Identity Management. A colleague with only User Access Administrator on the subscription tries to remove this assignment. Will they succeed?
- A. Yes — User Access Administrator can remove any role assignment in scope
- B. No — only a Global Administrator can remove assignments made by another Global Administrator
- C. No — PIM-activated assignments can only be removed by the PIM service
- D. Yes — Contributor is a lower role than User Access Administrator, so UAA can remove it
Answer + Explanation
Correct: A
User Access Administrator (and Owner) can manage role assignments at their scope. The source of the assignment (PIM vs direct) doesn't restrict who can remove it — only RBAC scope matters. UAA at the subscription scope can remove any role assignment at or below that scope, regardless of who made it.
Domain 2 — Storage (~8 questions)
Q8
You have a GPv2 storage account with blobs in the Hot tier. You want to automatically move blobs to Cool tier after 30 days and Archive after 90 days. What should you configure?
- A. Storage account replication policy
- B. Lifecycle management policy
- C. Soft delete retention policy
- D. Access tier policy in Diagnostic Settings
Answer + Explanation
Correct: B
Lifecycle management policies define rules that automatically tier or delete blobs based on age (last modified or last accessed). You can configure: Cool at 30 days, Archive at 90 days, Delete at 365 days — all in one policy.
Q9
A user generates a Shared Access Signature (SAS) token with a 24-hour expiry directly from the storage account key. Two hours later, the security team realizes the SAS has been leaked. How should you revoke the SAS?
- A. Delete the SAS token from the storage account portal
- B. Rotate the storage account access key that was used to sign the SAS
- C. Enable soft delete on the storage account
- D. Change the storage account replication type to LRS
Answer + Explanation
Correct: B
An account-key-signed SAS cannot be individually revoked — it's just a cryptographic signature. To invalidate it, you must rotate the storage account key that was used to sign it. This invalidates ALL SAS tokens signed with that key. This is why SAS tokens linked to Stored Access Policies are preferred — you revoke by deleting the policy.
Q10
Your company stores compliance records in Azure Blob Storage. Regulations require that no one — not even storage administrators — can delete or modify records for 7 years. What feature should you configure?
- A. Soft delete with 7-year retention
- B. Resource lock (CanNotDelete) on the container
- C. WORM (Write Once, Read Many) immutability policy with time-based retention
- D. Storage account firewall to block all write operations
Answer + Explanation
Correct: C
WORM immutability policies (available as time-based retention policies or legal holds on containers) prevent modification or deletion of data for the retention period — immutable to everyone, including storage admins and subscription owners. Soft delete has a maximum retention of 365 days, not 7 years. Resource locks can be removed by Owners.
Q11
You have a storage account with GRS replication. The primary region fails. You want to read data from the secondary region immediately while failover is pending. What must be true?
- A. The storage account must use RA-GRS (Read-Access Geo-Redundant Storage)
- B. Any GRS storage account allows secondary read during primary failure
- C. The storage account must have geo-failover pre-configured
- D. You must contact Azure support to enable secondary access
Answer + Explanation
Correct: A
With standard GRS, the secondary region is only accessible after a failover completes. With RA-GRS, the secondary region has a read-only endpoint available at all times: <account>.secondary.blob.core.windows.net. If you need secondary reads without waiting for failover, RA-GRS is required.
Q12
A developer needs to access a specific blob in an Azure storage container without exposing the storage account key. The access should be valid for exactly 2 hours with read-only permissions. Which solution is most secure?
- A. Account SAS with read permission, 2-hour expiry, signed with account key
- B. User delegation SAS signed with Entra ID credentials, 2-hour expiry, read permission
- C. Service SAS for the specific blob, 2-hour expiry, signed with account key
- D. Share the container's anonymous access URL
Answer + Explanation
Correct: B
User delegation SAS is signed with Entra ID (Microsoft Entra) credentials rather than storage account keys — it doesn't expose the account key and is the most secure SAS option. It also supports Entra-based auditing. Account key-signed SAS (options A and C) work but are less secure because they require access to the account key.
Q13
An Azure blob is moved to the Archive tier. A developer immediately tries to read the blob. What happens?
- A. The read succeeds after a 1-second delay
- B. The blob is automatically rehydrated within 1 minute and then readable
- C. The read fails — Archive blobs are offline and must be rehydrated first (1–15 hours)
- D. Reading an archived blob is not possible — it must be deleted and re-uploaded
Answer + Explanation
Correct: C
Archive blobs are stored offline — they cannot be read directly. Rehydration is required first: either by changing the tier to Hot or Cool (1–15 hours for standard priority, up to 1 hour for high priority). Only after rehydration completes can the blob be read. Always factor this into DR or restore scenarios.
Q14
Which Azure Files protocol requires the client to use port 445 (outbound) to the storage account?
- A. NFS 4.1
- B. REST API
- C. SMB 3.x
- D. iSCSI
Answer + Explanation
Correct: C
SMB (Server Message Block) uses TCP port 445. Many ISPs and corporate firewalls block outbound port 445, which is the #1 reason Azure Files SMB mounting fails from on-premises or home networks. NFS uses port 2049. The storage REST API uses HTTPS (port 443).
Q15
A blob storage container has public anonymous access disabled. A developer generates a Service SAS with Read permission on the container. Another developer uses that SAS to try to upload (write) a new blob. What happens?
- A. The upload succeeds because the SAS provides access to the container
- B. The upload fails — the SAS only grants Read permission; Write is denied with 403
- C. The upload fails because public access is disabled
- D. The upload succeeds but the blob is marked as read-only
Answer + Explanation
Correct: B
SAS tokens are scoped to the permissions specified at creation time. A Read-only SAS only allows read operations — any write, delete, or list operation (if not included) returns 403 Forbidden. Public access being disabled doesn't affect SAS-authenticated operations.
Domain 3 — Compute (~10 questions)
Q16
You need to deploy 50 identical VMs that automatically scale based on CPU load. The VMs run a stateless web application. Which service is most appropriate?
- A. 50 individual VMs with Azure Autoscale
- B. Azure Virtual Machine Scale Set (VMSS)
- C. Azure Container Instances (ACI) with 50 containers
- D. Azure Kubernetes Service (AKS)
Answer + Explanation
Correct: B
VMSS is specifically designed for deploying and managing groups of identical VMs with autoscaling. It manages the lifecycle (create, update, delete) of instances automatically. Individual VMs with autoscale don't exist as a native Azure feature — you'd manage this yourself.
Q17
You deploy a VM in an Availability Set. A few months later, you want to move the VM to an Availability Zone for higher SLA. What must you do?
- A. Change the availability configuration in the VM settings
- B. Stop the VM and reassign it to an availability zone
- C. You cannot change availability configuration after VM creation — recreate the VM
- D. Detach the VM from the availability set, then assign it to a zone
Answer + Explanation
Correct: C
Availability set and zone membership are set at VM creation and cannot be changed afterward. You must delete the VM (keeping the disk), then recreate it with the new availability configuration. Availability sets and zones are also mutually exclusive.
Q18
An ARM template includes this expression:
"location": "[resourceGroup().location]"
What does this expression evaluate to?
- A. The location of the Azure subscription
- B. The location where the template is being deployed (the deployment command's
--location) - C. The Azure region of the resource group where the template is being deployed
- D. The default location configured in the user's Azure CLI profile
Answer + Explanation
Correct: C
resourceGroup().location returns the Azure region of the resource group into which the template is being deployed. This is the canonical way to ensure all resources in a template deploy to the same region as the resource group without hardcoding a region name.
Q19
You deploy an App Service web app on a Basic (B1) plan. The app traffic doubles and you need to scale out to 3 instances. What must you do?
- A. Enable autoscale on the Basic plan
- B. Scale the instance count manually from 1 to 3 on the Basic plan
- C. Upgrade the App Service plan to Standard or above, then enable autoscale
- D. Create two additional App Service plans and configure traffic splitting
Answer + Explanation
Correct: B
Basic plan supports manual scaling — you can set the instance count manually (1 to 3 instances for B1). What Basic does NOT support is autoscaling (automatic scale-out based on rules). For autoscale, you need Standard or above. The question says "scale out to 3 instances" — not autoscale — so Basic manual scaling works.
Careful: If the question says "automatically scale," the answer is C. Here it says "scale out to 3 instances," which Basic can do manually.
Q20
A VM that runs SQL Server needs the highest possible disk IOPS with low latency. You don't need zone redundancy. Which managed disk SKU should you choose?
- A. Standard HDD
- B. Standard SSD
- C. Premium SSD v2
- D. Ultra Disk
Answer + Explanation
Correct: D — Ultra Disk
Ultra Disk provides up to 160,000 IOPS and sub-millisecond latency — the highest performance tier. Ultra Disk is locked to a single zone (not zone-redundant), but the question states zone redundancy is not required. Premium SSD v2 is high-performance but Ultra exceeds it.
Note: If the question adds zone redundancy as a requirement, Premium SSD (zone-redundant) would be the answer.
Q21
You are deploying Azure Bastion and encounter a deployment validation error. The VNet has a subnet named AzureBastion with a /26 prefix. What is causing the error?
- A. The subnet prefix is too small — Bastion requires a /25
- B. The subnet must be named exactly
AzureBastionSubnet— the nameAzureBastionis invalid - C. Bastion requires an NSG on the dedicated subnet
- D. The VNet must have at least 3 subnets for Bastion to deploy
Answer + Explanation
Correct: B
Azure Bastion requires the subnet to be named exactly AzureBastionSubnet — case-sensitive. AzureBastion (missing "Subnet") fails validation immediately. The /26 prefix meets the minimum size requirement.
Q22
A development team wants to run a containerized data pipeline job. The job runs for 2–3 hours nightly and then terminates. They want zero idle cost when the job isn't running. Which compute option best fits?
- A. Azure Kubernetes Service with one node pool (1 node)
- B. Azure App Service on a Basic plan
- C. Azure Container Instances (ACI)
- D. Azure VM with Docker installed
Answer + Explanation
Correct: C
ACI bills per second of actual execution. When the container stops, billing stops entirely — zero idle cost. AKS requires a node pool (VMs) that incur cost even when idle. App Service has an always-on minimum cost. A VM costs as long as it's running.
Q23
You deploy an ARM template with what-if and see a resource listed as ~ Modify. What does this indicate?
- A. The resource will be deleted and recreated with a new configuration
- B. The resource will be updated in place with new property values
- C. The resource has conflicting configurations that must be resolved before deployment
- D. The resource is outside the template scope and will not be affected
Answer + Explanation
Correct: B
what-if output symbols:
+ Create— resource doesn't exist and will be created~ Modify— resource exists and will be updated in place- Delete— resource exists but is not in the template (Complete mode)= Nochange— no changes× Unsupported— Azure can't determine the effect
Q24
You configure a VMSS autoscale rule: scale in by 2 instances when CPU < 20% for 10 minutes. The current instance count is 4 (minimum is 2). After 10 minutes of < 20% CPU, how many instances remain?
- A. 2 — scale in by 2, hitting the minimum
- B. 3 — scale in by 1 (can't go below minimum, so only removes 1)
- C. 4 — scale-in rules only fire once per hour
- D. 2 — scale in removes all instances below the average threshold
Answer + Explanation
Correct: A
The rule says scale in by 2. Current count is 4, minimum is 2. After scale-in: 4 - 2 = 2. This equals the minimum, so the action is valid and completes. If scale in by 2 would go below the minimum (e.g., current = 3, min = 2, scale-in by 2), Azure caps the result at the minimum.
Q25
Which statement about system-assigned vs user-assigned managed identities is correct?
- A. System-assigned identities can be shared across multiple VMs
- B. User-assigned identities are deleted when the associated VM is deleted
- C. User-assigned identities have a lifecycle independent of the resource they're attached to
- D. System-assigned identities can be assigned custom RBAC roles but user-assigned cannot
Answer + Explanation
Correct: C
User-assigned managed identities are standalone Azure resources — you create them independently and attach to one or more resources. They survive VM deletion. System-assigned identities are enabled directly on a resource and are deleted when that resource is deleted. Both types can be assigned RBAC roles.
Domain 4 — Networking (~9 questions)
Q26
Two VMs in the same VNet (different subnets) cannot communicate. Which is the most likely cause?
- A. VMs in different subnets cannot communicate by default
- B. A Network Security Group rule is blocking the traffic
- C. The subnets are in different availability zones
- D. VNet routing requires VPN Gateway for intra-VNet traffic
Answer + Explanation
Correct: B
By default, Azure routes traffic between subnets within the same VNet automatically. VMs in different subnets CAN communicate by default unless an NSG explicitly blocks it. Availability zones don't affect routing. VPN is for external connectivity.
Q27
You need to allow traffic on port 443 from a specific application server group to a database group, regardless of IP addresses, so that you don't have to update NSG rules when IPs change. What should you use?
- A. Service Tags
- B. Application Security Groups (ASGs)
- C. Custom route tables
- D. Private Link Service
Answer + Explanation
Correct: B
ASGs let you group VMs by logical role (e.g., AppServers, DBServers) and reference them in NSG rules. When a VM's IP changes or a new VM is added to the group, no NSG rule changes are needed — the logical group handles it. Service Tags represent Azure services, not your own VM groups.
Q28
You create a VNet-to-VNet connection between VNet-East (East US) and VNet-West (West US) using VPN Gateway. What type of VPN should you use?
- A. Policy-based VPN
- B. Route-based VPN
- C. ExpressRoute circuit
- D. Global VNet peering
Answer + Explanation
Correct: B
VNet-to-VNet connections require route-based VPN. Policy-based VPN is limited to a single tunnel and doesn't support VNet-to-VNet or P2S connections. ExpressRoute is for on-premises connectivity. Global VNet peering also works for cross-region VNet connectivity and is often simpler — but if the question specifies VPN Gateway, route-based is the answer.
Q29
You configure a Standard Load Balancer with a health probe on HTTP port 80. Backend VMs run a web app on port 80 but also have an NSG on their NIC blocking all inbound traffic (default deny only). Users cannot reach the application. What change fixes this?
- A. Change the health probe from HTTP to TCP
- B. Add an NSG rule allowing inbound from the
AzureLoadBalancerservice tag on port 80 - C. Upgrade the LB SKU to Premium
- D. Associate the NSG with the subnet instead of the NIC
Answer + Explanation
Correct: B
Standard Load Balancer traffic passes through the NIC NSG. The NIC NSG's default deny blocks both health probe traffic and user traffic. Adding an inbound rule allowing the AzureLoadBalancer service tag on port 80 permits both health probes and load-balanced traffic. Option D (moving NSG to subnet) would also work but is not the minimal change — and the question asks what change "fixes" it, implying the minimal correct fix.
Q30
Your organization has a hub VNet with a VPN Gateway and multiple spoke VNets. Spoke A needs to communicate with on-premises resources via the hub's VPN Gateway. You've configured peering from Hub to Spoke A. What additional settings must be configured?
- A. Enable
useRemoteGatewayson the Hub-to-SpokeA peering - B. Enable
allowGatewayTransiton the Hub-to-SpokeA peering ANDuseRemoteGatewayson the SpokeA-to-Hub peering - C. Create a VPN Gateway in Spoke A as well
- D. Enable global peering on both peering connections
Answer + Explanation
Correct: B
Gateway transit requires:
- Hub side (Hub-to-SpokeA):
allowGatewayTransit = true— "I share my gateway with this peer" - Spoke side (SpokeA-to-Hub):
useRemoteGateways = true— "I want to use the hub's gateway"
Both must be set on their respective peering connections.
Q31
You create a Private Endpoint for an Azure SQL server in your VNet. A VM in the VNet tries to connect to contoso.database.windows.net and reaches the public IP. What is likely misconfigured?
- A. The Private Endpoint is in the wrong subnet
- B. DNS is not resolving to the private IP — the DNS zone for the private endpoint is not linked to the VNet
- C. The NSG on the VM's subnet is blocking SQL traffic
- D. Private Endpoints only work for Blob storage, not SQL
Answer + Explanation
Correct: B
Private endpoints work by adding a private IP to your VNet AND updating DNS so the FQDN resolves to that private IP. If the Private DNS zone (privatelink.database.windows.net) is not linked to the VNet, DNS still resolves to the public IP, and traffic bypasses the private endpoint entirely. The connection reaches the public endpoint — not the private one.
Q32
You have a subnet with a route table containing:
- Route 1:
0.0.0.0/0→ next hopVirtualAppliance→10.0.0.4 - Route 2:
10.1.0.0/16→ next hopVirtualNetwork
Traffic to 10.1.5.10 takes which path?
- A. Through the VirtualAppliance at
10.0.0.4(route 1 applies because 0.0.0.0/0 is the catch-all) - B. Directly within the VNet (route 2 applies because
10.1.0.0/16is more specific) - C. Dropped — conflicting routes cause traffic to be black-holed
- D. Split 50/50 between both routes (Azure load-balances equal routes)
Answer + Explanation
Correct: B
Azure routing uses longest prefix match. 10.1.0.0/16 is more specific than 0.0.0.0/0, so route 2 wins. Traffic to 10.1.5.10 goes directly within the VNet. Route 1 handles all other internet-bound traffic not matched by more specific routes.
Q33
You need to allow on-premises users to access an Azure Storage account privately — using its private IP — over an existing ExpressRoute circuit. Which feature enables this?
- A. Service Endpoint for Storage
- B. Private Endpoint for the Storage account
- C. ExpressRoute Microsoft Peering
- D. Storage account network firewall rule for ExpressRoute
Answer + Explanation
Correct: B
Private Endpoint assigns a private IP to the storage account within your VNet. On-premises networks connected via ExpressRoute (private peering) can reach this private IP. Service Endpoints don't provide a private IP — the storage account still uses its public IP, and service endpoints don't work over ExpressRoute private peering for on-premises clients.
Q34
An NSG has these inbound rules:
- Priority 100: Allow TCP 80 from Internet
- Priority 200: Deny All from Internet
- Priority 65500: DenyAllInBound (default)
Traffic on TCP port 80 from the internet — what happens?
- A. Allowed — rule 100 (Allow TCP 80) is evaluated first and matches
- B. Denied — rule 200 (Deny All) also matches and overrides rule 100
- C. Denied — the default deny rule at 65500 applies to all internet traffic
- D. Allowed only if the VM also has an NSG on its NIC
Answer + Explanation
Correct: A
NSG rules are evaluated by priority — lowest number first. Rule 100 matches TCP port 80 from Internet → Allow. Evaluation stops at the first matching rule. Rule 200 (Deny All) is never reached for port 80 traffic because rule 100 already matched. Port 443 or any other port from Internet would hit rule 200 and be denied.
Domain 5 — Monitor & Maintain (~6 questions)
Q35
You want to receive an email notification when a VM in a production resource group is deleted by any user. Which alert type and scope should you configure?
- A. Metric alert scoped to the VM
- B. Activity log alert scoped to the resource group
- C. Log query alert using
AzureMetricstable - D. Resource health alert scoped to the subscription
Answer + Explanation
Correct: B
VM deletion is a management plane operation — it appears in the Activity Log. Activity log alerts trigger when specific operations occur within the defined scope. Scoping to the resource group catches any VM deletion within it. Metric alerts are for numeric thresholds; resource health is for platform-detected VM health states.
Q36
A Log Analytics query returns an empty result set immediately after you enable Diagnostic Settings on a new VM. What is the most likely explanation?
- A. The VM must be restarted to begin sending logs
- B. Data ingestion has a delay of 5–10 minutes after enabling Diagnostic Settings
- C. The KQL query syntax is incorrect
- D. Log Analytics workspaces only accept data from VMs in the same region
Answer + Explanation
Correct: B
Log Analytics ingestion is not real-time — there is typically a 5–10 minute delay between activity occurring and data appearing in the workspace. Newly configured diagnostic settings take time for the first data to flow through. Always wait before concluding data isn't flowing.
Q37
Your organization's RTO is 30 minutes and RPO is 1 hour for a critical VM. Which service should you use?
- A. Azure Backup with hourly backup policy
- B. Azure Site Recovery with continuous replication
- C. Azure Backup with daily backup + geo-redundant vault
- D. Availability Zones with Standard Load Balancer
Answer + Explanation
Correct: B
Azure Site Recovery replicates continuously (RPO ~15 minutes, well within the 1-hour RPO). Failover typically completes in minutes with pre-staged recovery plans (achieves the 30-minute RTO). Azure Backup with hourly policy would give RPO of up to 1 hour — borderline — but backup restore (RTO) takes longer than 30 minutes for a full VM. ASR is the correct answer for both RPO and RTO requirements in DR scenarios.
Q38
A KQL query in Log Analytics:
AzureActivity
| where TimeGenerated > ago(24h)
| summarize count() by OperationNameValue
| order by count_ desc
| top 5 by count_
What does this query return?
- A. All Azure activity in the last 24 hours
- B. The 5 most frequent Azure management operations in the last 24 hours
- C. The 5 most recent Azure management operations
- D. A summary of all operation types with counts, sorted alphabetically
Answer + Explanation
Correct: B
Step by step:
AzureActivity— query the activity log tablewhere TimeGenerated > ago(24h)— last 24 hours onlysummarize count() by OperationNameValue— count occurrences of each operation typeorder by count_ desc— sort by count, highest firsttop 5 by count_— return only the top 5 rows
Result: the 5 operation types with the highest occurrence count in the last 24 hours.
Q39
You delete a backup item from a Recovery Services vault. 10 days later, you realize you need the data. Is recovery possible?
- A. No — backup data is permanently deleted immediately when the item is removed
- B. Yes — soft delete retains deleted backup data for 14 days by default
- C. Yes — only if you had geo-redundant vault replication enabled
- D. No — Recovery Services vaults do not support soft delete for VM backups
Answer + Explanation
Correct: B
Azure Backup's soft delete is enabled by default on Recovery Services vaults. When backup data is deleted, it enters a soft-delete state for 14 days. During this window, you can "undelete" the backup item to restore it to active protection. After 14 days, it's permanently purged. Since 10 days have passed and the default retention is 14 days, recovery is still possible.
Q40
Azure Advisor identifies that a VM is running at < 5% average CPU over the past 14 days. What type of recommendation does Advisor provide for this VM?
- A. Security recommendation — disable unused VM extensions
- B. Cost recommendation — right-size or shut down the underutilized VM
- C. Operational Excellence recommendation — enable diagnostic settings
- D. Performance recommendation — increase VM CPU allocation
Answer + Explanation
Correct: B
Azure Advisor's Cost category identifies underutilized resources. A VM running at < 5% CPU for 14 days is flagged as a candidate for right-sizing (smaller VM size) or shutdown. This falls squarely in the Cost recommendations category — not performance (which would recommend more resources).
Score Yourself
| Domain | Questions | Your Score |
|---|---|---|
| Domain 1 — Identities & Governance | Q1–Q7 (7) | /7 |
| Domain 2 — Storage | Q8–Q15 (8) | /8 |
| Domain 3 — Compute | Q16–Q25 (10) | /10 |
| Domain 4 — Networking | Q26–Q34 (9) | /9 |
| Domain 5 — Monitor & Maintain | Q35–Q40 (6) | /6 |
| Total | 40 | /40 |
Passing Score Analysis
| Score | Action |
|---|---|
| 32–40 (80–100%) | Ready to schedule — book within 2 weeks |
| 26–31 (65–77%) | Review domains where you missed 2+ questions |
| < 26 (< 65%) | Return to domain chapters for weak areas, redo labs |
Weak Area Guidance
| If you missed Q... | Revisit |
|---|---|
| Q1, Q3, Q7 | Domain 1 — RBAC & Governance |
| Q2, Q5 | Domain 1 — Azure Policy |
| Q4, Q6 | Domain 1 — Locks & Managed Identities |
| Q8, Q10, Q13 | Domain 2 — Blob Tiers & Lifecycle |
| Q9, Q12 | Domain 2 — SAS & Access Control |
| Q11, Q14 | Domain 2 — Redundancy & Files |
| Q16, Q24 | Domain 3 — VMSS |
| Q17, Q21 | Domain 3 — Availability & Bastion |
| Q18, Q23 | Domain 3 — ARM Templates |
| Q19, Q22 | Domain 3 — App Service & ACI |
| Q26, Q29, Q34 | Domain 4 — NSGs |
| Q27, Q31 | Domain 4 — ASGs & Private Endpoints |
| Q28, Q30 | Domain 4 — VPN & Peering |
| Q32, Q33 | Domain 4 — UDR & Private Endpoints |
| Q35, Q36, Q38 | Domain 5 — Monitor & Alerts |
| Q37, Q39 | Domain 5 — Backup & ASR |
| Q40 | Domain 5 — Azure Advisor |