Terraform
Configure Terraform providers
Terraform providers are plugins that enable Terraform to interact with cloud platforms, SaaS providers, and other APIs. Terraform sources providers from the Terraform registry by default, which hosts providers maintained by HashiCorp, our partners, and community members. Each provider supports a set of resource types and data sources that you can manage with Terraform.
To use Terraform to manage resources for your chosen cloud platform, you must first install the corresponding provider and configure authentication. With the provider installed, you can use Terraform to create and manage the resources it supports.
In this tutorial, you will learn how to source and version providers from the Terraform registry, configure and authenticate providers, and upgrade provider versions safely. You will also learn how to configure multiple instances of the same provider using aliases and control which providers your Terraform modules use to provision infrastructure.
Prerequisites
This tutorial assumes that you are familiar with the Terraform workflow. If you are new to Terraform, complete the Get Started collection first.
You can complete this tutorial using AWS, Azure, or Google Cloud Platform. Select the tab at the top of the page for your preferred cloud provider.
To complete this tutorial, you will need:
- Terraform v1.2+ installed locally.
- An Azure account with the Azure CLI installed.
Note
Some of the infrastructure in this tutorial may not qualify for your cloud service's free tier. Destroy the infrastructure at the end of the tutorial to avoid unnecessary charges. We are not responsible for any charges that you incur.
Clone example repository
Clone the example repository for this tutorial, which contains example Terraform configuration for you to use.
$ git clone https://github.com/hashicorp-education/learn-terraform-providers
Change to the repository directory for your preferred cloud vendor.
$ cd learn-terraform-providers/azure
Install a provider from the registry
The Terraform registry hosts publicly available Terraform providers and modules. Before adding a provider to your configuration, review the provider documentation on the registry to understand the provider's capabilities and requirements.
Visit the Azure provider page in the Terraform registry.
The provider documentation includes:
- Documentation for all resources and data sources supported by the provider.
- Guides for authentication, upgrading your provider, and other use cases.
- A Use Provider button with example configuration you can copy into your workspace.
Terraform providers are distributed as plugins that Terraform downloads and
installs when you initialize your workspace. You can specify which providers
your configuration requires in the required_providers
block within the
terraform
configuration block.
Review the example configuration in terraform.tf
.
terraform.tf
terraform {
required_providers {
azurerm = {
source = "hashicorp/azurerm"
version = "~> 4.36.0"
}
random = {
source = "hashicorp/random"
version = "~> 3.7.2"
}
}
required_version = ">= 1.2"
}
The required_providers
block specifies:
- source: The provider's address in the registry. The format is
[hostname/]namespace/type
. When no hostname is specified, Terraform defaults toregistry.terraform.io
. - version: A version constraint that determines which provider versions are
acceptable. A
~> 6.3.0
constraint allows any version in the 6.3.x series but prevents updates to 6.4 and later.
Version constraints
Terraform supports several version constraint operators:
>= 6.0
: Version 6.0 or newer~> 6.0
: Any version in the 6.x series (equivalent to>= 6.0, < 7.0
)~> 6.3.0
: Any version in the 6.3.x series (equivalent to>= 6.3.0, < 6.4.0
)= 6.4.2
: Exactly version 6.4.2
Initialize your configuration to download the specified providers.
$ terraform init
Initializing the backend...
Initializing provider plugins...
- Finding hashicorp/azurerm versions matching "~> 4.36.0"...
- Finding hashicorp/random versions matching "~> 3.7.2"...
- Installing hashicorp/azurerm v4.36.0...
- Installed hashicorp/azurerm v4.36.0 (signed by HashiCorp)
- Installing hashicorp/random v3.7.2...
- Installed hashicorp/random v3.7.2 (signed by HashiCorp)
Terraform has created a lock file .terraform.lock.hcl to record the provider
selections it made above. Include this file in your version control repository
so that Terraform can guarantee to make the same selections by default when
you run "terraform init" in the future.
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.
Terraform downloaded the providers and created a dependency lock file for your
workspace. The dependency lock file tracks the version and checksums of the
providers used by your configuration. Terraform will use the versions specified
in your dependency lock file until you explicitly upgrade them with the
terraform init -upgrade
command.
Configure your provider
A provider
block configures the named provider. Most providers allow you to
configure their behavior in the provider block, such as endpoint URLs, cloud
regions, or other settings that apply to all resources managed by that
provider. If you do not specify a provider block for a given resource, Terraform
will default to a provider with empty configuration. To make your configuration
easier to understand, we recommend explicitly including a provider block for
each provider used by your configuration, even if it is empty.
Review the provider
block in your configuration:
main.tf
provider "azurerm" {
features {}
}
provider "random" { }
The azurerm
provider block configures the Azure provider. The Azure provider
requires you to include the features
block, but this configuration does not
require any advanced features. Refer to the provider
documentation
for the available attributes for your chosen provider.
The random
provider does not require configuration, so the example
configuration includes an empty provider
block for it.
The rest of the example configuration in main.tf
defines an Azure storage
account in the West US 2
region. It uses the random provider to generate a
unique name for your storage account.
main.tf
resource "azurerm_resource_group" "example" {
name = "terraform-provider-example"
location = "West US 2"
}
resource "random_string" "suffix" {
length = 6
upper = false
special = false
}
resource "azurerm_storage_account" "example" {
name = "learn${random_string.suffix.result}"
resource_group_name = azurerm_resource_group.example.name
location = azurerm_resource_group.example.location
account_tier = "Standard"
account_replication_type = "LRS"
}
Authenticate your provider
Terraform providers need credentials to authenticate with cloud APIs. Each provider supports different authentication methods, which are documented in the provider's registry page.
The Azure provider supports several authentication methods:
- The Azure CLI (recommended for local development)
- A Managed Service Identity
- A Service Principal and a Client Certificate
- A Service Principal and a Client Secret
- Using OpenID Connect
For this tutorial, authenticate either using the Azure CLI with a tenant ID or by setting environment variables with a service principal and client secret:
Authenticate with your Azure tenant using the Azure CLI.
$ az login --tenant "your-azure-tenant-id"
The Azure CLI will open a browser window to continue the authentication process. Refer to the Azure CLI documentation for more information about logging in.
Then set the subscription you will use for this tutorial. First list the subscriptions available to your account:
$ az account list
[
{
"cloudName": "AzureCloud",
"homeTenantId": "53b7328c-1234-5678-b84e-04b3f4bcf38f",
"id": "08fd09b4-abcd-efgh-979c-53cc488bd179",
"isDefault": false,
"managedByTenants": [],
"name": "Azure subscription 1",
"state": "Enabled",
"tenantDefaultDomain": "you.onmicrosoft.com",
"tenantDisplayName": "Default Directory",
"tenantId": "53b7328c-caf4-40fb-b84e-04b3f4bcf38f",
"user": {
"name": "you@email.com",
"type": "user"
}
},
## ...
Select the id
of the subscription you will use with this tutorial, and
configure it with the Azure CLI.
$ az account set --subscription "your-subscription-id"
Export the subscription ID as an environment variable to configure the Terraform provider.
$ export ARM_SUBSCRIPTION_ID="your-subscription-id"
Verify that your credentials are correctly configured by planning your configuration:
$ terraform plan
Terraform used the selected providers to generate the following execution plan. Resource
actions are indicated with the following symbols:
+ create
Terraform will perform the following actions:
# azurerm_resource_group.example will be created
+ resource "azurerm_resource_group" "example" {
+ id = (known after apply)
+ location = "westus2"
## ...
Plan: 3 to add, 0 to change, 0 to destroy.
─────────────────────────────────────────────────────────────────────────────────────────────
Note: You didn't use the -out option to save this plan, so Terraform can't guarantee to take
exactly these actions if you run "terraform apply" now.
Apply configuration
Apply your configuration to create your resources. Respond to the confirmation
prompt with a yes
.
$ terraform apply
Terraform used the selected providers to generate the following execution plan. Resource
actions are indicated with the following symbols:
+ create
Terraform will perform the following actions:
# azurerm_resource_group.example will be created
+ resource "azurerm_resource_group" "example" {
+ id = (known after apply)
+ location = "westus2"
+ name = "learnabcdef"
## ...
Plan: 3 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
random_string.suffix: Creating...
random_string.suffix: Creation complete after 0s [id=nb3zy5]
azurerm_resource_group.example: Creating...
azurerm_resource_group.example: Still creating... [00m10s elapsed]
azurerm_resource_group.example: Creation complete after 11s [id=/subscriptions/afb1f74d-44fa-4ca2-a9b9-c32b85883eb0/resourceGroups/terraform-provider-example]
azurerm_storage_account.example: Creating...
azurerm_storage_account.example: Still creating... [00m10s elapsed]
azurerm_storage_account.example: Still creating... [00m20s elapsed]
azurerm_storage_account.example: Still creating... [00m30s elapsed]
azurerm_storage_account.example: Still creating... [00m40s elapsed]
azurerm_storage_account.example: Still creating... [00m50s elapsed]
azurerm_storage_account.example: Still creating... [01m00s elapsed]
azurerm_storage_account.example: Creation complete after 1m7s [id=/subscriptions/afb1f74d-44fa-4ca2-a9b9-c32b85883eb0/resourceGroups/terraform-provider-example/providers/Microsoft.Storage/storageAccounts/terraformproviderexample]
Apply complete! Resources: 2 added, 0 changed, 0 destroyed.
Upgrade a provider
Providers are maintained and versioned separately from Terraform itself, and provider developers periodically release new versions that include bug fixes, new features, and additional resources. Terraform's dependency lock file ensures that your team uses consistent provider versions until you explicitly decide to upgrade your provider.
Review the dependency lock file
Examine the generated lock file:
$ cat .terraform.lock.hcl
.terraform.lock.hcl
# This file is maintained automatically by "terraform init".
# Manual edits may be lost in future updates.
provider "registry.terraform.io/hashicorp/azurerm" {
version = "4.36.0"
constraints = "~> 4.36.0"
hashes = [
"h1:62DjN6+oXv/KwL5901S56hiBU+bxYr1L/cJjN0CyMy0=",
"zh:0c127e6337e0259657066320c78c2f41fa85f0c380a338fd73745bb347da8339",
## ...
"zh:f569b65999264a9416862bca5cd2a6177d94ccb0424f3a4ef424428912b9cb3c",
]
}
The lock file records:
- The exact version of the provider that was selected (
4.36.0
) - The version constraint from your configuration (
~> 4.36.0
) - Cryptographic hashes to verify provider authenticity
Upgrade to a newer version
To upgrade to a newer provider version, update your configured version
constraint, and use the terraform init -upgrade
command.
First, edit terraform.tf
to update the version constraint for your provider.
terraform.tf
terraform {
required_providers {
azurerm = {
source = "hashicorp/azurerm"
version = "~> 4.37.0"
}
random = {
source = "hashicorp/random"
version = "~> 3.7.2"
}
}
required_version = ">= 1.2"
}
Next, run terraform init -upgrade
to upgrade your configuration's providers to
the latest version that matches their configured version constraint.
$ terraform init -upgrade
Initializing the backend...
Initializing provider plugins...
- Finding hashicorp/random versions matching "~> 3.7.2"...
- Finding hashicorp/azurerm versions matching "~> 4.37.0"...
- Using previously-installed hashicorp/random v3.7.2
- Installing hashicorp/azurerm v4.37.0...
- Installed hashicorp/azurerm v4.37.0 (signed by HashiCorp)
Terraform has made some changes to the provider dependency selections recorded
in the .terraform.lock.hcl file. Review those changes and commit them to your
version control system if they represent changes you intended to make.
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.
The -upgrade
flag tells Terraform to upgrade your workspace’s providers to the
latest version that matches the configured version constraint, and update the
lock file.
Note
Review provider release notes before upgrading, especially for major version changes that might include breaking changes or require configuration updates.
Use a child module
When you use modules, Terraform automatically passes the provider configuration from the root module to child modules. This allows child modules to create resources using the same provider settings.
Add the following module to your configuration in main.tf
to use the
Azure/avm-res-network-privatednszone/azurerm
module to manage a private DNS
zone:
main.tf
module "dns" {
source = "Azure/avm-res-network-privatednszone/azurerm"
version = "0.1.0"
domain_name = "example.local"
resource_group_name = azurerm_resource_group.example.name
}
Initialize your workspace to install the new module and other providers it requires.
$ terraform init
Initializing the backend...
Initializing modules...
Downloading registry.terraform.io/Azure/avm-res-network-privatednszone/azurerm 0.1.0 for dns...
- dns in .terraform/modules/dns
Initializing provider plugins...
- Finding hashicorp/random versions matching ">= 3.5.1"...
- Reusing previous version of hashicorp/azurerm from the dependency lock file
- Installing hashicorp/random v3.7.2...
- Installed hashicorp/random v3.7.2 (signed by HashiCorp)
- Using previously-installed hashicorp/azurerm v4.37.0
Terraform has made some changes to the provider dependency selections recorded
in the .terraform.lock.hcl file. Review those changes and commit them to your
version control system if they represent changes you intended to make.
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.
Apply your configuration. Respond to the confirmation prompt with yes
to
create your new domain.
$ terraform apply
azurerm_resource_group.example: Refreshing state... [id=/subscriptions/afb1f74d-44fa-4ca2-a9b9-c32b85883eb0/resourceGroups/terraform-provider]
azurerm_storage_account.example: Refreshing state... [id=/subscriptions/afb1f74d-44fa-4ca2-a9b9-c32b85883eb0/resourceGroups/terraform-provider/providers/Microsoft.Storage/storageAccounts/terraform]
Terraform used the selected providers to generate the following execution plan. Resource
actions are indicated with the following symbols:
+ create
Terraform will perform the following actions:
# module.dns.azurerm_private_dns_zone.example will be created
+ resource "azurerm_private_dns_zone" "example" {
+ id = (known after apply)
+ max_number_of_record_sets = (known after apply)
+ max_number_of_virtual_network_links = (known after apply)
## ...
Plan: 3 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
module.dns.random_id.telem[0]: Creating...
module.dns.random_id.telem[0]: Creation complete after 0s [id=lrZvLg]
module.dns.azurerm_private_dns_zone.example: Creating...
module.dns.azurerm_resource_group_template_deployment.telemetry[0]: Creating...
module.dns.azurerm_resource_group_template_deployment.telemetry[0]: Creation complete after 6s [id=/subscriptions/afb1f74d-44fa-4ca2-a9b9-c32b85883eb0/resourceGroups/terraform-provider/providers/Microsoft.Resources/deployments/46d3xgtf.res.network-privatednszone.v0-1-0.96b66f2e]
module.dns.azurerm_private_dns_zone.example: Still creating... [00m10s elapsed]
module.dns.azurerm_private_dns_zone.example: Still creating... [00m20s elapsed]
module.dns.azurerm_private_dns_zone.example: Still creating... [00m30s elapsed]
module.dns.azurerm_private_dns_zone.example: Creation complete after 34s [id=/subscriptions/afb1f74d-44fa-4ca2-a9b9-c32b85883eb0/resourceGroups/terraform-provider/providers/Microsoft.Network/privateDnsZones/example.local]
Apply complete! Resources: 3 added, 0 changed, 0 destroyed.
The child module will automatically use the same default provider configuration as your root module.
Provider aliasing
Sometimes you need multiple configurations of the same provider in your
workspace. For example, you might want to create resources in multiple regions
or use different authentication credentials. Provider aliases allow you to
define multiple configurations of the same provider. When you define a provider
with the alias
argument set, you can add the provider
meta-argument and
specify your alternative provider configuration in resources, data sources, or
modules.
If you do not define a default provider block (without an alias
argument),
then Terraform will automatically generate a default provider configuration for
resources that use that provider. We recommend that you include explicit
provider blocks for every provider you define, to make your configuration easier
to understand.
Add a second Azure provider configuration with the storage_use_azuread
flag
set to true
, a resource group that uses this provider configured for East
US
, and a storage account:
main.tf
provider "azurerm" {
alias = "east"
storage_use_azuread = true
features {}
}
resource "azurerm_resource_group" "east" {
provider = azurerm.east
name = "terraform-provider-east"
location = "East US"
}
module "avm-res-storage-storageaccount_example" {
source = "Azure/avm-res-storage-storageaccount/azurerm"
version = "0.6.4"
providers = {
azurerm = azurerm.east
}
name = "module${random_string.suffix.result}"
location = azurerm_resource_group.example.location
resource_group_name = azurerm_resource_group.example.name
default_to_oauth_authentication = false
}
The storage_use_azuread
attribute configures the Azure provider to use Active
Directory to authenticate with the storage service. The provider
attribute on
the azurerm_resource_group.east
resource configures it to use the specified
provider alias.
The alias
argument to the provider block creates a named variant of that
provider. Modules use the
providers
argument to map provider aliases to their internal provider
requirements. Resources, data sources, and modules without an explicit
provider
argument use the default (non-aliased) provider. All provider blocks
will use the same version of the given provider.
Re-run terraform init
to install the new module.
$ terraform init
Initializing the backend...
Initializing modules...
Initializing provider plugins...
- Reusing previous version of hashicorp/azurerm from the dependency lock file
- Reusing previous version of hashicorp/random from the dependency lock file
- Finding azure/azapi versions matching ">= 1.14.0, < 3.0.0"...
- Finding azure/modtm versions matching "~> 0.3"...
- Using previously-installed hashicorp/azurerm v4.37.0
- Using previously-installed hashicorp/random v3.7.2
- Installing azure/azapi v2.5.0...
- Installed azure/azapi v2.5.0 (signed by a HashiCorp partner, key ID 6F0B91BDE98478CF)
- Installing azure/modtm v0.3.5...
- Installed azure/modtm v0.3.5 (signed by a HashiCorp partner, key ID 6F0B91BDE98478CF)
Partner and community providers are signed by their developers.
If you'd like to know more about provider signing, you can read about it here:
https://developer.hashicorp.com/terraform/cli/plugins/signing
Terraform has made some changes to the provider dependency selections recorded
in the .terraform.lock.hcl file. Review those changes and commit them to your
version control system if they represent changes you intended to make.
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.
Apply the configuration to create resources with the provider alias. Respond to
the confirmation prompt with a yes
.
$ terraform apply
module.avm-res-storage-storageaccount_example.data.modtm_module_source.telemetry[0]: Reading...
module.avm-res-storage-storageaccount_example.data.modtm_module_source.telemetry[0]: Read complete after 0s
module.dns.random_id.telem[0]: Refreshing state... [id=lrZvLg]
## ...
Terraform used the selected providers to generate the following execution plan. Resource
actions are indicated with the following symbols:
+ create
Terraform will perform the following actions:
# azurerm_resource_group.east will be created
+ resource "azurerm_resource_group" "east" {
+ id = (known after apply)
+ location = "eastus"
+ name = "terraform-provider-east"
## ...
Plan: 4 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
module.avm-res-storage-storageaccount_example.random_uuid.telemetry[0]: Creating...
module.avm-res-storage-storageaccount_example.random_uuid.telemetry[0]: Creation complete after 0s [id=6ab73d5b-49e2-4951-8737-8a054a3c5ce2]
module.avm-res-storage-storageaccount_example.modtm_telemetry.telemetry[0]: Creating...
azurerm_resource_group.east: Creating...
## ...
module.avm-res-storage-storageaccount_example.azurerm_storage_account.this: Still creating... [00m50s elapsed]
module.avm-res-storage-storageaccount_example.azurerm_storage_account.this: Still creating... [01m00s elapsed]
module.avm-res-storage-storageaccount_example.azurerm_storage_account.this: Creation complete after 1m9s [id=/subscriptions/afb1f74d-44fa-4ca2-a9b9-c32b85883eb0/resourceGroups/terraform-provider/providers/Microsoft.Storage/storageAccounts/terraformexample]
Apply complete! Resources: 4 added, 0 changed, 0 destroyed.
Clean up your infrastructure
Remove the infrastructure you created in this tutorial to avoid unnecessary charges.
Run terraform destroy
to remove your infrastructure. Respond to the
confirmation prompt with "yes".
$ terraform destroy
module.dns.random_id.telem[0]: Refreshing state... [id=lrZvLg]
module.avm-res-storage-storageaccount_example.random_uuid.telemetry[0]: Refreshing state... [id=6ab73d5b-49e2-4951-8737-8a054a3c5ce2]
module.avm-res-storage-storageaccount_example.data.modtm_module_source.telemetry[0]: Reading...
## ...
Plan: 0 to add, 0 to change, 10 to destroy.
Do you really want to destroy all resources?
Terraform will destroy all your managed infrastructure, as shown above.
There is no undo. Only 'yes' will be accepted to confirm.
Enter a value: yes
module.avm-res-storage-storageaccount_example.modtm_telemetry.telemetry[0]: Destroying... [id=92ceba95-bd20-4a69-9ee8-6e30b0456eaa]
module.avm-res-storage-storageaccount_example.modtm_telemetry.telemetry[0]: Destruction complete after 0s
module.avm-res-storage-storageaccount_example.random_uuid.telemetry[0]: Destroying... [id=6ab73d5b-49e2-4951-8737-8a054a3c5ce2]
## ...
azurerm_resource_group.example: Still destroying... [id=/subscriptions/afb1f74d-44fa-4ca2-a9b9-.../resourceGroups/terraform-provider, 00m20s elapsed]
azurerm_resource_group.example: Still destroying... [id=/subscriptions/afb1f74d-44fa-4ca2-a9b9-.../resourceGroups/terraform-provider, 00m30s elapsed]
azurerm_resource_group.example: Still destroying... [id=/subscriptions/afb1f74d-44fa-4ca2-a9b9-.../resourceGroups/terraform-provider, 00m40s elapsed]
azurerm_resource_group.example: Destruction complete after 48s
Destroy complete! Resources: 10 destroyed.
Next steps
In this tutorial, you learned how to manage Terraform providers in your configuration. You explored the Terraform registry, configured and versioned providers, handled authentication, used provider inheritance in modules, and implemented provider aliases for multi-region deployments.
To continue learning about Terraform providers:
- Read the provider configuration documentation.
- Learn about provider development
- Explore provider-specific tutorials for AWS, Azure, Google Cloud, and other platforms.
- Review the dependency lock file documentation for advanced version management.