Automate Azure Infrastructure with ARM Templates: Step-by-Step Guide
VMoreCloud › Microsoft Azure › Infrastructure as Code › Automation
MICROSOFT AZURE • ARM TEMPLATES • INFRASTRUCTURE AS CODE

Automate Your Azure Infrastructure with ARM Templates

Learn how to define Azure resources as reusable JSON infrastructure code, validate your template, preview deployment changes, and deploy a storage account using Azure CLI.

Author: Khurram Shahzad
Platform: Microsoft Azure
Technology: ARM / Azure CLI
Level: Beginner–Intermediate
Format: Hands-on tutorial
Reading Time: 12–15 minutes

Make Azure Deployments Repeatable and Consistent

ARM templates let you describe the Azure infrastructure you want in a declarative JSON file. Keep the definition in source control, review changes before deployment, and use the same pattern to build consistent development, test, and production environments.

ARM
JSON
What this tutorial coversYou will create a simple ARM template for an Azure Storage account, parameterize its name and location, validate the template, preview its changes with Azure CLI what-if, deploy it to a resource group, and verify the result. Commands are written for Bash, including Azure Cloud Shell’s Bash environment.
01

Infrastructure as Code

Define resources and their configuration in a version-controlled JSON file.

02

Preview Before Deploying

Use validation and What-If to identify issues and review expected changes.

03

Repeatable Deployments

Deploy consistent resource configurations through a documented workflow.

Introduction

Cloud infrastructure often needs to be recreated across multiple environments or updated in a controlled way. Creating each resource manually in the Azure portal can be slow, difficult to audit, and prone to configuration differences. Infrastructure as Code (IaC) addresses this problem by storing infrastructure definitions as code that can be reviewed, reused, and deployed consistently.

Azure Resource Manager (ARM) templates are JSON files that describe the resources and configuration for an Azure solution. Instead of writing a sequence of commands for every resource, you declare the intended state and let Azure Resource Manager coordinate the deployment. Microsoft also recommends considering Bicep for new authoring because it offers the same Azure deployment capabilities with a more concise syntax; ARM JSON remains useful for existing templates and scenarios that require the JSON format. Read Microsoft’s ARM template overview.

Example scenarioA team needs a consistently configured storage account for each application environment. A parameterized template allows the team to reuse one resource definition while supplying environment-specific values at deployment time.

What Are Azure Resource Manager (ARM) Templates?

An ARM template is a declarative JSON document describing Azure resources, their properties, dependencies, parameters, variables, and optional outputs. Azure Resource Manager interprets the template and deploys resources at the selected scope.

Template elementPurposeExample in this tutorial
$schemaIdentifies the template schema.Resource-group deployment schema URL.
contentVersionVersion label for the template content.1.0.0.0
parametersAccepts values supplied when deploying.Storage account name and location.
variablesHolds reusable expressions or values.Not required for this small example.
resourcesDefines the Azure resources to deploy.One StorageV2 account.
outputsReturns useful deployment results.The deployed storage account name.

ARM templates support repeatable deployments and can be deployed using the Azure portal, Azure CLI, Azure PowerShell, REST APIs, or Azure Cloud Shell. For a resource-group deployment, Azure CLI uses az deployment group commands.

Why Automate Azure Infrastructure?

Consistency

Store the desired configuration in one reviewed template instead of relying on a sequence of manual portal steps.

Reusability

Use parameters to customize names, regions, and supported configuration values for different environments.

Change visibility

Review source-control changes and run What-If before deploying infrastructure updates.

Automation pipelines

Integrate validation and deployment into a controlled CI/CD workflow when the team is ready.

Templates do not remove the need for review or governance. A template can still contain incorrect configuration or request changes that are inappropriate for production, so validation, access control, What-If review, and testing remain important.

Prerequisites

  • An Azure subscription where you are permitted to create a resource group and storage account.
  • Azure CLI installed locally, or use Azure Cloud Shell.
  • Permissions to create the target resources and perform ARM deployment operations.
  • A text editor such as Visual Studio Code.
  • A globally unique Azure Storage account name containing only lowercase letters and numbers, between 3 and 24 characters.
Cost and production cautionAzure resources may incur charges. This example creates a storage account, not a complete private production architecture. Review your subscription, region, networking requirements, data classification, and expected costs before deploying. Delete the demo resource group when finished if you no longer need the resources.

How the Deployment Workflow Works

StageActionPurpose
1Write the templateDeclare the desired resource configuration.
2Sign in and select subscriptionTarget the correct Azure context.
3ValidateCheck the template and deployment request.
4Run What-IfPreview expected resource changes without applying them.
5DeployAsk Azure Resource Manager to create or update the resource.
6VerifyConfirm deployment state and resource properties.

