Virtual Event
Join us for the next HashiConf Digital October 12-15, 2020 Register for Free

Get Started - Azure

Write Configuration

This getting started track is intended to help you quickly learn the fundamentals of Terraform and the Azure Provider. After completing the tutorial, you'll know how to author a basic Terraform configuration for Azure.

There are two different but closely related topics covered here: How to use Terraform, and how to use the Azure Provider.

The tutorial begins with a introduction to Terraform basics. As you progress through the track, you'll modify a configuration step-by-step until you have explored all of the core parts of a Terraform configuration. You'll learn basic HCL (HashiCorp Configuration Language) syntax, remote backends, outputs, and provisioners.

Along the way we'll explore the Azure Provisioner (azurerm) for Terraform. Azurerm provides a declarative interface for managing Azure resources with Terraform. Azurerm lets you create, modify, and delete Azure resources in a Terraform configuration. The sample configuration creates a new resource group, VNET, subnet, NIC, etc, and then deploys a Linux VM.

At the end of this track we'll list additional resources for using Terraform with Azure.


  • An Azure account. If you don't have an Azure account, create one now. This tutorial can be completed using only the services included in an Azure free account. You need to have at least Contributor role in the subscription to create and manage infrastructure for the tutorial.

    If you are using a paid subscription, you may be charged for the resources needed to complete the tutorial.

  • A system with Terraform 0.12.6 or later installed. This track includes instructions for installing Terraform on the platform of your choice.

Azure Cloud Shell is the most convenient platform for this tutorial. Everything you need is preinstalled, and Cloud Shell uses the credentials of the signed-in Azure user. Most of the procedures assume that you are using Cloud Shell, either from the Azure Portal or standalone. Code samples are provided as-is.

The set of files used to describe infrastructure in Terraform is known as a Terraform configuration. In this lesson you write your first configuration to create and configure a resource group in Azure. But first, there are a few things you should know about Terraform configurations.

Terraform uses a declarative model for defining infrastructure: You write a configuration that declares your desired state and then leave it up to Terraform and the Azure provider to determine how to create and configure Azure to match the desired state. Configuration files are made up of resources with settings and values representing the desired state of your infrastructure.

Terraform configurations are made up of one or more files in a directory. By default this directory will also contain provider binaries, plan file, and state files once Terraform has run the configuration. Plugins and other binary files needed by Terraform are saved in a hidden .terraform directory. The directory that contains the configuration files is often called the "working directory" or the "home directory."

A configuration is idempotent. If you apply a configuration to existing infrastructure with no changes to the configuration, Terraform will not reapply the settings. It is possible to taint a resource to compel Terraform to reapply settings when it otherwise would not, an advanced topic that is beyond the scope of this guide.

Terraform persists state (described later in this guide) over multiple sessions, allowing Terraform to compare the configuration files with previous and current state of Azure resources. When you change a configuration and apply it to existing infrastructure, Terraform compares the new configuration to the state saved from the previous terraform apply to create an execution plan that includes only the directly affected resources and dependencies.

It's common to work with secrets in Terraform configurations. Secrets can include user account, passwords, connection strings, ssh keys, certificates, storage access keys, etc. -- any information in your configuration that you don't want everybody to know is a secret. Be careful not to include secrets in configuration files that get checked into source control. The entire topic of using secrets with Terraform is outside the scope of this guide. However, samples in the rest of this guide do contain tips about working with secrets.

»Configuration file format

Configuration files can be in either of two formats: HashiCorp Configuration Language (HCL), or JSON. HCL is a structured language created with DevOps in mind; it is machine-friendly yet easy for humans to read, and it supports comments. HCL format files have a .tf extension. JSON is sometimes preferable when configurations are generated by a machine. JSON files have a .tf.json extension. A configuration can be composed of both .tf and .tf.json files. In general, we recommend that you work with HCL. The format of configuration files is documented here.


Terraform can configure resources across multiple clouds. For example, a single configuration can span both Azure and AWS. In such cases, there needs to be a way for Terraform to know how to manage each cloud. This is where cloud providers come in. Each cloud provider can have a provider block present in the configuration.

The provider block is used to configure the named provider, in this instance the Azure provider (azurerm). The Azure provider is responsible for creating and managing resources on Azure, and for all other interactions with Azure including authentication.

A basic Azure provider block looks like this:

provider "azurerm" {
    version = "~>2.20.0"
    features {}

The version argument is optional, but recommended. It is used to constrain the provider to a specific version or a range of versions in order to prevent downloading a new provider that may possibly contain breaking changes. If the version isn't specified, Terraform will automatically download the most recent provider during initialization. The ~> symbol is the pessimistic constraint operator. It tells Terraform to use all non-beta versions >=2.20.0 and <2.21.0.

Provider blocks may contain additional fields for identity, environment, role, and many others. A complete list of provider fields for Azure is here.


Cloud providers require some type of authentication before Terraform can connect to the service to manage infrastructure. Azure Provider supports several methods of authentication to suit different requirements.

The authentication method you use is usually decided by circumstances. If you have the option, the recommended method of authentication for Azure is managed identity. Managed identities for Azure resources is a feature of Azure Active Directory (Azure AD). Using a managed identity for the Terraform host VM or container removes the need to pass a client secret or certificate to Terraform.

Authentication is configured in the provider block. The following example shows a configuration for authentication to Azure using a managed identity:

provider "azurerm" {
    version = "~>2.20.0"
    use_msi = true
    subscription_id = "xxxxxxxxxxxxxxxxx"
    tenant_id       = "xxxxxxxxxxxxxxxxx"
    features {}


A resource block defines the desired state for a given resource within the infrastructure. A resource can be a physical component such as a network interface, or it can be a logical resource such as an application.

A resource block has two string parameters before opening the block: the resource type (first parameter) and the resource name (second parameter). The combination of the type and name must be unique in the configuration.

The following example uses a resource block to provision a new Azure resource group. A resource group is a fundamental object in the Azure Resource Manager (ARM) deployment model, and it is required to create, modify, or destroy infrastructure in ARM. A configuration can create a new resource group or use an existing group, and often does both.

resource "azurerm_resource_group" "rg" {
    name     = "myTFResourceGroup"
    location = "westus2"

In this example, the resource type is azurerm_resource_group and the name is "rg". The resource name is used to refer to the object created in the resource block throughout the configuration. It is not the same as the name of the resource group in Azure.

The general format for referring to a resource created in a Terraform configuration is <type>.<name>. The resource group in the sample above is azurerm_resource_group.rg. Later in this guide we'll see how to refer to the properties of resources and use them as arguments to create new resources.

Within the resource block enclosed by {} are the arguments for that resource. The argument options available depend on the resource. Resources can have both required and optional arguments. This example specified name and location, both required fields.

Many resources return attributes. Azurerm_resource_group has one attribute, the resource group ID:

»Complete configuration

Create a file called in a folder called myTFproject. Copy this configuration to and save before moving to the next section.

# Configure the Azure provider
provider "azurerm" {
    version = "~>2.20.0"
    features {}

# Create a new resource group
resource "azurerm_resource_group" "rg" {
    name     = "myTFResourceGroup"
    location = "westus2"