Azure Infrastructure as Code

Azure Resource Manager

Before diving into Azure Resource Manager (ARM) templates and Terraform, let's briefly look into what ARM is and how important it is to the deployment and management of resources in Azure. ARM provides a consistent layer through which you create, update and delete resources in Azure. Through ARM, you can also manage security, access control, locks and tags of your resources.

Imagine you want to create a virtual machine in your subscription. When you submit a request for the VM to be created, Azure Resource Manager first performs authentication and authorisation to ensure that the request is coming from a valid user and that the user has the authorisation to create a VM in the given subscription. Once authentication and authorisation are complete, the request is passed to the VM service which in turn will create the requested VM. Updates or delete requests for the VM also follow the same path.

To submit a request to Azure Resource Manager, one can use Azure portal, REST API endpoints, Azure Command Line Interface (CLI) or Azure PowerShell. Because all requests go through ARM, you get a consistent result no matter what tool you use to submit your request. Microsoft has done a great job ensuring that Azure Portal, CLI, PowerShell and REST API offer the same capability.

A newcomer to Azure trying out a few things might find the portal more user-friendly and can quickly get results without a steep learning curve. However, as soon as one gets past the initial stages of introduction to Azure, the Portal's limitations are easily exposed. The portal, in itself, is not limited but it limits the user. Let's look at some scenarios where Azure Portal limits the user:

  • Recreating resources: when you create a resource through the portal, you need to go through the same steps again if you want to create similar resources e.g. additional VMs.

  • Reproducing environments: your pilot in a DEV subscription has worked like a charm and you want all the resources in that environment to be recreated in a Test environment. You will need to manually recreate each resource manually.

The above two scenarios sound very much like an on-prem environment setup; you buy servers for your dev environment, set them up and check everything works as expected. Repeat the steps for your test, UAT, PROD and DR. The appeal of the Cloud for most organisations is to reduce the Total Cost of Ownership (TCO). The ability to get resources at a click of a button (a resource with exact same specification all the time!) reduces the cost of setting up new hardware to match the existing one.

Infrastructure as Code (IaC)

Azure enables developers to describe their infrastructure in form of code. This code can then be deployed and redeployed with the same result. Developers are familiar with the DRY principle and IaC guarantees that DRY is adhered to. You can define your entire infrastructure (VMs, Storage, Service Bus, Azure Cache for Redis, Web Apps etc) and deploy it to your dev subscription. When ready to create that infrastructure in your Test environment, at the press of a button you will get the exact copy of your dev infrastructure in Test. Any serious infrastructure setup and maintenance will use continuous delivery (CD) for deploying resources similar to CI/CD for deploying software. Microsoft provides an Azure DevOps platform for creating and running your infrastructure deployment pipeline. Other tools out there can also be used including GitLab and GitHub.

ARM templates

To implement Infrastructure as Code, you use ARM templates. A template is a declarative language using JSON or Bicep syntax to define Infrastructure. There are plenty of examples of templates for different resources on the web. If you are trying out ARM templates for the first time, bear in mind that templates adhere to a defined schema and most examples on the web are based on older versions. If you are copying snippets from one example to another, ensure that they are from the same version of the schema you are using otherwise you may get errors.

A template can have five sections:

  1. Parameters: they provide placeholders for values that you can pass at runtime and are not hard coded. For example, a VM name is a candidate for parameterisation otherwise every time you want to create a new VM you will need to change your template. You can parameterise as much or as little as you want. You may want to provision low-specification VMs in the dev/test environments and high-specification ones in prod. By parameterising the VM spec, you will not need to change your template when deploying to these two environments - you just pass different parameter values.

  2. Variables: variables generate values at runtime usually by combining one or more parameters with other values. For example, if you wanted your VM name to include environment, you may create a variable that combines the name and environment parameters.

  3. User-defined functions: you can use this section to combine multiple standard functions into a complicated function.

  4. Resources: this is the section where you define all the resources you want to deploy.

  5. Output: this section is used to display output at the end of template deployment.

At first, ARM templates could only be defined using JSON syntax. Microsoft later developed Bicep as an alternative and more concise language. I can see developers preferring Bicep to JSON as the former would feel natural to a developer. Let's look at an example to demonstrate how concise Bicep is compared to JSON syntax:


"parameters": {
    "vnetName": {
        "type": "string",
        "defaultValue": "myCoolVnet"


param vnetName string = 'myCoolVnet'

The above snippets are both defining a string parameter and assigning a default value.


Terraform is an open-source tool developed by HashiCorp. It uses HashiCorp Configuration Language (HCL) to declaratively define Infrastructure as code. Terraform takes the idea of having a predictable and repeated IaC further than ARM templates.

Imagine you are experimenting with Azure. You have your IaC scripted in ARM templates and then suddenly you want to experiment with Amazon Web Services (AWS). How do you redeploy what you have in Azure to AWS? Terraform is a multi-cloud IaC language that allows the deployment of the same infrastructure to different cloud providers.


Infrastructure as Code is a powerful concept. It enables organisations to deploy and maintain infrastructure predictably and consistently. Using IaC, organisations can deploy resources to different environments or regions with little overheads. Azure provides ARM templates that use JSON or Bicep syntax as a solution. HashiCorp provides Terraform as a cross-cloud IaC tool that supports most of the major Cloud platforms.