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.
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
- official, maintained by Hashicorp
- partner, maintained by 3rd party org with a direct relationship with Hashicorp
- 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 evenresource
ordata
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 any3.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 afterterraform
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>
}