The azurerm provider is the Terraform plugin that calls the Azure Resource Manager (ARM) API. This guide walks through the spots people stumble on in practice — authentication methods, switching subscriptions, defaulting tags and regions — together with what the Associate exam expects.
This article assumes stable, documented behavior. Version-dependent features are called out where relevant, and we recommend verifying them in a sandbox environment.
The azurerm provider is the component Terraform uses to create, update, and delete resources via Azure Resource Manager (ARM). Terraform core handles declaration, dependency resolution, and diff computation, while the provider performs the actual API calls.
In production, always pin the version with required_providers and explicitly include features {} in the provider block. features is a required empty block for azurerm — remove it and init fails. By default the provider also auto-registers ARM Resource Providers (Microsoft.Compute, etc.). When your org's guardrails forbid auto-registration, use skip_provider_registration.
Relationship between Terraform and the azurerm provider, including the auth flow (conceptual)
Minimal configuration (version pinning, features, and controlling registration skip)
terraform {
required_version = ">= 1.5.0"
required_providers {
azurerm = {
source = "hashicorp/azurerm"
version = "~> 3.100"
}
}
}
provider "azurerm" {
features {}
# 事前にRP登録済みなら true を検討
# skip_provider_registration = true
}
azurerm supports several authentication methods. Choose by execution environment: Azure CLI for local development, Managed Identity for runners hosted on Azure, and secretless federation (OIDC) or Service Principals for CI/CD.
Using environment variables (ARM_CLIENT_ID, etc.) keeps secrets out of the provider block. OIDC federation includes version-dependent settings, so check the option names against the official docs for the version you're using.
| Auth Method | Typical Use Case | Strengths | Caveats |
|---|---|---|---|
| Azure CLI | Developer machines and Cloud Shell | Minimal setup, instant to try | Generally not recommended for CI; depends on the executing user's context |
| Managed Identity | Azure VM/VMSS, ACI, Functions, Pipeline Agents, etc. | No secrets, no rotation needed | Requires proper RBAC on the executing resource; not usable off-Azure |
| Service Principal (secret / certificate) | Widely used across CI/CD systems | Stable behavior, easy to least-privilege | Requires secret management and rotation; watch for expiration |
| OIDC Federation | Modern CI like GitHub Actions or Azure DevOps | Secretless, secure, and low operational overhead | Provider-version-dependent options; create the Federated Credential on the SP beforehand |
Representative authentication examples
# 1) Azure CLI を利用
provider "azurerm" {
features {}
use_azure_cli = true
}
# 2) Managed Identity(システム割り当て)
provider "azurerm" {
features {}
use_msi = true
subscription_id = var.subscription_id
tenant_id = var.tenant_id
}
# 3) Service Principal(環境変数で供給)
# export ARM_CLIENT_ID=... ARM_CLIENT_SECRET=... ARM_TENANT_ID=... ARM_SUBSCRIPTION_ID=...
provider "azurerm" {
features {}
}
# 4) OIDC(フェデレーション)
# バージョンによりオプション名が異なるため公式を要確認
# 例: use_oidc = true, oidc_token_file_path = var.oidc_token_file_path など
For deployments that span multiple subscriptions, use provider aliases. The safest pattern is to isolate subscription_id, tenant_id, and the auth method per alias, then explicitly declare the provider on each resource.
Frequently swapping the Azure CLI account context within a single run is a recipe for flakiness. In CI, define aliases up front and pick between them explicitly during plan/apply.
Multi-subscription deployment using aliases
provider "azurerm" {
alias = "hub"
features {}
subscription_id = var.hub_subscription_id
tenant_id = var.tenant_id
use_azure_cli = true
}
provider "azurerm" {
alias = "spoke"
features {}
subscription_id = var.spoke_subscription_id
tenant_id = var.tenant_id
use_azure_cli = true
}
resource "azurerm_resource_group" "rg_hub" {
name = "rg-hub-shared"
location = var.location
provider = azurerm.hub
}
resource "azurerm_resource_group" "rg_spoke" {
name = "rg-spoke-app"
location = var.location
provider = azurerm.spoke
}
The standard pattern is to centralize the region in variables and codify naming in locals. This makes reviews easier, and the exam rewards the same reproducibility and readability.
azurerm supports default_tags at the provider level. default_tags and per-resource tags are merged, and when keys collide the resource value wins. This is great for cross-cutting tag propagation and governance.
features.resource_group.prevent_deletion_if_contains_resources blocks accidental deletion of resource groups that still hold resources (the default can vary by version, so it's best to set it explicitly with clear intent).
Patterns for location, naming, and default tags
variable "location" {
type = string
default = "japaneast"
}
variable "env" { type = string }
variable "owner" { type = string }
locals {
name_prefix = lower(join("-", [var.env, "app01"]))
rg_name = "rg-${local.name_prefix}"
}
provider "azurerm" {
features {
resource_group {
prevent_deletion_if_contains_resources = true
}
}
default_tags {
tags = {
environment = var.env
owner = var.owner
}
}
}
resource "azurerm_resource_group" "main" {
name = local.rg_name
location = var.location
tags = {
# 同じキーがある場合はこの値が優先される
owner = var.owner
}
}
When Resource Provider auto-registration is blocked, certain resource creations fail with 404 or AuthorizationFailed. Setting skip_provider_registration = true doesn't always solve the root cause, so your operational design should pick a clear lane: pre-register, or allow auto-registration.
With Service Principals, the classic failures are expiration and insufficient permissions. Watch for cases where Contributor isn't enough (Key Vault data plane, for example). Azure CLI auth depends on the current az account set subscription, so it's not recommended for CI.
Isolate failures by cross-checking Terraform debug logs against ARM error messages. Reproduce with plan first; on retries, tuning -parallelism can sidestep transient throttling.
Environment variables and logs for debugging
# Service Principal(シークレット)の例
export ARM_CLIENT_ID=00000000-0000-0000-0000-000000000000
export ARM_CLIENT_SECRET=********
export ARM_TENANT_ID=11111111-1111-1111-1111-111111111111
export ARM_SUBSCRIPTION_ID=22222222-2222-2222-2222-222222222222
# 詳細ログ(必要な時だけ)
export TF_LOG=TRACE
export TF_LOG_PATH=./terraform.trace.log
# Azure CLI の現在サブスクリプションを明示
az account set --subscription $ARM_SUBSCRIPTION_ID
The azurerm backend is separate from the provider — it's declared in the terraform block's backend section. State is stored in an Azure Storage blob, and locking is implemented via blob leases.
For CI, pre-provision the backend resource group, storage account, and container with IaC, and grant access via Azure AD (preferred) or SAS. Enabling versioning and soft delete on the container (the bucket-equivalent) makes recovery easy.
azurerm backend example (declared in the terraform block, not in provider)
terraform {
backend "azurerm" {
resource_group_name = "rg-tfstate"
storage_account_name = "sttfstate1234"
container_name = "tfstate"
key = "${terraform.workspace}.tfstate"
}
}
# 認証は実行環境に依存(例:az login、Managed Identity、ARM_* 環境変数)
Associate
問題 1
Your organization deploys to two Azure subscriptions (hub and spoke) simultaneously with different RBAC. Which is the recommended approach to switch the target per resource with minimum risk?
正解: A
Splitting concurrent multi-subscription deployments via provider aliases is the safest and most reproducible approach. Declaring the provider on each resource locks in the target regardless of runtime context or CLI state. Swapping subscription_id directly on resources isn't a common pattern, and manual CLI switching introduces instability. Varying only tenant doesn't satisfy the requirement either.
Why is the features block required? Do I still need it if it is empty?
The azurerm provider expresses internal feature toggles through the features block during initialization. Even when empty, the block is required by spec, and omitting it causes an error at init time.
When default_tags and per-resource tags conflict, which wins?
When the same key exists in both, the resource-level tags win. The practical pattern is to put org-wide defaults in default_tags and override exceptions on the resource itself.
Should the azurerm backend be configured inside the provider block?
No. The backend is declared in the terraform block's backend section, independent of the provider. It specifies state storage and locking, which is a different role from the provider that drives API calls.
Practice with certification-focused question sets
無料で問題を解いてみるNicheeLab Editorial Team
NicheeLab editorial team focused on data engineering and cloud certification learning. Content is structured around practical study needs and official exam domains.
HCL Syntax: Terraform's Configuration Language (2026)
HCL2 fundamentals for Terraform — blocks, attributes, expres...
Terraform Authoring & Operations Pro: Complete Guide (2026)
Tactics for the Terraform Pro exam — module authoring, works...
Terraform Providers: Plugin Management Fundamentals (2026)
Provider mechanics — required_providers, versions, mirrors, ...
Terraform Resource Blocks: Declarative Infra Units (2026)
Resource block fundamentals — addresses, references, common ...
Terraform Data Sources: Read-Only External Data (2026)
Data source basics — declaration, refresh behavior, dependen...