VM Maintenance — Moving to a Different Host
When Azure schedules maintenance on the physical host running a virtual machine, the VM may experience downtime. Two self-service options are available to proactively move a VM to a different host: Redeploy and Reapply. Understanding the difference between them and distinguishing both from unrelated operations (like resource group moves) is important.
- Redeploy — moves the VM to a new physical host within Azure. The VM is deallocated, moved to a new host, and restarted. This resolves physical host issues and is the correct action when a maintenance notification says the current host will be affected. The VM gets a new host assignment.
- Reapply — re-applies the VM's configuration on the same host. This resolves issues with extensions, guest agent connectivity, or configuration drift — not hardware problems. It does not change the physical host.
- Moving to a different resource group or subscription — a metadata operation only. The VM stays on exactly the same physical host in exactly the same Azure region. This has zero effect on maintenance scheduling.
- Enabling "Updates" or clicking "One-time update" — these schedule or trigger OS-level updates on the current VM; they do not migrate the VM to new hardware.
VM Resize in Availability Sets
When resizing a VM that is in an availability set, Azure must ensure the new VM size is available on a physical host in the same fault domain cluster. If the desired size is not available in the current cluster, the resize will fail. The solution is to deallocate the VM first, which releases it from its current host and allows Azure to allocate it to any host in the region — including one that supports the new size.
While a VM is running, it is bound to its current physical host. Deallocating the VM releases that binding. When the VM is started again after the resize, Azure can place it on any host in the region that supports the new size — it is no longer constrained to the original host cluster. This is why deallocating before resizing is the correct first step when a size is unavailable.
- Creating a proximity placement group — PPGs constrain VM placement to a specific area; they do not help when a size is simply unavailable.
- Converting to a managed availability set — changes the disk management model; does not affect host cluster capacity for specific VM sizes.
- Shutting down VM2 and VM3 (other VMs in the set) — freeing capacity on other VMs does not make the desired size available on the current host cluster.
VM Changes — Which Cause Downtime
Not all changes to a running virtual machine require it to stop. Knowing which operations can be performed on a live VM versus which require deallocation is important for planning maintenance windows and understanding the impact of configuration changes.
| Change | Causes Downtime? | Why |
|---|---|---|
| Change VM size (SKU) | Yes | Requires VM deallocation and reallocation to a new (or same) host |
| Add a network interface | Yes | Requires VM deallocation; NIC attachment modifies the hypervisor fabric connection |
| Add a managed data disk | No | Hot-attach is supported; disk attaches while VM is running |
| Add a VM extension (Puppet, custom script, etc.) | No | Extensions install into the running OS via the VM Agent |
| Enable Desired State Configuration (DSC) | No | DSC extension applies configuration to the running OS |
Even though adding extensions or enabling DSC does not cause downtime, the VM must be in a Running state for the extension to execute. If a VM is in the Stopped (Deallocated) state, it must be started before any extension — including DSC — can be applied. Enabling DSC on a deallocated VM requires starting it first, not capturing a snapshot.
Azure Disk Encryption & Key Encryption Key (KEK)
Azure Disk Encryption (ADE) encrypts the OS and data disks of a virtual machine using BitLocker (Windows) or DM-Crypt (Linux). A Key Encryption Key (KEK) is an optional additional layer of protection in Azure Key Vault that wraps the disk encryption key. Enabling ADE with a KEK requires running a specific PowerShell cmdlet.
To enable Azure Disk Encryption with a KEK on a running VM, use: Set-AzVMDiskEncryptionExtension. This cmdlet installs the ADE extension on the VM and configures it with the specified Key Vault and KEK. The -KeyEncryptionKeyUrl parameter specifies the KEK. This is the only correct cmdlet — not Set-AzDiskEncryptionKey (which does not exist as a standard cmdlet) and not Set-AzDiskDiskEncryptionKey.
ADE — Which VMs Can Be Encrypted
Azure Disk Encryption requires the virtual machine to be in a specific state to be encrypted. Not all VMs are eligible, and the VM's power state is the most commonly tested constraint.
Azure Disk Encryption can only be enabled on running (started) virtual machines. A VM that is in the Stopped (Deallocated) state cannot be encrypted because the ADE extension needs to execute within the running operating system to configure BitLocker or DM-Crypt. If a question presents a mix of running and deallocated VMs and asks which ones can be encrypted, the answer includes only the running ones.
A VM in the Stopped (Deallocated) state has its compute resources released. The ADE extension has no running OS to operate within, so encryption cannot be configured. To encrypt a deallocated VM, it must first be started.
Disk Encryption Methods — ADE vs CMK vs Confidential vs Encryption at Host
Azure offers several distinct disk encryption mechanisms, each designed for different scenarios and threat models. Knowing which method to select based on the stated requirements is important, as they differ fundamentally in where keys are stored, what is encrypted, and what happens when a VM is moved off Azure.
| Method | What It Encrypts | Key Stored In | Survives VM Download? | Use Case |
|---|---|---|---|---|
| Azure Disk Encryption (ADE) | OS disk + data disks (BitLocker/DM-Crypt inside the OS) | Azure Key Vault (required) | Yes — BitLocker remains active on the disk | Encrypt both OS and data disks; maintain encryption if disk is removed from Azure |
| Customer-Managed Keys (CMK / SSE) | Data at rest on the Azure storage infrastructure (Server-Side Encryption) | Azure Key Vault or Managed HSM | No — encryption is at the storage layer, not the OS layer | Controlling the storage encryption key; compliance requirements for key custody |
| Confidential disk encryption | OS disk, bound to a vTPM; protects against Azure infrastructure access | TPM (hardware-bound) | No — bound to the specific hardware | Confidential computing; protection from Azure operator access |
| Encryption at host | Temp disks, disk caches, and data flowing between storage and the host | Platform-managed or customer key | No — host-level only | Closing the cache/temp disk encryption gap that SSE doesn't cover |
When a requirement specifies all three of: (1) store and use the encryption key in Key Vault, (2) maintain encryption if the VM is downloaded from Azure, and (3) encrypt both the OS disk and data disks — the answer is Azure Disk Encryption (ADE). CMK encrypts at the storage layer and does not survive download. Confidential disk encryption is hardware-bound. Encryption at host does not cover the OS disk via BitLocker/DM-Crypt.
VM Data Disk — Storage Type, Redundancy & Host Caching
Choosing the right managed disk configuration involves independently selecting the storage performance tier, the redundancy level, and the host caching mode. These three choices serve different purposes and the constraints of each must be evaluated separately before arriving at a combined answer.
| Type | Performance | LRS | ZRS | Datacenter Outage Resiliency? |
|---|---|---|---|---|
| Premium SSD | Highest — single-digit ms latency | Yes | Yes | ZRS only |
| Standard SSD | Moderate | Yes | Yes | ZRS only |
| Standard HDD | Lowest | Yes | No | No ZRS option |
LRS (Locally Redundant Storage) keeps 3 copies within one datacenter — it does not survive a full datacenter outage. ZRS (Zone-Redundant Storage) keeps 3 copies across 3 availability zones — it survives a datacenter outage within the region. When the requirement states "resilience against a datacenter outage," ZRS is required.
| Caching Mode | Behaviour | Data Loss Risk on Host Failure? |
|---|---|---|
| None | All reads and writes go directly to the managed disk | No — data always written to disk immediately |
| Read-only | Reads served from host cache; writes go directly to disk | No — only reads are cached; writes are direct |
| Read/Write | Both reads and writes pass through host cache; flushed periodically | Yes — unflushed cached writes are lost if host fails |
For a disk that must: (1) survive a datacenter outage → ZRS, (2) provide lowest latency and highest performance → Premium SSD, and (3) ensure no data loss if the host fails → host caching = None. Read/Write caching risks losing unsaved cached writes on host failure and must never be chosen when "no data loss" is a hard requirement.
vCPU Quota & Deallocated VMs
Azure subscriptions have vCPU quotas that limit how many virtual CPUs can be deployed per region and per VM family. Understanding which VMs count against quota — and which do not — is essential for calculating whether a new deployment will succeed.
- Running VMs — consume vCPU quota. Their vCPUs count against the regional and family limits.
- Stopped (Deallocated) VMs — do not consume quota. Deallocating releases the compute allocation back to the pool. This is why "Stop (Deallocate)" reduces quota usage, while "Shut down from within the OS" (which leaves the VM in Stopped but not Deallocated) does not.
- Stopped (not deallocated) VMs — still consume quota. The VM still has compute resources reserved even though it is not actively running.
A VM that is shut down from within the operating system enters the "Stopped" state but remains allocated on the host — it continues to consume quota and you continue to be billed for compute. Only when you use the Azure portal, CLI, or PowerShell to explicitly Stop (Deallocate) the VM does it release quota. When calculating available quota headroom, count only running VMs (and stopped-but-not-deallocated VMs).
Availability Set — Fault Domains vs Update Domains for High Availability
Availability Sets protect VMs from two distinct failure categories. Fault domains protect against unplanned hardware failures; update domains protect against planned maintenance downtime. Choosing the right number of each requires understanding what kind of failure you're protecting against and how VMs are distributed across domains.
| Domain Type | Protects Against | Azure Reboots How Many at Once? | Default / Max |
|---|---|---|---|
| Fault Domain (FD) | Unplanned hardware failure — power, switch, rack | N/A — failures are random per domain | 2 default / 3 max |
| Update Domain (UD) | Planned maintenance — Azure reboots one UD at a time | All VMs in one UD simultaneously | 5 default / 20 max |
During planned maintenance, Azure reboots all VMs in one update domain at a time. To guarantee that at least M VMs out of N total remain running, you need at least enough UDs so that each UD contains at most N − M VMs.
- 2 VMs, need 1 always available: at most 1 VM per UD → need at least 2 update domains.
- 9 VMs, need 8 always available: at most 1 VM per UD → need at least 9 update domains. Choosing 10 UDs is safe (at most 1 VM per UD since 9 ÷ 10 rounds up to 1).
- 50 VMs, maximum availability: use the maximum of 20 update domains to minimise how many VMs are offline at once.
Azure distributes VMs as evenly as possible across UDs. For N VMs across D UDs, the busiest UD has ceil(N/D) VMs, and that is the maximum number offline at once. For example, 14 VMs across 10 UDs: ceil(14/10) = 2, so at most 2 VMs are offline during a maintenance window. For 14 VMs across 2 FDs: 14 ÷ 2 = 7 per FD, so an entire rack failure could take 7 VMs offline simultaneously.
To maximise availability in an ARM template deployment of 50 VMs in an availability set, use platformFaultDomainCount: 2 or 3 (not 0 or 1) and platformUpdateDomainCount: 20 (the maximum). Setting these to 0 or 1 would place all VMs in the same domain, providing no protection at all.
Proximity Placement Groups — Region Constraint
A Proximity Placement Group (PPG) is a logical grouping that signals Azure to place associated resources physically close together within a data centre, reducing network latency between VMs in the group. However, PPGs have a regional scope — they can only contain resources within the same Azure region.
To assign a VMSS or individual VM to a proximity placement group, the VMSS/VM and the PPG must be in the same Azure region. The resource group membership of the PPG or the VM is irrelevant — only the Azure region matters. When selecting a PPG for a VMSS, filter the available options by matching region: only PPGs in the same region as the VMSS are valid candidates.
DSC Extension & Post-Deployment Software Configuration
Desired State Configuration (DSC) is a PowerShell-based platform for declaring the software configuration state that a Windows server should maintain. When deploying virtual machines via ARM templates — especially in VM scale sets — DSC ensures that required software (such as NGINX, IIS, or specific Windows features) is installed and configured on every instance, including new instances added during scale-out.
- Desired State Configuration (DSC) extension — declared as an extension in the VMSS ARM template. It references a DSC configuration script stored in Azure Blob Storage and applies that configuration to each VM instance after deployment.
Publish-AzVMDscConfigurationcmdlet — uploads the DSC configuration script (.ps1) to Azure Blob Storage so the DSC extension can reference it. The cmdlet and extension work together: cmdlet publishes the configuration, extension applies it.
- Azure Application Insights — an application performance monitoring service; it collects telemetry, it does not install software packages.
- New-AzConfigurationAssignment — assigns maintenance window configurations (update schedules) to resources; it does not configure or install software.
VMSS Autoscaling — Reading Rules & Calculating Outcomes
VM Scale Set autoscaling rules define conditions under which instances are added (scale-out) or removed (scale-in). Calculating the expected instance count at a given point in time requires applying the rules in order, respecting minimum and maximum boundaries, and accounting for the fact that scale events are discrete — a scale action fires once when the condition is met for the full duration, not continuously.
- Start with the initial instance count.
- Check whether the scale-out or scale-in condition threshold was met for the entire required duration.
- Apply the instance change (add or subtract as specified in the rule).
- Clamp the result to the configured minimum and maximum bounds.
- Check whether another scale event could fire within the same time window (accounting for any cooldown period).
Config: Initial=4, Min=2, Max=20. Scale-out: CPU>80% for 5 min → +2. Scale-in: CPU<30% for 5 min → −4.
Scenario A — CPU 85% for 6 minutes: scale-out condition met at minute 5 → 4 + 2 = 6 instances. Still high CPU at minute 6, but no second scale event fires yet (cooldown). Answer: 6 instances.
Scenario B — CPU 25% for 6 minutes, then 50% for 6 minutes: scale-in at minute 5 → 4 − 4 = 0, bounded to min = 2 instances. Then 50% (no condition met) → stays at 2. Answer: 2 instances.
Scale-in results can never go below the configured minimum, and scale-out results can never exceed the configured maximum. If the math produces a result outside those bounds, clamp to the boundary. A scale-in of −4 from 4 instances with a minimum of 2 produces 2, not 0.
Scheduled Runbook to Resize a VM
When a single-instance VM experiences predictable CPU spikes at known times (such as end-of-month batch processing), the appropriate response is to schedule an Azure Automation runbook that increases the VM's size before the spike occurs, then reduces it afterwards. This is a scheduled vertical scaling operation — not a scale set, not a vCPU quota change, and not an extension.
A runbook that increases processor performance for a VM should modify the VM size property — changing the VM's SKU from a smaller size (e.g., Standard_D4s_v3) to a larger one (e.g., Standard_D8s_v3). This is done via the Azure PowerShell cmdlet Update-AzVM after setting the new size with $vm.HardwareProfile.VmSize. The runbook stops the VM, changes the size property, and restarts it.
- Add VM1 to a scale set — the scenario states the application does not support multiple active instances, making horizontal scaling (scale sets) impossible.
- Add the Azure Performance Diagnostics agent — a monitoring agent; it collects diagnostics but does not change VM performance.
- Increase the vCPU quota for the subscription — quota is a limit on how many vCPUs can be deployed, not a property of an individual VM.
- Add a DSC extension — DSC manages software configuration state; it does not resize a VM.
Active Directory Domain Controller Migration to Azure
When lifting an on-premises domain controller (DC) to an Azure VNet, two critical configuration choices must be made correctly for Active Directory to function: the DC's IP address and the VNet's DNS configuration. Errors in either will break domain name resolution for all machines in the VNet.
The DC must be assigned a static IP address within the destination Azure subnet's address range. Azure reserves the first 4 addresses and the last address in each subnet (.0, .1, .2, .3, .255 for a /24), so the DC's static IP must be chosen from the remaining usable range. The DC's old on-premises IP (e.g., 192.168.2.1) cannot be used — it belongs to an entirely different address space. Dynamic (DHCP) assignment must not be used because DHCP-assigned IPs can change on VM restart, breaking AD replication and DNS.
All VMs in the Azure VNet must resolve Active Directory DNS records (domain names, SRV records for replication, Kerberos, etc.). Azure's default DNS cannot resolve AD DS names. The VNet's DNS server settings must be changed to point to the DC's new Azure static IP. Azure Private DNS zones named after the AD domain (e.g., contoso.com) are not a substitute — they are for Azure-managed resolution, not AD DS SRV records.
Azure Site Recovery — Test Failover Subnet Mapping
When performing a test failover with Azure Site Recovery (ASR), the replicated VM is spun up in a target virtual network. ASR must determine which subnet in the target VNet to connect the test VM to. This mapping is based on a specific matching rule that does not rely on subnet names.
ASR matches subnets between source and target VNets by comparing IP address ranges (CIDR blocks). If a subnet in the target VNet has exactly the same IP range as the subnet the source VM was connected to, ASR places the test VM in that matching subnet — regardless of what either subnet is named. Subnet names like "RecoverySubnetA" or "DemoSubnet1" are irrelevant to the mapping logic.
Source: VM1 is connected to Subnet2 (172.16.2.0/24) in VNET1 (East US).
Target VNET2 (West US) subnets: DemoSubnet1 (172.16.1.0/24), RecoverySubnetA (172.16.5.0/24), RecoverySubnetB (172.16.3.0/24), TestSubnet1 (172.16.2.0/24).
ASR finds that TestSubnet1 has the same range as Subnet2 → the test failover VM connects to TestSubnet1.
VMware to Azure Migration — Azure Site Recovery Order of Operations
Migrating VMs from VMware vSphere to Azure using Azure Site Recovery follows a precise sequence. The steps are ordered because each one depends on the previous being complete — in particular, the on-premises configuration server must be deployed before replication can be configured or enabled.
- Deploy the OVA template to vSphere — this is the very next step after creating the vault. The OVA creates the configuration server on-premises. This server is the bridge between VMware and Azure; without it, ASR cannot discover or replicate VMware VMs.
- Register the configuration server with the vault.
- Configure a replication policy — set RPO threshold and recovery point retention.
- Enable replication — select source VMs and target Azure settings.
- Run a test failover — validate without impacting production.
- Perform the final failover — cut over to Azure.
The first action after creating a Recovery Services vault for a VMware migration is deploying the Open Virtualization Application (OVA) template to vSphere. Creating a recovery plan, configuring a virtual network, and setting up an extended network are all later steps. Without the configuration server (deployed via OVA), ASR has no visibility into the on-premises VMware environment.
App Service Plan Tiers — Scale-Out, Staging Slots & Zone Redundancy
The App Service plan tier determines which platform capabilities are available to hosted web apps. Three commonly tested capabilities — rules-based autoscale (scale-out), staging deployment slots, and zone redundancy — are not available on all tiers, and knowing the tier thresholds for each is important.
| Tier | Rules-Based Scale Out | Staging Slots | Zone Redundancy |
|---|---|---|---|
| Free / Shared | No | No | No |
| Basic | No (manual scale only) | No | No |
| Standard | Yes | Yes (up to 5 slots) | No |
| Premium v2 / v3 | Yes | Yes | Yes |
| Isolated / Isolated v2 | Yes | Yes | Yes |
Zone redundancy for App Service plans requires Premium v2, Premium v3, or Isolated tier. Standard tier supports autoscaling and staging slots but does not support zone redundancy. When a plan is at Standard tier and zone redundancy is required, the plan must be upgraded to at least Premium v2.
Basic tier supports custom domain verification but not autoscaling. Standard is the cheapest tier that satisfies both requirements simultaneously. If a web app needs to verify a custom domain AND scale automatically — Standard is the minimum and correct answer for minimising cost.
App Service Plan — OS Compatibility and Region Constraints
Every web app must be placed in an App Service plan that satisfies two independent constraints: the plan must be in the same Azure region as the app, and the plan's operating system must be compatible with the app's runtime stack. Both conditions must be met — a plan that satisfies one but not the other is not eligible.
| Runtime Stack | Windows Plan | Linux Plan |
|---|---|---|
| .NET (Core) / .NET 5+ / .NET 8+ | Yes | Yes |
| ASP.NET 4.8 / ASP.NET 3.5 (Framework) | Yes — Windows only | No |
| Node.js, Python, Ruby | Yes (most versions) | Yes |
| PHP, Java SE, Tomcat | Yes | Yes |
ASP.NET 4.8 (the classic .NET Framework) cannot run on Linux App Service plans. Whenever a web app specifies ASP.NET 4.8 as its runtime, all Linux plans are immediately ineligible. Only Windows plans in the correct region remain as candidates. .NET (Core) and .NET 5+ are cross-platform and run on both.
App Service Plan — Multiple Apps, One Plan, OS Compatibility
A single App Service plan can host multiple web apps simultaneously, regardless of their runtime stacks, as long as the plan's operating system is compatible with every app hosted on it. Apps with different runtimes do not each require their own plan — grouping compatible apps together minimises cost and administrative overhead.
- Windows plan: can host .NET Framework (ASP.NET 4.8/3.5), .NET (Core), PHP, Java, and Node.js — all Windows-compatible runtimes together.
- Linux plan: can host .NET (Core), PHP, Python, Ruby, Node.js, and Java SE — all Linux-compatible runtimes together.
- Apps requiring different OS types must use separate plans. Apps in different regions must use separate plans.
WebApp1 (.NET 9, Windows or Linux), WebApp2 (ASP.NET 4.8, Windows only), WebApp3 (PHP, Linux or Windows), WebApp4 (Python, Linux only). All in the same region.
WebApp2 requires Windows. WebApp4 requires Linux. WebApp1 can go to either. WebApp3 can go to either. Optimal: Plan A (Windows) = WebApp2 + WebApp1 (or WebApp3). Plan B (Linux) = WebApp4 + the remaining cross-platform app. Minimum = 2 plans.
App Service Autoscaling — Rules, Methods & Cooldown
App Service supports three scale-out methods with different levels of automation. When autoscaling is triggered by a rule, a cooldown period determines the minimum time before another scale event can fire — this prevents thrashing (rapid scale-in and scale-out) when usage hovers near a threshold.
- Manual — an administrator sets the instance count explicitly. No automatic scaling occurs.
- Rules-Based — Azure Monitor rules define thresholds (CPU percentage, memory, HTTP queue length, etc.) and scaling actions. When a metric exceeds the threshold for the specified duration, a scale event fires. This is the correct method for "scale automatically when CPU exceeds 80%."
- Automatic (Azure-managed) — Azure manages the instance count without user-defined rules, based on load patterns. Available on Premium v2 and higher plans only.
After a scale event fires, the cooldown period must expire before the next scale event can fire. This prevents the system from rapidly oscillating between instance counts. To calculate the number of instances at a specific point in time:
- Check whether the threshold condition has been met for the full required duration.
- If yes, fire the scale event and apply min/max bounds.
- The next scale event cannot fire until the cooldown expires.
- Only one scale event fires per cooldown window — not multiple, even if the condition remains true.
Config: Default=1, Min=1, Max=5. Scale-out: CPU>80% for 15 min → +1 instance. Cooldown: 10 min.
Scenario A — CPU at 80% for exactly 15 minutes: condition met at minute 15 → scale fires → 1+1=2 instances. Cooldown starts. After 10 minutes another scale can fire if condition still met. Answer at minute 15: 2 instances.
Scenario B — After first scale-out, time before another instance can be created: the cooldown period = 10 minutes minimum before the next scale event.
On a Standard App Service plan, the "Automatic" scale-out option is not available — it requires Premium v2 or higher. To configure CPU-threshold-based autoscaling on Standard tier, the correct setting is Rules Based in the Scale out method settings. Selecting "Standard S1" or "Premium P1" in Scale up changes the plan size, not the scaling method.
Custom Domain Configuration — Azure App Service
Adding a custom domain to an Azure web app involves creating DNS records at the domain registrar and verifying ownership through the App Service portal. The sequence and record types required depend on whether the domain is a root/apex domain or a subdomain.
| Record Type | Purpose | When Required |
|---|---|---|
| TXT | Domain ownership verification (asuid.subdomain → Custom Domain Verification ID) | Always — required for verification regardless of whether CNAME or A record is used |
| CNAME | Maps subdomain to app hostname (www.contoso.com → webapp1.azurewebsites.net) | Subdomains (www, app, etc.) only — cannot use CNAME for root/apex domain |
| A record | Maps root domain to app's public IP (contoso.com → 40.x.x.x) | Root/apex domain — always paired with a TXT verification record |
Before any DNS routing record (CNAME or A) is effective, the TXT verification record must be created. The first step in configuring a custom domain for a web app is to create a TXT record (specifically asuid.subdomain pointing to the Custom Domain Verification ID from the App Service portal). Only after creating this record can the domain be validated and added to the app.
App Service — Web Deploy & Website Contributor Role
Web Deploy is a deployment method for pushing web application content directly to an Azure App Service web app using Microsoft Entra (Azure AD) credentials. It is commonly used by developers through Visual Studio or CI/CD pipelines. The principle of least privilege dictates a specific role for this use case.
To allow developers to deploy content to a web app using Web Deploy with their Microsoft Entra credentials, assign them the Website Contributor role. This role grants the permissions needed to deploy and manage web app content (including using Web Deploy) without providing access to Azure subscription resources, networking, or other services. It is the least-privilege role that satisfies this specific requirement.
- Owner role — grants full control of all Azure resources including the ability to assign roles. This is far more permissive than needed for content deployment.
- App-level credentials for FTPS — FTPS uses a separate set of deployment credentials, not the developer's Microsoft Entra identity. This does not satisfy the "use their Entra credentials" requirement.
- User-level credentials for FTPS — similarly uses FTPS and the developer's deployment password, not their Entra credentials.
App Service — TLS Certificates from Key Vault
When configuring HTTPS for an Azure App Service web app using a certificate stored in Azure Key Vault, the certificate must meet specific requirements to be eligible. Not all certificates stored in a vault can be used for App Service TLS.
- Must be an X.509 certificate.
- Must contain a private key — public-only certificates cannot be used for TLS binding.
- Must be current — not expired at the time of binding.
- The certificate's Common Name (CN) or Subject Alternative Name (SAN) must match the custom domain being secured.
A certificate that is expired, lacks a private key, or whose domain name does not match the web app's custom domain will not be eligible for selection during TLS binding configuration.
App Service Backup — Storage Account, Retention & Slot Behaviour
Azure App Service backup writes ZIP files to a blob container in an Azure Storage account — not to a Recovery Services vault or Backup vault. Before configuring any backup settings, the storage account must exist. Backup configuration is per-slot and each slot must be configured independently.
- Create an Azure Storage account first — this is always the prerequisite for App Service backup.
- Exclude folders using a
_backup.filterfile — placed in the web app's wwwroot directory, one excluded path per line. Backup policies, locks, and WebJobs cannot exclude folders from an App Service backup. - Retention = 0 + "Keep at least one backup" = Yes means only the most recent backup is retained. Older backups are deleted immediately after the next one is created, so at any given time there is exactly one backup in storage.
Each deployment slot (production, staging, test) has its own backup configuration. A backup taken from the production slot does not include the test slot. To back up a test slot, backup must be configured separately on that slot. Cross-slot restores are permitted — a production backup can be restored to a test slot — but the backup must actually exist within its retention period.
Deployment Slot Swap-Back — Fastest Revert
Deployment slots enable blue-green deployments by allowing a new version to be tested in a staging slot before being swapped to production. If problems are discovered in production after a swap, the fastest way to revert is to swap the slots back — which is an almost instantaneous routing change.
After a slot swap that introduces problems, the staging slot still contains the previous good version of the application. Swapping the slots back immediately returns the previous version to production — typically in seconds. Restoring an App Service backup is a slow, destructive operation that replaces file content and may take minutes or longer. Whenever the requirement specifies "revert as quickly as possible" and a staging slot is available with the previous version, the answer is swap the slots.
App Service VNet Integration — Outbound Only, NSG Behaviour & On-Premises Access
VNet Integration connects an App Service web app to a virtual network, enabling the web app to reach private resources within that VNet (and peered VNets). It is a one-directional feature — it provides outbound connectivity from the web app into the VNet, not inbound connectivity into the web app from the VNet.
With VNet Integration enabled, the web app can communicate with VMs, databases, and other private resources in the VNet (and in peered VNets through peering). However, internet users accessing the web app via its public URL still reach it through App Service's public frontend — VNet Integration does not affect inbound access to the web app at all.
An NSG associated with the integration subnet governs what traffic the web app can send into the VNet, and what VNet resources can respond back. It does not control public inbound traffic to the web app from the internet. Only App Service access restrictions (IP rules configured on the app's Networking blade) control which public IP addresses can reach the web app.
To allow an Azure web app to connect to an on-premises SMB file share (port 445), two components are needed together: an Azure Virtual Network Gateway (which establishes the Site-to-Site VPN tunnel to the on-premises network) and VNet Integration on the web app (which enables the web app to route traffic through that VPN gateway to on-premises). The VPN gateway creates the secure tunnel; VNet Integration gives the web app access to that tunnel.
| VNet Integration | App Service Environment (Isolated) | |
|---|---|---|
| App is deployed inside VNet | No — outbound only via delegation | Yes — ASE subnet is within the VNet |
| NSG controls inbound to app | No | Yes — NSG on the ASE subnet |
| Can reach peered VNets | Yes | Yes |
Azure Container Registry — Service Tiers & Content Trust
Azure Container Registry offers three service tiers that differ in storage capacity, throughput, and available features. Several advanced features — including private endpoints, geo-replication, and content trust for image signing — are restricted to the Premium tier.
| Feature | Basic | Standard | Premium |
|---|---|---|---|
| ACR Tasks (build/run) | Yes | Yes | Yes |
| Private endpoints | No | No | Premium only |
| Geo-replication | No | No | Premium only |
| Content trust (signed images) | No | No | Premium only |
| Dedicated data endpoint | No | No | Premium only |
To push and pull signed images in an ACR, enable content trust on the registry. Content trust uses Docker Content Trust (DCT) to cryptographically sign and verify image layers. Enabling CMK encryption is for data-at-rest protection — not image signing. Repository-scoped tokens control access permissions — not signing. A connected registry is for offline or edge scenarios. Content trust is a Premium-tier feature; if the current tier is Standard, it must be upgraded first.
Azure Container Registry — Authentication & Admin User
ACR supports several authentication patterns. The choice depends on the use case: quick manual access, automated CI/CD pipelines, or Azure-hosted workloads accessing the registry. Understanding which credential pattern to use — and what the admin username actually is — prevents configuration mistakes.
- Admin user — a built-in account with username = the registry name. Enabled via the portal. Best for quick testing or ACI deployment. Not recommended for production automated pipelines.
- Service principal + AcrPull — a service principal with the AcrPull role. Best for CI/CD pipelines and automated build systems.
- Managed identity (AKS, App Service) — recommended for Azure-hosted workloads. No credentials to manage or rotate.
- Repository-scoped token — grants access to specific repositories only. For granular access control.
When admin user is enabled on a registry named CrackCertsReg1, the admin username is CrackCertsReg1 — exactly the registry name. It is not "admin", "administrator", or "root". The password is one of two auto-generated values that can be rotated in the portal.
ACR Dedicated Data Endpoint
By default, Azure Container Registry uses a shared data endpoint for image layer downloads. The dedicated data endpoint feature provides a registry-specific FQDN for data traffic, which simplifies firewall rule management — administrators can allow access to just that specific endpoint rather than a broad Azure storage endpoint range.
Enabling a dedicated data endpoint for an ACR requires configuring two separate settings in the portal:
- Networking blade — this is where the "Enable dedicated data endpoint" toggle is located. Enabling it here activates the feature and generates the dedicated FQDN.
- Properties blade — the dedicated data endpoint FQDN is displayed here for reference after it has been enabled via Networking.
Both blades must be visited: Networking to enable the feature, Properties to retrieve the endpoint FQDN. ACR Tasks, Access control (IAM), Events, and the Overview blade are not involved in this configuration.
The dedicated data endpoint feature is only available on the Premium tier. A Basic or Standard registry does not support this feature. If a registry is on Standard and the dedicated endpoint is needed, the tier must be upgraded to Premium first.
ACR CLI Commands — Create, Build, Push, Deploy
Working with Azure Container Registry from the Azure CLI and Docker CLI involves a set of distinct commands for different operations. Knowing which command to run for each task prevents confusion between provisioning the registry, building images, pushing images, and deploying containers.
| Task | Command | Notes |
|---|---|---|
| Create a new ACR | az acr create | Provisions the registry resource in Azure |
| Build image from source + push to ACR | az acr build | Cloud build in ACR; no local Docker needed |
| Push a locally built image to ACR | docker push | Requires prior docker tag with ACR login server |
| Tag image with ACR login server name | docker tag | First step before pushing; required after az acr login |
| Deploy a container instance | az container create | Deploys to Azure Container Instances |
After running az acr login --name registryname, the next step before pushing is to tag the image with the registry's login server name: docker tag localimage registryname.azurecr.io/imagename:tag. Only after tagging can the image be pushed with docker push registryname.azurecr.io/imagename:tag. Listing images, deploying a container group, or configuring a YAML file are not the immediate next steps after login.
Container Hosting Services — OS Constraints & Autoscaling Support
Three Azure services can host containerised workloads: Azure Container Instances, Azure Container Apps, and Azure App Service. Each service has constraints on which container operating systems it supports and whether it can automatically scale the number of running container instances.
| Service | Windows Containers | Linux Containers | Auto-Scale? |
|---|---|---|---|
| Azure Container Instances (ACI) | Yes | Yes | No — single group, no auto-scale |
| Azure Container Apps | No — Linux only | Yes | Yes — KEDA-based, scales to zero |
| Azure App Service (containers) | Yes | Yes | Yes — rules-based, Standard+ tier |
Azure Container Apps runs exclusively on Linux. Windows Server containers (including Nano Server and Server Core images) cannot run in Container Apps. They can run in ACI or App Service. When an image is identified as a Windows container, Container Apps must be eliminated from the list of eligible services.
ACI does not have built-in autoscaling. It is designed for running individual container groups on demand, not for scaling out multiple instances in response to load. If a question asks "which services can automatically scale a container?", the answer excludes ACI. Only Container Apps and App Service support automatic instance scaling.
Container Group — OS Constraint, CPU Resources & Persistent Storage
An Azure Container Group is the top-level resource in Azure Container Instances — a group of containers that share a network namespace, lifecycle, and (optionally) storage volumes. Understanding the constraints on what containers can be grouped together, and how CPU resources are shared within a group, avoids configuration errors.
All containers within a container group must use the same operating system. A group cannot contain a mix of Windows and Linux containers. Two containers both using Windows images — even different variants like Nano Server and Server Core — can share a group because they are both Windows. A Linux container and a Windows container cannot share a group.
Each container in a group is allocated a CPU resource request (minimum guaranteed) and optionally a CPU resource limit (maximum allowed to use). If container2 has a CPU limit that is too high, it can monopolise the group's total CPU allocation and starve container1. To ensure container1 is not negatively affected, the correct action is to decrease container2's resource limit to a value that leaves sufficient CPU available for container1. Removing limits entirely would make the problem worse.
Azure Container Instances supports mounting Azure Files shares as volumes for persistent storage. This is the only supported file-system mount type for persisting data across container restarts. Azure Blob storage, Queue storage, and Table storage cannot be mounted as file-system volumes in ACI.
ACI — Azure Files Mount Constraints
When an Azure Container Instance needs to mount an Azure Files share as a persistent volume, regional co-location is required. Volume mounts must also be configured at the time the container group is created — they cannot be added to a running group.
- Same region required — the ACI container group and the storage account containing the Azure Files share must be in the same Azure region. A container group in East US cannot mount a share in West US.
- Both Windows and Linux ACI support Azure Files mounts — Azure Files (SMB protocol) works on both OS types within ACI.
- Configured at creation time — volume mount configuration is specified when the container group is provisioned. It cannot be added or modified on a running group.
Azure Files share storage1 is in East US. Containers: container1 (East US, Windows), container2 (West US, Windows), container3 (East US, Linux).
container1 (East US, Windows) → Yes — same region. container2 (West US, Windows) → No — wrong region. container3 (East US, Linux) → Yes — same region, Linux ACI supports Azure Files. Answer: container1 and container3 only.
ACI — Command Override & Environment Variables for Container Startup
When creating an Azure Container Instance, two mechanisms allow you to pass information and configuration to the container process at startup. They serve different purposes and are sometimes needed together.
A command override replaces the container image's default CMD/ENTRYPOINT with a custom command executed at container start. It is used to pass specific operational parameters or arguments to the container process — for example, a config file path, an operating mode flag, or specific startup options. The command override controls how the container process runs.
Environment variables are key-value pairs injected into the container's runtime environment. ACI supports two types: standard (visible in portal and API) and secure (values encrypted and never exposed in output or logs). Secure environment variables are the correct mechanism for injecting passwords, API keys, and connection strings at container startup without exposing them.
If a container requires both specific configuration parameters at startup AND secure values (passwords, secrets), the answer is to configure both command override and environment variables. Tags are resource metadata for billing/management — they are not passed into the container at runtime. Customer-managed keys are for encrypting the container group's data at rest — not for runtime injection.
ACI ARM Template — osType & restartPolicy Properties
When deploying an Azure Container Instance via an ARM template, two properties control fundamental runtime behaviour: osType determines the container's operating system, and restartPolicy determines what happens when the container process exits unexpectedly.
The osType property specifies the container's operating system type — either Windows or Linux. It must match the OS of the container image. Internet connectivity is controlled separately: setting ipAddress.type: Public in the ARM template allocates a public IP address, allowing internet users to reach the container. Without a public IP address allocation in the ARM template, the container is not reachable from the internet — regardless of OS type.
| restartPolicy Value | Behaviour | Typical Use Case |
|---|---|---|
| Always | Container restarts automatically whenever it exits, regardless of exit code | Long-running services like web servers (IIS) — if IIS fails, the container restarts automatically |
| OnFailure | Restarts only when the container exits with a non-zero exit code | Batch jobs that should retry on failure but stop cleanly on success |
| Never | Container never restarts — runs once and stops | One-time tasks, data processing jobs |
When a question presents an ARM template with restartPolicy: Always and asks what happens if IIS inside the container fails — the answer is "the container instance will restart automatically." When restartPolicy: Never is set and the container process fails, the container stops and cannot restart on its own — it must be redeployed manually.
Azure Container Apps Environment — VNet Subnet Requirements
When deploying an Azure Container Apps environment with custom VNet integration, a dedicated infrastructure subnet is required. The minimum subnet size depends on the environment type — the current default (workload profiles) has a smaller requirement than the legacy consumption-only environment.
| Environment Type | Minimum Subnet Size | Notes |
|---|---|---|
| Workload profiles (default) | /27 (32 addresses) | The default when creating new Container Apps environments. Smaller requirement enables more flexible VNet address planning. |
| Legacy Consumption-only (v1) | /23 (512 addresses) | The original environment type. Still works but Workload profiles is now default for new environments. |
New Container Apps environments default to the workload profiles environment type, which requires only a /27 subnet. The /23 requirement applies to the legacy consumption-only environment type. When the exam or a question does not specify the environment type, /27 is the current default minimum. The subnet must also be delegated to Microsoft.App/environments when using the workload profiles environment.
| VNet | Address Space | Existing Subnets | Remaining | Fits /27? |
|---|---|---|---|---|
| VNet1 | 10.1.128.0/27 (32) | Subnet1: /28 (16) | /28 (16 addresses) | No — only 16 addresses remaining, need 32 |
| VNet2 | 192.168.0.0/16 | Two /17 subnets filling entire /16 | None | No — fully allocated |
| VNet3 | 172.16.0.0/16 | Single /24 subnet | Large /16 remaining space | Yes — ample space |
ARM Template Copy Loops
ARM templates support copy loops to iterate over a resource property (such as data disks) to create multiple instances from a single template block. Two key constructs are needed: the copy array that declares the loop, and copyIndex() that provides the current iteration index within each loop iteration.
To create a VM with multiple data disks using a copy loop:
- Dropdown 1 (loop declaration):
"copy":[— this is the array that declares the copy loop for thedataDisksproperty. Not"copyIndex":[(a function call, not an array) and not"dependsOn":[(used for resource ordering). - Dropdown 2 (per-iteration index):
"[copyIndex— this function returns the current loop index (0, 1, 2, ...) and is used to generate unique disk names or LUN numbers within each iteration.
ARM VM Extensions — Domain Join Configuration
ARM templates can deploy VM extensions as child resources of a virtual machine. The domain join extension (JsonADDomainExtension) automates joining a Windows VM to an Active Directory domain as part of the deployment. The extension resource type and its settings properties follow a specific structure.
- Resource type for VM extensions:
Microsoft.Compute/virtualMachines/extensions— this is the correct ARM resource type. The value"Extensions"alone is not a valid resource type, andMicrosoft.Compute/VirtualMachinesis the VM itself, not the extension. - Settings section: contains the domain name, OU path, domain join options, restart setting, and the username. Plain text, non-sensitive values go in
"Settings":{. - ProtectedSettings section: contains sensitive values — specifically the domain join password. Passwords must go in
"protectedSettings":{so they are encrypted at rest and in transit. - Statuses section: displays extension installation status; it is not a configuration section in an ARM template declaration.
ARM Template Functions — resourceId() & imageReference
ARM templates use built-in functions to construct resource identifiers and reference image configurations. Two of the most commonly tested in VM deployment templates are resourceId() in the dependsOn array and the imageReference property in the storage profile.
The resourceId() function returns the fully qualified Azure resource ID for a given resource type and name. In a VM template, the dependsOn array uses resourceId() to declare that the VM resource must wait for the NIC to finish deploying before it starts:
"dependsOn": [
"[resourceId('Microsoft.Network/networkInterfaces', 'VM1-nic')]"
]
The correct function here is resourceId() — not reference() (which retrieves runtime output values of a deployed resource) and not union() (which merges objects).
The storageProfile section of a VM resource uses imageReference to specify the OS image. The correct sub-property name is imageReference — not image, not Array, and not vhd. The vhd property is for unmanaged disk deployments (legacy); managed disk and Marketplace image deployments use imageReference.
ARM Deployment Cmdlets — Scope Determines the Cmdlet
The PowerShell cmdlet used to deploy an ARM template depends entirely on the deployment scope — where the template is being deployed to. Using the wrong cmdlet for the scope will fail, most commonly when a template creates resource groups (a subscription-level operation) but the deployment is attempted with the resource-group-level cmdlet.
| Scope | PowerShell Cmdlet | When to Use |
|---|---|---|
| Resource Group | New-AzResourceGroupDeployment | Template deploys resources INTO an already-existing RG. Requires -ResourceGroupName. |
| Subscription | New-AzDeployment | Template creates resource groups or deploys subscription-level resources. Use when template type is Microsoft.Resources/resourceGroups. |
| Management Group | New-AzManagementGroupDeployment | Policies, blueprints at MG scope. |
| Tenant | New-AzTenantDeployment | Root tenant scope deployments. |
If an ARM template contains a resource of type Microsoft.Resources/resourceGroups — meaning the template itself creates resource groups — you must use New-AzDeployment (subscription-scope). Using New-AzResourceGroupDeployment will fail because it requires the target RG to already exist, and it cannot deploy subscription-level resources. The cmdlet New-AzResource creates individual resources, not deployments. New-AzTenantDeployment is for the root tenant scope, not subscription.
Bicep Templates — Idempotency, Parameter Functions & Subnet Validation
Bicep is a declarative DSL for deploying Azure resources that compiles to ARM JSON. Like ARM templates, Bicep deployments are idempotent — re-deploying the same template produces the same result without errors, even if the resource already exists. Several Bicep expressions are commonly misread, particularly the distinction between the resource name and its deployment location.
name: 'VNET1'— a string literal; the resource name is always "VNET1" regardless of where it is deployed or any parameters.location: resourceGroup().location— a dynamic function that returns the deployment resource group's Azure region at deployment time. Not a static value — it changes if the template is deployed to a different resource group in a different region.- The name and location are different fields. The name is not derived from the location — they are independent of each other.
- Subnet validation — two subnets (10.0.0.0/24 and 10.0.1.0/24) within a VNet address space of 10.0.0.0/16 are non-overlapping and both fall within the parent range. Both provision successfully.
- Idempotency — deploying the same Bicep file more than once does not cause an error. Azure compares the desired state to the current state and applies only the differences.
A common misread: "the name of the VNet will be the same as the location of the resource group." This is false. The name is the literal string in the name: field (e.g., 'VNET1'). The location is a region identifier (e.g., 'eastus') returned by resourceGroup().location. They are completely independent fields that happen to both be strings.
ARM Copy Loop — Resource Group Naming & copyIndex() Behaviour
When an ARM template uses a copy loop to create multiple resource groups or storage accounts, the naming pattern and the starting index of copyIndex() determine the exact names produced. The deployment cmdlet's -Location parameter specifies where the deployment metadata is stored, not the location of the resources created by the template.
By default, copyIndex() starts at 0 and increments by 1 for each iteration. A template with "name": "[concat('RG', copyIndex())]" and "count": 4 creates resources named RG0, RG1, RG2, and RG3 — not RG1 through RG4. The first resource always has index 0 unless an offset is specified: copyIndex(1) starts at 1.
When running New-AzDeployment -Location "eastus" -TemplateFile deploy.json, the -Location parameter specifies where the deployment operation record is stored in Azure (the deployment metadata). It does NOT determine the location of resource groups or resources created by the template — those are specified within the template itself (e.g., "location": "westus"). If the template hardcodes "location": "westus", the resource groups will be in West US regardless of the cmdlet's -Location parameter.
Multiple Web Apps — One App Service Plan to Minimise Costs
When deploying multiple Azure web apps, the number of App Service plans required determines infrastructure cost. A single plan can host any number of web apps, and multiple web apps sharing one plan share its compute resources. Minimising the number of plans is therefore the key to minimising costs in a multi-app deployment.
If a deployment template is used to deploy 10 Azure web apps, and all 10 apps share the same Azure region and have compatible operating systems, all 10 apps can be deployed into a single App Service plan. This minimises costs because the plan's compute capacity is shared among all apps rather than paying for 10 separate plan instances. The answer is always to identify the single plan that hosts all apps — not to create one plan per app, which would be the maximum cost approach.
Traffic Manager and Application Gateway provide routing and load balancing at the network level — they are not prerequisites for deploying web apps. The minimum prerequisite before deploying 10 web apps from a template is the App Service plan that will host them. Traffic Manager would be relevant if global load balancing across regions were required, not for a simple 10-app deployment.