Terraform Associate
Deep Dive
Providers are the bridge between Terraform and external APIs. Understanding their plugin architecture, support tiers, and advanced configuration is essential for the exam.
Contents
Terraform is split into two main components that communicate through an RPC protocol over gRPC:
Terraform Core
terraformTerraform Providers (plugins)
.terraform/providers/💡 Why separate plugins
Separating Core from Providers allows: (1) the core doesn't need to be recompiled when new APIs are added, (2) providers can have their own release cycle, (3) any company can build its own provider without modifying Terraform Core.
| Tier | Maintained by | Registry namespace | Examples |
|---|---|---|---|
| Official | HashiCorp | hashicorp/ | hashicorp/aws, hashicorp/azurerm, hashicorp/google |
| Partner | Technology company with a HashiCorp agreement | company/ | datadog/datadog, mongodb/mongodbatlas, pagerduty/pagerduty |
| Community | Open-source community | anyone/ | kreuzwerker/docker, hashicorp/dns (deprecated examples) |
🎯 For the exam
Official providers are maintained by HashiCorp and have the highest level of support and testing. The source of an official provider always starts with hashicorp/. The exam may ask you about the difference between official, partner, and community.
Always declare the providers you use in the required_providers block inside terraform . Specifying the version is a mandatory best practice in production.
terraform {
required_version = ">= 1.6.0"
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0" # >= 5.0.0, < 6.0.0
}
random = {
source = "hashicorp/random"
version = "= 3.5.1" # exact version
}
datadog = {
source = "DataDog/datadog"
version = ">= 3.20.0"
}
}
}| Operator | Meaning | Example |
|---|---|---|
| ~> | Pessimistic constraint: only increments the last segment | ~> 5.0 = >=5.0, <6.0 | ~> 5.2.1 = >=5.2.1, <5.3 |
| >= | Greater than or equal to | >= 5.0 = any version 5.0 or higher |
| <= | Less than or equal to | <= 5.9 = up to and including 5.9 |
| = | Exact version (hard pin) | = 5.31.0 = only that version |
| != | Excludes a specific version | != 5.10.0 = any version except 5.10.0 |
| > | Strictly greater than | > 5.0 = from 5.0.1 onward |
💡 ~> is the most used operator on the exam
~> 5.0 means "5.x but not 6.x". ~> 5.2.1 means "5.2.x but not 5.3". The difference lies in which segment is the "last" one allowed to increment.
After terraform init, the lock file is generated, pinning the exact versions installed, even if the constraint allows a range.
# .terraform.lock.hcl — auto-generated, IS committed
provider "registry.terraform.io/hashicorp/aws" {
version = "5.31.0" # exact installed version
constraints = "~> 5.0" # constraint from required_providers
hashes = [
"h1:HASH_FOR_CURRENT_PLATFORM",
"zh:CROSS_VERIFICATION_HASH",
]
}
# To add hashes for other platforms (e.g. CI uses Linux, devs use Mac):
# terraform providers lock -platform=linux_amd64 -platform=darwin_arm64✅ Why commit the lock file
⚠️ Don't confuse it with tfstate
When you need multiple configurations of the same provider (for example, two AWS regions or two accounts), you use the alias argument.
# Two AWS regions in the same module
provider "aws" {
region = "us-east-1"
# No alias = default provider
}
provider "aws" {
alias = "west"
region = "us-west-2"
}
# Use the aliased provider in a resource
resource "aws_vpc" "main" {
cidr_block = "10.0.0.0/16"
# Uses the default provider (us-east-1)
}
resource "aws_vpc" "disaster_recovery" {
provider = aws.west # reference: provider_name.alias
cidr_block = "10.1.0.0/16"
}
# Pass an aliased provider to a module
module "vpc_west" {
source = "./modules/vpc"
providers = {
aws = aws.west # provider map for the module
}
}Child modules automatically inherit the default provider from the root module. You only need the providers argument when using an alias or when you want to override the inherited provider.
| Scenario | Needs providers = {}? | Reason |
|---|---|---|
| Module uses a single provider, same as root | ❌ No | Automatically inherits the default provider from the root |
| Module uses a provider with an alias | ✅ Yes | You must map which root alias corresponds to the module's provider |
| Module needs a provider different from the root | ✅ Yes | The root explicitly passes the correct provider to the module |
| Multi-provider module (e.g.: aws + random) | ✅ Yes | Each provider used by the module must be mapped explicitly |
Did you get this topic?
Test what you just learned
A Terraform module needs to create resources in two different AWS accounts. How should this be configured correctly?
Put what you learned to the test with original Terraform Associate exam questions.
Start Terraform Associate mock examUnlimited mock exams with the Pro plan
Log in to track your progress.