INSIGHTS
Certifications & Exams

AZ-104: Bicep and ARM Deployment Decisions

Use Azure Resource Manager and Bicep safely: understand deployment scopes, parameters, dependencies, what-if and controlled changes.

In this article
  1. Understand declarative intent and Azure resource state
  2. Match the deployment scope to the resource type
  3. Parameterize real environment differences
  4. Treat dependencies and outputs as operational contracts
  5. Preview changes with what-if before committing
  6. Make rollback a property-specific plan
  7. Investigate deployment failures at the right level
  8. Work a realistic administrator deployment lab

A deployment that works when clicked through the portal can fail when repeated for a new region because configuration has drifted. An ARM template or Bicep file describes the desired Azure resource configuration so an operator can reproduce it, review it and track changes. The AZ-104 exam expects administrators to understand both the resource model and the practical deployment process; it is not exclusively a developer exercise.

The hard part is rarely typing a Bicep keyword. It is knowing which scope is being modified, which permissions are required, which values should be parameters, and what an apparently harmless update could do to a live storage account, virtual network or application. These are production administration decisions.

Understand declarative intent and Azure resource state

Resource Manager uses a declarative representation of resources and their properties. A Bicep file compiles to an ARM template and expresses the intended result in more compact syntax; Azure performs the deployment. That differs from a long imperative script that calls ‘create’ commands in order and hopes prior actions succeeded.

Declarative does not mean risk-free. Changing a resource property can trigger a restart, redeployment or replacement depending on the resource provider and property. A deployed environment also contains resources beyond the current file’s scope, including those managed by other teams. Know the resource ownership boundary before assuming a deployment will be isolated. Bicep modules can group related parts of a solution without making service dependencies disappear.

An ARM/Bicep deployment is a declaration about desired resource configuration, not an imperative script telling Azure to click portal fields in a fixed order. For a storage account, the template can describe the resource type, location, SKU and security settings, while Azure Resource Manager evaluates dependencies and provider constraints. Running the deployment twice against the same scope should converge on the described state for the declared properties. This does not mean every operation is harmless or that deleting a declaration necessarily deletes the existing resource; understand the selected deployment mode and supported deployment-stack behavior rather than importing assumptions from a different infrastructure tool.

Match the deployment scope to the resource type

A Bicep file can target a resource group, subscription, management group or tenant, but resources have supported scopes and deployment commands differ. A resource-group deployment typically creates or updates workload resources; subscription deployments often establish groups and certain governance objects. The identity executing a deployment needs authority at the actual target scope, not merely permission to read the Bicep source file.

Consider an application release requiring a new resource group and an App Service within it. Deploying everything under one resource-group-scope file may not be the most straightforward design because the group is the scope itself. Use suitable orchestration or modules with intentional scopes. Check tenant and subscription selection explicitly in automation; deploying to the wrong subscription is often harder to undo than a syntax error.

Subscription-level scope is appropriate for creating a resource group or assigning supported subscription objects. A workload’s storage and compute typically deploy at resource-group scope, while some governance resources target management groups. The deployment identity needs permission at the destination scope, including any required role-assignment operations. Do not grant a workload pipeline subscription Owner just because one bootstrap operation fails; separate high-privilege platform bootstrap from low-privilege application deployment. For a multi-scope change, record which identity deploys each module and which resources belong to each scope, so a failed platform assignment cannot leave the application in an ungoverned state.

Parameterize real environment differences

Parameters represent values that legitimately differ between deployments, such as region, environment label, instance size or an existing VNet identifier. Avoid turning every property into a parameter; excessive flexibility makes a file difficult to review and increases the chance of incompatible combinations. Secure values should use appropriate secure parameter handling and a secret store where needed, not plain text in a checked-in parameter file.

An environment-specific file can declare a production SKU while a development file uses a lower-cost option, but both should preserve the same fundamental security posture. Validate defaults carefully: a network access default that is acceptable for an isolated lab may be dangerous in production. Define what must remain invariant across environments, and encode those expectations in review and policy checks.

A good parameter file varies values that legitimately change between development and production: environment name, region, instance size and perhaps network allocation. It should not make secrets, arbitrary role scopes or public exposure convenient knobs with unsafe defaults. Put sensitive values in an appropriate secret store or secure parameter mechanism, and validate parameter constraints. Consider a plan that tests in West Europe but deploys to North Europe: region support, resource availability, quotas and naming restrictions can differ, so ‘same template’ is not proof of identical runtime capability. Deployments require an environmental acceptance test, not only syntactically valid input.

Treat dependencies and outputs as operational contracts