Step 1: Create the Project Files

Create a working folder for the template. These examples use Bash syntax and are suitable for Azure Cloud Shell Bash, Linux, or macOS terminals.

mkdir azure-arm-storage-demo cd azure-arm-storage-demo touch main.json

Your project will contain the following file:

azure-arm-storage-demo/main.json

For a larger project, keep templates, parameter files, documentation, and pipeline definitions organized in source control. Do not commit credentials, secrets, or private deployment values to the repository.

Step 2: Create the ARM Template

Open main.json and paste the following complete example. It defines a StorageV2 account with locally redundant storage (LRS), HTTPS-only traffic, TLS 1.2 as the minimum TLS version, and public blob access disabled.

{ "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", "contentVersion": "1.0.0.0", "parameters": { "storageAccountName": { "type": "string", "metadata": { "description": "Globally unique storage account name using lowercase letters and numbers." }, "minLength": 3, "maxLength": 24 }, "location": { "type": "string", "defaultValue": "[resourceGroup().location]", "metadata": { "description": "Azure region for the storage account." } } }, "resources": [ { "type": "Microsoft.Storage/storageAccounts", "apiVersion": "2023-05-01", "name": "[parameters('storageAccountName')]", "location": "[parameters('location')]", "kind": "StorageV2", "sku": { "name": "Standard_LRS" }, "properties": { "supportsHttpsTrafficOnly": true, "minimumTlsVersion": "TLS1_2", "allowBlobPublicAccess": false, "allowSharedKeyAccess": false, "publicNetworkAccess": "Enabled" } } ], "outputs": { "storageAccountName": { "type": "string", "value": "[parameters('storageAccountName')]" } } }

Understand the important settings

  • Parameters: The account name and location can be provided at deployment time, so the template can be reused.
  • StorageV2: Specifies a general-purpose v2 storage account.
  • Standard_LRS: Uses locally redundant storage. Choose a redundancy option appropriate to your resilience requirements.
  • HTTPS and TLS: Requires HTTPS traffic and sets the minimum TLS version to 1.2.
  • allowBlobPublicAccess: false: Disables anonymous public access to blobs at the account level.
  • allowSharedKeyAccess: false: Disables Shared Key authorization. This can break applications that depend on account keys or connection strings; confirm your application supports Microsoft Entra ID authorization before using this setting.
  • publicNetworkAccess: Enabled: The account’s public network endpoint remains enabled. Public endpoint availability is not the same as anonymous blob access. For production workloads, assess network firewall rules, private endpoints, private DNS, and approved access paths.
Important security noteThis is an instructional baseline, not a complete production security design. It does not configure a private endpoint, virtual network rules, diagnostic settings, lifecycle management, or a recovery strategy. Add and review those controls according to your workload requirements.

Step 3: Sign In to Azure

Authenticate with Azure CLI:

az login

If you have access to multiple subscriptions, list them and select the subscription where you intend to create the demo resources.

az account list --output table az account set --subscription "YOUR-SUBSCRIPTION-ID-OR-NAME" az account show --output table

Replace the placeholder with your own subscription ID or exact subscription name. Confirm the displayed subscription before continuing.

Create a resource group

A resource group provides a management boundary for this tutorial’s storage account. Choose an Azure region available to your subscription.

az group create \ --name rg-arm-automation-demo \ --location eastus

The commands in this article use eastus as an example. Change the region if needed. The resource group must exist before you run the resource-group deployment commands below.

Step 4: Validate the Template

Validation checks the deployment request before you create the resource. Run this from the folder containing main.json:

az deployment group validate \ --resource-group rg-arm-automation-demo \ --template-file main.json \ --parameters storageAccountName=REPLACEWITHUNIQUELOWERCASE

Replace REPLACEWITHUNIQUELOWERCASE with a unique storage account name made only of lowercase letters and numbers. For example, do not use the placeholder literally. Storage account names are globally unique across Azure, so a name may already be taken.

If validation returns an error, read the full message. Common causes include invalid JSON, an unavailable or invalid parameter value, an unsupported property, insufficient permissions, or a resource name that does not meet Azure’s requirements.

Expected outcomeA successful validation response indicates that Azure accepted the template and deployment request for validation. It does not guarantee that every later deployment operation will succeed or that the architecture meets your security and compliance requirements.

Step 5: Preview Changes with What-If

Before creating resources, use the What-If operation to preview the changes Azure Resource Manager expects to make. What-If does not apply those changes; it helps you review the deployment plan. Microsoft Learn: ARM template What-If.

az deployment group what-if \ --resource-group rg-arm-automation-demo \ --template-file main.json \ --parameters storageAccountName=REPLACEWITHUNIQUELOWERCASE

