Explaining Terraform Providers via `terraform` and `provider` keywords/blocks

The aim of this page📝 is to enhance my knowledge of Terraform provider plugins via the content analysis + dynamics of `terraform` and `provider` keywords and blocks.

Pavol Kutaj
3 min readOct 13, 2023
  • The commonly used providers are available at the public registry at terraform.io
  • It is useful to know you are not limited public registry
  • There are three tiers
  1. official, maintained by Hashicorp
  2. partner, maintained by 3rd party org with a direct relationship with Hashicorp
  3. community, maintained by individuals from the community — be aware
  • TF providers are open-source and written in the Go language
  • Providers are a collection of target-environment (aws, gcp, azure) specific datasources and resources enabling all of the Terraform functionality
  • Provider is downloaded into .terraform subfolder of your configurations as a default
  • Current AWS provider is ~330MB in size
  • Versioned by semver
  • You can use multiple instances of provider — e.g. AWS provider is limited to a region; it is required to have more > 1 for multi-region deploys

terraform keyword is used to configure settings related to Terraform and to define a required provider

  • provider information is defined in terraform config block called required providers
  • terraform keyword has info about ..required version of terraform ..back-end settings for state data ..required provider plugins ..provider metadata ..experimental language features

there are three main sections of terraform keyword: required versions, backend, provider requirements

terraform {
required_version = ">= 0.12.0"
required_providers {
aws = {
source = "hashicorp/aws"
version = ">= 3.0.0"
}
}
backend "s3" {
bucket = "my-terraform-state"
key = "terraform.tfstate"
region = "us-west-2"
}
}
  • required_version uses version constraints syntax is the same used for provider plugins
  • providers are defined in required_providers block
  • each key in the required_providers block (e.g. aws, google) is a specific <name_refererence> for provider plugins
  • the convention is to use the standard provider_name unless you are going to have multiple instances of the same plugin name (advanced topic, not addressed here)
  • the content for required_providers is
required_providers {
<provider_name> = {
<source> : <repo_location>
<version> = <version_constraint>
}
}
  • if you skip required_providers (is optional!), terraform will find the latest version of a provider in its public registry
  • how? It infers the name of the provider from the values in provider block, or even resource or data blocks
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 3.0"
}
}
  • by default, terraform assumes we’re using a public Terraform registry and the simple format for that is hashicorp/*

on version constraints

  • version constraints are essential if using terraform features not available in older versions of terraform
  • you can use any comparison operator, i.e. =, >, <, >=, <=
  • in addition a special character ~> allowing the right-most number to increment
  • i.e. in version = "~> 3.0", it says that any 3.x version is acceptable. here the rightmost number is allowed to increment
  • for example
terraform {
required_version = ">= 1.0, < 2.0"
}

when you initialize terraform with terraform init it creates .terraform.lock.hcl with metadata

  • this is a way to ensure that everyone in the team is using the same version of the provider, as multiple local machines can access the configuration directory with different configs
  • in my case
terraform {
required_version = "1.2.6"

backend "s3" {
encrypt = true
# This file is maintained automatically by "terraform init".
# Manual edits may be lost in future updates.

provider "registry.terraform.io/hashicorp/aws" {
version = "5.15.0"
hashes = [
"h1:XlodkDeDpZLtfjAkqHLHhvOjpO/LtuTVAjx0/0pJBf4=",
"zh:069d0037cd1f8791a27ec31a535ce47d02d4f220fe88f9c3caa8661c0a98892a",
"zh:08c18e8f5f69736e86919e6c2a68c94f39f879511d51b2a8e58ad1776ee18854",
"zh:41c9c95e225f72421fa4a1c3e5105f36b3b149cba1daf9bc88b0a993c1d19e07",
"zh:51e6cf850de8a8ae0e3b4e55b45ca2e6632a149c5851158f3c2711af51adb277",
"zh:5703eacc47d5a8169d1028f8cfcdf32cd12972ebea8780e870f520020280258a",
"zh:6a77e0406126208ae217c416e4b59940cd989df4d7d5ac23dfe8043725ff8f6a",
"zh:702cc6db865aeee571a639a81be3ed36326dcbda5c0a2ca91c9280772fce3e49",
"zh:8279822c5a267869d4459e429ad7b3b8ffaa36de2f6ca29cf7779214783ddf3a",
"zh:9b12af85486a96aedd8d7984b0ff811a4b42e3d88dad1a3fb4c0b580d04fa425",
"zh:bcb74854b0742a03b46e526bc2a79f556988c7622d54ebb2ccefc72c9759e9bc",
"zh:c7b0f4e94a9351a004a5555e91c8fe5b7da8cd2e03411cbd59d135ea8fceedd8",
"zh:cec427b1ef0e0948fd16736c72de57438fafcd8eeb5aab3bb1131579d2d6d031",
"zh:d5e4819851e52c15283064f6fa8cb8179a69cc981bee39e9b5ce5f027da8e251",
"zh:dade91d49309813b7453b053429678c8e7185e5ac54b2f68edb2ffea20242149",
"zh:e05e1395a738317a6761b592a5643ea5e660abd32de36ece68809cfd04a6a8e3",
]
}

`provider` keyword is where you configure a selected provider

provider "aws" {
region = "us-west-2"
access_key = "YOUR_ACCESS_KEY"
secret_key = "YOUR_SECRET_KEY"
profile = "YOUR_PROFILE"
shared_credentials_file = "YOUR_SHARED_CREDENTIALS_FILE"
}
  • provider block is usually defined after terraform block, with its contents specific to that provider plugin
  • for example for AWS
terraform {
required_version = "1.2.6"

backend "s3" {
encrypt = true
bucket = "<BUCKET_NAME>"
dynamodb_table = "<DYNAMODB_TABLE_NAME>"
region = "<AWS_REGION>"
key = "<KEY_NAME>"
}
}

provider "aws" {
region = "<AWS_REGION>"

assume_role {
role_arn = "<ROLE_ARN>"
}
}
  • or, for example for GCP provider - you can see that the contents are provider-specific
provider "google" {
project = "<PROJECT_NAME>"
impersonate_service_account = <SERVICE_ACCOUNT> == "" ? null : <SERVICE_ACCOUNT>
}

--

--

No responses yet