Terraform

Terraform Init – Command Overview with Quick Usage Examples

Terraform init

In this post, I will explain what the terraform init command is used for, what it does, and when to run it. I will explore the options available and give an example of when to use it in automation using Azure DevOps.

What is Terraform Init?

After writing your Terraform code or cloning your existing Terraform code from source control, the terraform init command is the first command you should use to initialize the working directory.

What Does the Terraform Init Command Do?

  • Backend Initialization
  • Child Module Installation
  • Plugin Installation

Quick Usage Examples

Example Configuration Files

The example files I will use in this article will create a specified number of groups in Azure AD. These files are contained in a directory called az-ad-group. Within it, I have my Terraform configuration files, named main.tf, variables.tf and terraform.tfvars, as well as a .gitignorefile which will specify which file extensions within the folder the git source control should ignore. I have a subfolder (or module) within this which holds a main.tf and variables.tf file. Lastly, the azure-pipeline.yml file specifies the pipeline settings to run terraform init and terraform plan.

AZ-AD-Group

main.tf

provider "azurerm" {
  features {}
}

terraform {
  required_providers {
    azurerm = {
      source  = "hashicorp/azurerm"
      version = ">=2.95.0"
    }
    azuread = {
      source  = "hashicorp/azuread"
    }
  }
  backend "azurerm" {
    resource_group_name  = "tf-rg"
    storage_account_name = "jacktfstatesa"
    container_name       = "terraform"
    key                  = "adgroups.tfstate"
  }
}

module "ad_group" {
  source = "./ad_group"
  ad_group_names = var.ad_group_names
}

Note that the main.tf file contains the required_providers and backend blocks. I also call a module called ad_group. Since this article focuses on the terraform init command, and everything relevant to that command is shown in the above code, I will not publish the rest of the files here, but they can be found in the GitHub repository should you wish to try the example out yourself or delve deeper into the setup.

Backend Initialization

backend "azurerm" {
    resource_group_name  = "tf-rg"
    storage_account_name = "jacktfstatesa"
    container_name       = "terraform"
    key                  = "adgroups.tfstate"
 }

Before that can happen successfully I will need to login to Azure using the Azure CLI. If I run it without first authenticating, Terraform complains that the resource group containing the storage account cannot be found.

Backend

To login to Azure, use the following commands. The --tenant flag does not need to be specified if you have only one Azure AD tenant linked to your login. If you have multiple tenants linked to your login, you should specify this to avoid confusion.

az login --tenant <tenant ID>
az account set --subscription <subscription ID>
Backend 2
adgroups.tfstate

Any changes to the backend configuration will be detected by Terraform. When terraform init is run, Terraform will throw an error alerting you to the change.

init error
  • migrate-state
  • reconfigure

Child Module Installation

module "ad_group" {
  source = "./ad_group"
  ad_group_names = var.ad_group_names
}

When terraform init is run we can see it being installed:

Initializing modules

Plugin Installation

Most Terraform providers are published separately from Terraform as plugins. There are hundreds of available providers which allow Terraform to be used with different services. Common providers include azurerm for Microsoft Azure, azuread for Azure Active Directory, and aws for Amazon Web Services. A full list of available providers can be browsed using the Terraform registry.

Init provider plugins

terraform.lock.hcl

.terraform.lock.hcl

The contents of the .terraform.lock.hcl file will look like this:

# This file is maintained automatically by "terraform init".
# Manual edits may be lost in future updates.

provider "registry.terraform.io/hashicorp/azuread" {
  version = "2.18.0"
  hashes = [
    "h1:cpppwljjeyqTnwNlQGHK+o1Jb5Tf4UAnJiInNkN6P38=",
    "zh:04b2b5e09dedd45316cd47d21d2ed7e3cd7a4e5f3c8b6e8fba0a10e7eb2a1ca9",
    "zh:232440381b60d918e0da0ea8e8a2e8a78a4fe1ae785b3f829f2f965464ab79a2",
    "zh:688111a9cb8d9ffec2ccabacb27456d275bf1d404dd5f85e681715abbdd64654",
    "zh:7f37b7be7859170f077c58e74be42b5571e364c52aac0a2df3a6a14fbe48d3c5",
    "zh:a385743bfae40f6a01bf6662a3c7a71035113c33965e0dbf421997a015734d08",
    "zh:a97b7430647d7b449441e5515f11a4d123f6d6a383a8fbca5c0a4086be407358",
    "zh:be6d40d1431e8e71a96cce2099a259ef5a8dfb0e849817875d9ee4bb8cf59d40",
    "zh:db3b541d90881d620111fdae0efe90d1e0972fc80a2b4346d4af8d96e1fc1195",
    "zh:e6d9e0481f2bdc16ee69aa00001d9713282daccfbc621e0143c53d9f6dbdb537",
    "zh:ee5b724ca78301057059eff18062fa88d8b24ac7b39f52eb17b8609634427ce0",
    "zh:fdb169f89551f97f6b0bf90d61d5fda166a25cce6867ec16f63c3bfb4d90a0a2",
  ]
}