Review the result for unexpected updates, replacements, or deletions. A new storage account should appear as a resource to create if the name is available and the deployment request is valid.

Do not skip the review in productionWhat-If is a planning aid, not a substitute for change approval. Its output can contain uncertainty or limitations for complex deployments, and the actual environment may change between preview and deployment. Review the output and confirm the target subscription and resource group before proceeding.

Step 6: Deploy the Template

After reviewing the validation and What-If results, deploy the template:

az deployment group create \ --name deploy-arm-storage-demo \ --resource-group rg-arm-automation-demo \ --template-file main.json \ --parameters storageAccountName=REPLACEWITHUNIQUELOWERCASE

Use the same unique name you used during validation and What-If. Azure CLI submits the template to Azure Resource Manager, which coordinates the resource deployment. The command returns deployment information, including a provisioning state when it completes.

For unattended automation, avoid hard-coding secrets in templates or shell history. Use managed identity or an appropriately secured workload identity for pipelines, and apply least-privilege role assignments to the deployment identity.

Step 7: Verify the Deployment

Check the deployment result:

az deployment group show \ --name deploy-arm-storage-demo \ --resource-group rg-arm-automation-demo \ --query properties.provisioningState \ --output tsv

For a successful deployment, the expected provisioning state is Succeeded. Next, confirm that the storage account exists and review its properties. Replace the placeholder with your deployed name.

az storage account show \ --name REPLACEWITHUNIQUELOWERCASE \ --resource-group rg-arm-automation-demo \ --query "{name:name,location:location,kind:kind,sku:sku.name,httpsOnly:enableHttpsTrafficOnly,publicNetworkAccess:publicNetworkAccess}" \ --output json

You can also list storage accounts in the resource group:

az storage account list \ --resource-group rg-arm-automation-demo \ --output table

Verify the properties that matter to your requirements rather than relying on the existence of the resource alone.

Step 8: Update and Redeploy

One advantage of declarative infrastructure is that you can update the template and redeploy it to move the resource toward the configuration described by the template. For example, if you add a supported tag property or adjust a configuration setting, validate and run What-If again before deploying.

1

Edit the template

Make a small, intentional change in main.json. Keep changes in source control and explain why they are needed.

2

Validate and preview again

Rerun az deployment group validate and az deployment group what-if using the same resource group, template, and parameters.

3

Deploy the reviewed update

Run az deployment group create only after you understand the proposed changes and have the required approvals.

Deployment mode cautionUnderstand the deployment mode and deletion behavior before using it. Do not switch modes or remove resource definitions without reviewing the consequences for existing resources. A deployment template should not be treated as a cleanup command unless that behavior is deliberate and approved.

Security and Best Practices for ARM Templates

  • Use source control. Version templates, review pull requests, and keep a record of approved infrastructure changes.
  • Parameterize environment-specific values. Keep the template reusable and store non-secret environment configuration in parameter files where appropriate.
  • Never embed secrets in template files. Use secure parameters and approved secret-management patterns when a deployment genuinely requires a secret. Prefer managed identities or Microsoft Entra ID-based access when supported.
  • Use least privilege. Give deployment identities only the permissions they need at the narrowest practical scope.
  • Validate and use What-If. Review planned changes before applying them, especially in shared or production subscriptions.
  • Test in a non-production environment. Check resource behavior and application compatibility before broad rollout.
  • Modularize complex templates. Use linked or nested templates and shared components when that improves maintainability.
  • Apply governance. Use Azure Policy, resource locks where appropriate, and approved naming/tagging conventions to support compliance and cost management.
  • Keep API versions and resource settings reviewed. Check current Microsoft resource documentation before adopting a new resource type or API version.
  • Plan networking and data protection. Public network access, private endpoints, logging, backup, retention, and recovery requirements depend on the workload and should be explicitly designed.

Microsoft’s guidance also recommends designing templates around deployment boundaries, using parameters thoughtfully, and testing templates before relying on them in production. See ARM template best practices.

ARM JSON vs. Bicep: Which Should You Use?

ConsiderationARM JSONBicep
SyntaxJSON structure can become verbose for large deployments.More concise domain-specific syntax.
Azure deployment engineDeployed through Azure Resource Manager.Compiled to ARM JSON and deployed through Azure Resource Manager.
Existing estatesUseful for existing JSON templates and integrations.Can be introduced for new modules or gradual migration.
Learning and maintenanceRequires understanding JSON structure and ARM expressions.Often easier to read and maintain for new IaC projects.

For this article, the hands-on example uses ARM JSON because the topic is ARM templates. For a new Azure infrastructure project, evaluate Bicep as well; Microsoft recommends it for a more straightforward authoring experience. Learn about Bicep.

Troubleshooting Common ARM Template Problems

