I've recently been discussing the merits of different Azure deployment processes with my colleagues, particularly debating the trade-offs of using Azure Resource Manager Templates (aka "ARM"), versus script-based approaches based on Azure CLI or PowerShell CmdLets.

There has been good debate online too. I'm not going to replicate the arguments here except to summarise the general consensus is that ARM can be frustratingly fiddly and verbose. So, why bother with it at all?

Let me start by saying that I'm still a fan of ARM: it brings a handful of unique benefits to the table, and you need to consider them carefully before you choose a different approach.

Some background

First though, it's probably worth setting some context about what "good" looks like. While there are many ways to skin the proverbial cat, I like to stick as close as possible to vendor tooling, remaining as supported as possible while positioning myself to benefit from the compatibility improvements and efficiencies that come from a single technology supplier.

For the purposes of this post, I'm thinking about this topic in terms of Azure Subscriptions, tooling provided by Azure DevOps, and cloud-native apps based mainly on PaaS offerings (functions, APIs, web apps). If you have your own preferred tools or frameworks to orchestrate your deployments then you're likely to have different concerns and priorities.

That aside, here's how I like to set things up:

  • Actual people get Reader access only to Azure subscriptions.
  • An Azure DevOps Service Principal is the only thing that can deploy to a subscription.
  • Deployments are performed by Azure DevOps using source-controlled code, so there's always an audit of what is deployed in which environment, any when it was deployed.
  • Resources are treated as immutable infrastructure, and aren't changed manually once the're deployed. This means that between IaC and data backups I'm always able to restore to a known "good" state.
  • Environment verification is performed using simple scripts, though I'm working on a more comprehensive test framework to enable a unit-test-like experience for validating Azure environments.

This is a pretty standard "least privilege" setup with clear verification, audit points, and responsiblities. Done right, it minimises the need for complex disaster recover scenarios because all resources have a defined, limited lifecycle. If you have a recovery scenario, you reprovision the environment/system/app from scratch and restore your "last known good" data backup.

Mostly ARMless?

So, should I have mostly scripts in my source control, or ARM templates? There are a handful of small benefits that push me toward using ARM rather than a scripted approach, despite how verbose it can be.

  1. ARM is declarative: it describes how an environment should be once deployed. This means that the desired outcome is machine readable.

  2. Being machine readable enables better static analysis of environment definitions. For example, visualising the output of a template before it is executed.

  3. Being machine readable ensures a strict and predictable format which makes it easier to create tooling to reliably orchestrate, verify, and reuse ARM templates, both from third-parties and the vendor. See for example Azure Blueprints.

  4. ARM allows parallelisation during deployment without complex code or manually developed orchestration. This is particularly useful when you're managing large numbers of resources.

  5. Because ARM is a data structure (with very limited macro capabilities), it is easy to sandbox. It cannot be executed. As a result, I'm not giving an attacker an admin command prompt when I go to deploy a JSON file, as opposed to running a CLI or PowerShell script.

This latter point is summarised in the diagram below:

service-provider-model

For scenarios where I or my customer intend to deliver services (to internal or external parties) I need a carefully designed multi-tenant cloud architecture. Tenants should not be able to interfere with one another, nor should they be able to compromise the service I'm providing.

This "service provider model" is a common operational model, either through an central IT function or cloud competency delivering capability to a wider organisation, or a standalone organisation delivering specific managed services to external customers.

While there are many, many ways for a service provider to interact with those third-parties to provide control and management, ARM offers a handful of critical benefits that make it an ideal building block for meeting complex management scenarios that those organisations often face.

To sum up

Reality is more complex than the simplistic "either/or" suggested by the title of the article. ARM vs Scripting is a false dichotomy, if you're in the field for very long then you're going to need both at some point.

I use PowerShell and CLI daily where I need it, but ARM is still where I go to create my reusable architecture building blocks.

Title image credit: Max LaRochelle