provider "registry.terraform.io/hashicorp/azurerm" {
  version     = "2.98.0"
  constraints = ">= 2.95.0"
  hashes = [
    "h1:8Sg08lYcJC12Y8EH5oFfgBhIR9OhZFKF633NjOMjilY=",
    "zh:025f656a6d3ecc30f7cc2279bc41969789987b405e3fa8a7c1eb5f74e3ee1140",
    "zh:23c54b330678a16378156193d709bbddce3ba76ee827fd65fb751ce90790af9e",
    "zh:2d28d359ce6881918bd6c03701f6ec4fd90215abfce9b863cfd3172e28c1acb3",
    "zh:31df88584d39cf876fa45ff6de92e67e03814a0985d34c7671bd6989cda22af8",
    "zh:36019109790b9a905770355e5bbb57b291a9689a8b9beac5751dcbdb1282d035",
    "zh:5fb4a277331c459db9e1b150d79b7c7157a176ceca871195e81225e949141b72",
    "zh:7ec304afa1b60dc84257a54cea68e97f85df3feb405d25a9226a4f593ed00744",
    "zh:bac469f104b8ad2c8b5ddc88ddae3b0bc27ae5f9c2ccf03f14a001a5c3ed6ae1",
    "zh:d860b0ec60a978fe3f08d695326e9051a61cd3f60786fc618a61fbdb5d6a4f15",
    "zh:ebcb2911ee27587f63df7eff3836c9a206181a931357c6b9a380124be4241597",
    "zh:f37fae57bf7d05c30fda6e5414ad5a4aad1b34d41a5f2465a864736f92ded1ac",
  ]
}

Do You Need to Run Terraform Init Before Every Terraform Plan?

terraform init is the first command you should run in the workflow, however, if you know that no changes have been made to the modules, backend, or provider installations, you can go ahead and run terraform plan without running terraform init first. In automation, it is always best practice to put in a terraform init stage first to make sure the modules, providers, and backend are always up-to-date as specified in your configuration files.

Is it Safe to Run Terraform Init Multiple Times?

It is always safe to run terraform init. It will never modify the configuration or destroy any resources. If it is run multiple times it will simply update the working directory with the changes in the configuration. This will be required if the configuration changes include the addition of a new provider block or a change to the backend storage location for example.

Running Terraform Init in Automation

terraform initwill be the first step in configuring your Terraform workflow in an automation pipeline. In order to set this up in using Azure DevOps pipelines, we will use the azure-pipelines.yml file contained in the example code repository.

stages:
- stage: Build
  displayName: Terraform-Plan  
  jobs:
  - job: TerraformPlan
    displayName: Terraform-Plan
    pool:
      name: Private-Build-Agents
    steps:
    - checkout: self
    - script: ls $(System.DefaultWorkingDirectory)
    - task: TerraformInstaller@0
      displayName: 'Use Terraform latest'

    - task: TerraformCLI@0
      displayName: Terraform-Init
      inputs:
        command: 'init'
        workingDirectory: '$(System.DefaultWorkingDirectory)'
        backendType: 'azurerm'
        backendServiceArm: 'IAC Service Connection-Azure'
        backendAzureRmResourceGroupName: 'tf-rg'
        backendAzureRmStorageAccountName: 'jacktfstatesa'
        backendAzureRmContainerName: 'terraform'
        backendAzureRmKey: 'adgroups.tfstate'

    - task: TerraformCLI@0
      displayName: Terraform-Plan
      inputs:
        command: 'plan'
        workingDirectory: '$(System.DefaultWorkingDirectory)'
        environmentServiceName: 'RG Service Connection'
Downloading task
Terraform-Init

In some cases where you have lots of providers specified and want to avoid them being installed repeatedly on each pipeline run by terraform init, you may wish to make the providers available locally. This is possible and is covered in this advanced ‘Terraform in automation’ tutorial.

Terraform Init Options

  • backend=false
  • backend-config=path
  • force-copy
  • from-module=SOURCE
  • get=false
  • input=false
  • lock=false
state blob is already locked
Break lease
az storage blob lease break -b terraform.tfstate -c myAzureStorageAccountContainerName --account-name "myAzureStorageAccountName" --account-key "myAzureStorageAccountAccessKey"

Or using Terraform you can force the unlock, (get the LockID from the error) e.g.

terraform force-unlock <LockId>
  • lock-timeout=<duration>
  • no-color
color
no-color
  • plugin-dir
  • upgrade
azuread = {
   source  = "hashicorp/azuread"
   version = "=2.17.0"
}

If I then proceed to remove the version constraint from the azuread provider:

azuread = {
   source  = "hashicorp/azuread"
}
init upgrade

When re-run with the upgrade flag, you will notice that Terraform searches for the latest version of the azureadprovider (v2.18.0 at the time of writing). Also, notice that any modules in the configuration are also upgraded.

init upgrade 2
  • migrate-state
  • reconfigure
  • lockfile=MODE
  • ignore-remote-version

Key Points

The terraform init command is the first command you should use to prepare the working directory. terraform init specifically performs the following actions:

  • Backend Initialization
  • Child Module Installation
  • Plugin Installation

For more documentation on the terraform initcommand check out the Hashicorp website. You may also check how initialization policies work with Spacelift.

Terraform Management Made Easy

Spacelift effectively manages Terraform state, more complex workflows, supports policy as code, programmatic configuration, context sharing, drift detection, resource visualization and includes many more features.

Start free trial