Invalid JSON or template syntax

Check braces, commas, quotation marks, parameter names, expressions, and the file path. Use an editor with JSON validation, then rerun Azure validation.

Storage account name is unavailable

Choose another globally unique name. Use only lowercase letters and numbers and keep the name within the required length.

Authorization failure

Confirm the signed-in identity, selected subscription, resource-group scope, and permissions to create the requested resource and ARM deployment.

Region or SKU not available

Check subscription restrictions, region availability, policy assignments, and the current resource provider documentation.

Validation passes but deployment fails

Inspect the deployment error details. Validation cannot guarantee every runtime or provider operation will succeed.

Application breaks after hardening

Review whether the application relies on Shared Key authorization or public network access. Test security changes against application requirements.

Inspect deployment operations

For additional details about failed operations, list the deployment operations for the resource group deployment:

az deployment operation group list \ --name deploy-arm-storage-demo \ --resource-group rg-arm-automation-demo \ --output table

Check the detailed error message and correct the underlying template, permissions, policy, or resource configuration rather than repeatedly rerunning an unchanged failed deployment.

Optional: Clean Up the Demo Resources

If this was only a learning exercise and you no longer need the storage account, you can delete the dedicated demo resource group. This deletes the resources contained in that group, so verify the name carefully before running the command.

az group delete \ --name rg-arm-automation-demo \ --yes \ --no-wait
Destructive actionDo not run this command against a production resource group or any group containing resources you want to keep. Resource deletion can cause data loss and service interruption.

Frequently Asked Questions

What is an Azure ARM template?

An ARM template is a declarative JSON file that defines Azure resources and their configuration for deployment through Azure Resource Manager.

Can ARM templates automate Azure infrastructure?

Yes. Templates describe the desired resources and can be validated, previewed, and deployed through Azure CLI, Azure PowerShell, the Azure portal, REST APIs, or Azure Cloud Shell.

Does What-If create or change Azure resources?

No. What-If previews expected changes without applying them. It should be used alongside validation, review, and appropriate change controls.

Should I use ARM JSON or Bicep for a new project?

ARM JSON remains supported and is useful for existing templates. Microsoft recommends considering Bicep for new authoring because its syntax is more concise while deploying through Azure Resource Manager.

Can I use ARM templates in CI/CD pipelines?

Yes. Teams can integrate template validation, What-If review, approval gates, and deployment into Azure DevOps or other CI/CD systems. Secure the pipeline identity and use least privilege.

Do ARM templates automatically make my resources secure?

No. Templates automate the configuration you define, but the design must still address identity, networking, encryption, monitoring, backup, compliance, and application compatibility.

Why does my storage account deployment fail?

Common reasons include a globally unavailable name, invalid template syntax, unsupported properties, insufficient permissions, Azure Policy restrictions, or region/SKU limitations. Inspect the deployment error for the exact cause.

Will deploying the same template always create a new resource?

Not necessarily. ARM templates are declarative; repeated deployments generally seek to bring resources to the state described by the template. The result depends on the resource configuration, current state, and deployment behavior.

Conclusion

Azure Resource Manager templates provide a repeatable way to define and deploy Azure infrastructure as code. In this walkthrough, you created a parameterized JSON template for a storage account, signed in to Azure, validated the deployment, previewed changes with What-If, deployed the resource, and verified its state.

For real workloads, treat the template as maintainable infrastructure code: keep it in source control, review changes, use least-privilege identities, validate and preview deployments, and design security and recovery controls for the workload. If you are starting a new Azure IaC project, also evaluate Bicep as a concise authoring option.

Deployment checklistCreate the template → Confirm subscription and resource group → Validate → Run What-If → Review changes → Deploy → Verify the result → Document and clean up the demo resources when no longer needed.

Continue Learning Microsoft Azure

Explore more practical cloud computing, Azure networking, hybrid cloud, Windows Server, backup, and virtualization tutorials on VMoreCloud.

Microsoft Azure • AWS • VMware • Windows Server • Linux • Backup & Disaster Recovery

Sources & Further Reading

KS

Khurram Shahzad

Hybrid Cloud & Virtualization Engineer

Hybrid Cloud & Virtualization Engineer specializing in VMware, Azure, AWS, Windows Server, Microsoft 365, Linux, networking, backup & disaster recovery. I share practical guides, technical projects and insights into modern IT infrastructure through VMoreCloud.

Technical note: Azure resource properties, supported API versions, permissions, regional availability, and CLI behavior can change. Review current Microsoft Learn documentation and test deployments in a non-production subscription before using a template for critical workloads. This tutorial is educational and is not a claim that the commands were executed in your Azure tenant.

Leave a Reply

Your email address will not be published. Required fields are marked *