Terraform
Build infrastructure
In this tutorial, you will create a Terraform configuration to deploy an Azure resource group. This resource group is the foundation for the infrastructure you will build in the subsequent tutorials.
Prerequisites
- An Azure subscription. If you do not have an Azure account, create one now. This tutorial can be completed using only the services included in an Azure free account.
If you are using a paid subscription, you may be charged for the resources needed to complete the tutorial.
Terraform 1.2.0+ installed locally.
The Azure CLI installed
Install the Azure CLI
You will use the Azure CLI to authenticate with Azure.
Open your PowerShell prompt as an administrator and run the following command:
$ Invoke-WebRequest -Uri https://aka.ms/installazurecliwindows -OutFile .\AzureCLI.msi; Start-Process msiexec.exe -Wait -ArgumentList '/I AzureCLI.msi /quiet'; rm .\AzureCLI.msi
Authenticate using the Azure CLI
Terraform must authenticate to Azure to create infrastructure.
In your terminal, use the Azure CLI to setup your account permissions locally.
$ az login
Your browser will open and prompt you to enter your Azure login credentials. After successful authentication, your terminal will display your subscription information.
You have logged in. Now let us find all the subscriptions to which you have access...
[
{
"cloudName": "AzureCloud",
"homeTenantId": "0envbwi39-home-Tenant-Id",
"id": "35akss-subscription-id",
"isDefault": true,
"managedByTenants": [],
"name": "Subscription-Name",
"state": "Enabled",
"tenantId": "0envbwi39-TenantId",
"user": {
"name": "your-username@domain.com",
"type": "user"
}
}
]
Find the id
column for the subscription account you want to use.
Once you have chosen the account subscription ID, set the account with the Azure CLI.
$ az account set --subscription "35akss-subscription-id"
Create a Service Principal
Next, create a Service Principal. A Service Principal is an application within Azure Active Directory with the authentication tokens Terraform needs to perform actions on your behalf. Update the <SUBSCRIPTION_ID>
with the subscription ID you specified in the previous step.
$ az ad sp create-for-rbac --role="Contributor" --scopes="/subscriptions/<SUBSCRIPTION_ID>"
Creating 'Contributor' role assignment under scope '/subscriptions/35akss-subscription-id'
The output includes credentials that you must protect. Be sure that you do not include these credentials in your code or check the credentials into your source control. For more information, see https://aka.ms/azadsp-cli
{
"appId": "xxxxxx-xxx-xxxx-xxxx-xxxxxxxxxx",
"displayName": "azure-cli-2022-xxxx",
"password": "xxxxxx~xxxxxx~xxxxx",
"tenant": "xxxxx-xxxx-xxxxx-xxxx-xxxxx"
}
Set your environment variables
HashiCorp recommends setting these values as environment variables rather than saving them in your Terraform configuration.
In your Powershell terminal, set the following environment variables. Be sure to update the variable values with the values Azure returned in the previous command.
$ $Env:ARM_CLIENT_ID = "<APPID_VALUE>"
$ $Env:ARM_CLIENT_SECRET = "<PASSWORD_VALUE>"
$ $Env:ARM_SUBSCRIPTION_ID = "<SUBSCRIPTION_ID>"
$ $Env:ARM_TENANT_ID = "<TENANT_VALUE>"
For more information on Service Principal authentication, visit the Azure provider documentation.
Write configuration
Create a folder called learn-terraform-azure
.
$ New-Item -Path "c:\" -Name "learn-terraform-azure" -ItemType "directory"
Create a new file called main.tf
and paste the configuration below.
main.tf
# Configure the Azure provider
terraform {
required_providers {
azurerm = {
source = "hashicorp/azurerm"
version = "~> 3.0.2"
}
}
required_version = ">= 1.1.0"
}
provider "azurerm" {
features {}
}
resource "azurerm_resource_group" "rg" {
name = "myTFResourceGroup"
location = "westus2"
}
Note
The location
of your resource group is hardcoded in this example. If you do not have access to the resource group location westus2
, update the main.tf
file with your Azure region.
This is a complete configuration that Terraform can apply. In the following sections you will review each block of the configuration in more detail.
Terraform Block
The terraform {}
block contains Terraform settings, including the required
providers Terraform will use to provision your infrastructure. For each provider, the
source
attribute defines an optional hostname, a namespace, and the provider
type. Terraform installs providers from the Terraform
Registry by default. In this example
configuration, the azurerm
provider's source is defined as hashicorp/azurerm
, which
is shorthand for registry.terraform.io/hashicorp/azurerm
.
You can also define a version constraint for each provider in the
required_providers
block. The version
attribute is optional, but we
recommend using it to enforce the provider version. Without it, Terraform will
always use the latest version of the provider, which may introduce breaking
changes.
To learn more, reference the provider source documentation.
Providers
The provider
block configures the specified provider, in this case azurerm
.
A provider is a plugin that Terraform uses to create and manage your resources.
You can define multiple provider blocks in a Terraform configuration to manage
resources from different providers.
Resource
Use resource
blocks to define components of your infrastructure. A
resource might be a physical component such as a server, or it can be a logical
resource such as a Heroku application.
Resource blocks have two strings before the block: the resource type and the
resource name. In this example, the resource type is azurerm_resource_group
and the name is rg
. The prefix of the type maps to the name of the provider. In the
example configuration, Terraform manages the azurerm_resource_group
resource with the
azurerm
provider. Together, the resource type and resource name form a unique ID
for the resource. For example, the ID for your network is
azurerm_resource_group.rg
.
Resource blocks contain arguments which you use to configure the resource. The Azure provider documentation documents supported resources and their configuration options, including azurerm_resource_group and its supported arguments.
Initialize your Terraform configuration
Initialize your learn-terraform-azure
directory in your terminal. The
terraform
commands will work with any operating system. Your output should
look similar to the one below.
$ terraform init
Initializing the backend...
Initializing provider plugins...
- Finding hashicorp/azurerm versions matching "~> 3.0.2"...
- Installing hashicorp/azurerm v3.0.2...
- Installed hashicorp/azurerm v3.0.2 (signed by HashiCorp)
Terraform has been successfully initialized!
You may now begin working with Terraform. Try running "terraform plan" to see
any changes that are required for your infrastructure. All Terraform commands
should now work.
If you ever set or change modules or backend configuration for Terraform,
rerun this command to reinitialize your working directory. If you forget, other
commands will detect it and remind you to do so if necessary.
Format and validate the configuration
We recommend using consistent formatting in all of your configuration files. The
terraform fmt
command automatically updates configurations in the current
directory for readability and consistency.
Format your configuration. Terraform will print out the names of the files it modified, if any. In this case, your configuration file was already formatted correctly, so Terraform won't return any file names.
$ terraform fmt
You can also make sure your configuration is syntactically valid and internally
consistent by using the terraform validate
command.
Validate your configuration. The example configuration provided above is valid, so Terraform will return a success message.
$ terraform validate
Success! The configuration is valid.
Apply your Terraform Configuration
Run the terraform apply
command to apply your configuration.
This output shows the execution plan and will prompt you for approval before
proceeding. If anything in the plan seems incorrect or dangerous, it is safe to
abort here with no changes made to your infrastructure. Type yes
at the
confirmation prompt to proceed.
$ terraform apply
An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
+ create
Terraform will perform the following actions:
# azurerm_resource_group.rg will be created
+ resource "azurerm_resource_group" "rg" {
+ id = (known after apply)
+ location = "westus2"
+ name = "myTFResourceGroup"
}
Plan: 1 to add, 0 to change, 0 to destroy.
Do you want to perform these actions?
Terraform will perform the actions described above.
Only 'yes' will be accepted to approve.
Enter a value: yes
azurerm_resource_group.rg: Creating...
azurerm_resource_group.rg: Creation complete after 1s [id=/subscriptions/c9ed8610-47a3-4107-a2b2-a322114dfb29/resourceGroups/myTFResourceGroup]
Apply complete! Resources: 1 added, 0 changed, 0 destroyed.
Navigate to the Azure portal in your web browser to validate the resource group.
Inspect your state
When you apply your configuration, Terraform writes data into a file called terraform.tfstate
. This
file contains the IDs and properties of the resources Terraform created
so that it can manage or destroy those resources going forward. Your state file contains all of the data in your configuration and could also contain sensitive values in plaintext, so do not share it or check it in to source control.
For teams or larger projects, consider storing your state remotely. Remote stage storage enables collaboration using Terraform but is beyond the scope of this tutorial.
Inspect the current state using terraform show
.
$ terraform show
# azurerm_resource_group.rg:
resource "azurerm_resource_group" "rg" {
id = "/subscriptions/c9ed8610-47a3-4107-a2b2-a322114dfb29/resourceGroups/myTFResourceGroup"
location = "westus2"
name = "myTFResourceGroup"
}
When Terraform created this resource group, it also gathered the resource's properties and meta-data. These values can be referenced to configure other resources or outputs, which you will encounter in later tutorials.
To review the information in your state file, use the state
command. If you have a long state file, you can see a list of the resources you created with Terraform by using the list
subcommand.
$ terraform state list
azurerm_resource_group.rg
If you run terraform state
, you will see a full list of available commands to view and manipulate the configuration's state.
$ terraform state
Usage: terraform state <subcommand> [options] [args]
This command has subcommands for advanced state management.
These subcommands can be used to slice and dice the Terraform state.
This is sometimes necessary in advanced cases. For your safety, all
state management commands that modify the state create a timestamped
backup of the state prior to making modifications.
The structure and output of the commands is specifically tailored to work
well with the common Unix utilities such as grep, awk, etc. We recommend
using those tools to perform more advanced state tasks.
Subcommands:
list List resources in the state
mv Move an item in the state
pull Pull current state and output to stdout
push Update remote state from a local state file
replace-provider Replace provider in the state
rm Remove instances from the state
show Show a resource in the state
Next Steps
For more detail on the concepts used in this tutorial:
- Read about the Terraform configuration language in the Terraform documentation.
- Learn more about Terraform providers.
- Review usage examples of the Terraform Azure provider from Terraform provider engineers