Bicep supports symbolic references and dependencies between Azure resources. A subnet must exist before a resource referring to it can be configured; a managed identity may need a permission assignment before it can access a vault. Explicit dependencies are useful where the platform cannot infer order from references, but adding arbitrary waits is a warning that the deployment structure needs investigation.

Outputs can reveal generated resource identifiers or endpoints for downstream automation. Keep sensitive output out of general build logs; an output is not a secret-management service. After the deployment, verify the application-relevant outcome: a VM with the expected identity, a subnet with the correct NSG, a storage account with the intended network settings. A successful template operation is not a substitute for functional validation.

Preview changes with what-if before committing

The Resource Manager what-if operation predicts resource-level changes without making them. It can show which properties are expected to change and whether a resource might be created or removed. Review the preview for destructive or security-relevant effects, and require a second review for production changes with broad impact. What-if has documented limitations involving dynamic expressions, runtime references and external resources; a clean preview is useful evidence but not an absolute guarantee.

Suppose an update changes a storage account’s redundancy type while a separate release alters its firewall rules. Ask which file owns those properties and whether the deployment is based on stale expectations. Record the preview and compare it to the final deployment operation. Production change control should reveal how the actual result differed from what-if, not merely that a command exited successfully.

Use what-if to ask a concrete question: which resources and properties are expected to change if this Bicep file is deployed now? Read the proposed modifications and deletions, then compare with an approved change request. A what-if result may include changes due to resource-provider responses or unsupported property detail; reconcile surprising output before applying it. For a production network security group, replacing a rule or association can change traffic before a VM is touched. This is why change review should focus on dependency and impact, not simply on whether the template successfully compiled.

Make rollback a property-specific plan

Rolling back Bicep source code does not always reverse a service operation. If a template deletes a resource or performs a change with data-loss implications, restoring an older file can be insufficient. Decide how to recover content, network access and application behavior for the particular change. Preserve deployment history, but understand that deployment-history entries are not full backups of application data.

For risky changes, separate infrastructure configuration, migration and data cutover. A storage endpoint change may require clients to switch DNS or connection strings; a virtual-network change can interrupt reachability. Prepare tests for each boundary, an operator to approve the cutover and a clearly defined stop condition. The objective is to make configuration reproducible while still respecting the runtime system.

Investigate deployment failures at the right level

A deployment can fail because of missing permissions, resource-provider registration, incorrect region or SKU availability, policy denies, quota limits or inconsistent template expressions. Start with the specific deployment operation and inner error details. Do not automatically grant the deployment identity Owner at subscription scope to quiet an authorization message.

If a storage-account deployment receives a policy error, inspect the relevant assignment and parameters. If a VM is rejected because a size is unavailable in the selected zone, verify SKU and capacity constraints before altering the template’s dependency graph. Errors name different layers of the system; keep their causes separate. Log the target subscription, resource group, template revision, parameter values without secrets and deployment correlation ID.

Troubleshoot by first reading the Azure Resource Manager deployment operation and its nested error, not by re-running the entire template. AuthorizationFailed indicates an identity/scope issue; RequestDisallowedByPolicy indicates an assigned governance rule; regional SKU availability and quota failures require capacity or region review. A failed dependent resource may obscure the original failure in an upstream operation. Capture the correlation ID, subscription, scope, template version and parameters. Fix the cause in source control, evaluate with what-if and rerun a disposable or staged deployment. Manual portal patches that aren’t reflected in the template create silent drift on the next release.

Work a realistic administrator deployment lab

Create a small Bicep file that defines a storage account and a VNet with parameters for region and resource naming. Run a what-if preview against a disposable group, deploy, then change one harmless property and compare the reported difference. Intentionally choose a disallowed configuration in a lab governed by a test policy so you can inspect the denial without affecting production.

Finally, remove test resources through an explicitly reviewed operation and inspect the deployment history. Record the differences between successful template validation, successful resource deployment and working application connectivity. The AZ-104 lesson is not to memorize template syntax in isolation; it is to operate declarative Azure changes with the correct scopes, identities, evidence and rollback strategy.

In a training subscription, create one small storage account and a resource group through appropriate deployment scopes. Export the ARM representation, identify the API version, dependencies and parameters, then express the same resource in Bicep where appropriate. Use what-if to predict a harmless tag change and confirm the deployed state afterward. Trigger a policy deny or quota issue only in a disposable environment and capture the failure code. Finally, remove the test deployment in a controlled way, checking whether any protected data or resources must be retained. The evidence should include both predicted and actual changes rather than screenshots of a successful deployment button.

Filed under Certifications & Exams