ITCertFoundryTechnical training system
AUTOMATION

Terraform on Azure: Provider Setup and First Resource

Configure the AzureRM provider, authenticate safely, and apply your first Terraform-managed resource.

The provider block

terraform {
  required_providers {
    azurerm = {
      source  = "hashicorp/azurerm"
      version = "~> 3.0"
    }
  }
}

provider "azurerm" {
  features {}
}

Authenticating to Azure

The simplest path for local development: install the Azure CLI, run az login once to authenticate interactively in a browser, and the AzureRM provider automatically picks up that session — no keys to manage by hand.

For automated pipelines (CI/CD), use a service principal instead: az ad sp create-for-rbac generates credentials that get passed via environment variables (ARM_CLIENT_ID, ARM_CLIENT_SECRET, ARM_SUBSCRIPTION_ID, ARM_TENANT_ID) rather than typed into any .tf file.

A first real resource

resource "azurerm_resource_group" "example" {
  name     = "itcertfoundry-example-rg"
  location = "East US"
}

The actual workflow

terraform init
terraform plan
terraform apply
terraform destroy

Azure-specific things that trip people up

Almost everything in Azure has to live inside a resource group first — plan to create that resource before anything that depends on it, and reference it by name rather than hardcoding the group twice.

Azure region names are inconsistent about spacing and casing across the portal, CLI, and Terraform docs ("East US" versus "eastus") — always copy the exact string Terraform's provider docs expect rather than guessing from the portal.

Guardrails worth having from day one

Run terraform plan and read it before every apply, same discipline as any other cloud provider — Azure billing surprises are just as real as AWS ones.

Move state to a remote backend (azurerm storage account backend is the native pattern) as soon as more than one person or one pipeline touches the same infrastructure.

Real scenarios you'll actually face

"terraform apply fails immediately with a resource-group-not-found error, even though I defined the resource group right there in the same file." Terraform builds its dependency graph from resource references, not from the order things are written in the file — if a resource references the group by a hardcoded name string instead of `azurerm_resource_group.example.name`, Terraform has no way to know it needs to create the group FIRST. Reference the actual resource attribute, not a copy-pasted string of its name, and the ordering resolves itself automatically.

"The pipeline's Terraform run fails with an authentication error, but it works fine from my own laptop." Your laptop is using your interactive `az login` session; the pipeline has no browser to log in with and needs its own identity — a service principal with its own client ID/secret passed via environment variables. A missing or expired `ARM_CLIENT_SECRET` in the pipeline's environment is the most common cause, and it's easy to miss specifically because local testing never exercises that code path at all.

"An apply partially completed, then failed, and now I'm not sure what state everything is actually in." Terraform applies resources according to its dependency graph, and a failure partway through leaves everything created up to that point correctly recorded in state, and everything after it not yet created — it's not silently broken, it's honestly incomplete. `terraform plan` immediately after a partial failure shows you exactly what's left to create; running `terraform apply` again is usually the correct next step, not a state teardown, since Terraform will simply pick up where it actually stopped.

OFFLINE OPTION

Want a printable copy?

This complete guide is also available as a professionally formatted PDF.

Download PDF ↓