Learning objectives
By the end of this module, you should be able to:
- Read blocks, arguments and expressions in HCL.
- Explain required_providers and provider configuration.
- Identify resource addresses and distinguish them from provider-side IDs.
HCL is structured configuration
Terraform configuration is made of blocks, arguments and expressions. Block labels such as resource type and local name form addresses used throughout plans, state and references.
Providers translate Terraform operations
Providers implement resource and data-source behavior for external APIs. required_providers declares source addresses and version constraints; provider blocks configure instances of those providers.
Addresses are Terraform identities
An address such as aws_instance.web or terraform_data.example["api"] identifies a managed instance in Terraform. A cloud-side ID such as an instance ID is a different concept and is typically stored as an attribute.
Worked examples
See the idea in practice.
Provider constraint pattern
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 6.0"
}
}
}
- Version constraints belong in configuration.
- .terraform.lock.hcl records concrete provider selections for repeatability.
Resource address
terraform_data.service["api"]
- The type is terraform_data, the local name is service, and api is the for_each key.
Hands-on lab
Lab — Read HCL and resource addresses
Goal: Create multiple built-in resources and inspect their stable addresses.
STEP 1Create resources
mkdir -p ~/gnu-terraform-labs/module02 && cd ~/gnu-terraform-labs/module02
cat > main.tf <<'EOF'
resource "terraform_data" "service" {
for_each = toset(["api", "worker"])
input = each.key
}
EOF
STEP 2Initialize and apply
terraform init
terraform apply -auto-approve
STEP 3List state addresses
terraform state list
STEP 4Inspect one instance
terraform state show 'terraform_data.service["api"]'
Verify
- State contains service["api"] and service["worker"].
- state show displays the selected object attributes.
Expected outcome
- You can parse a Terraform resource address without confusing it with a remote provider ID.
If it fails
- Quote addresses containing brackets so the shell does not interpret them.
- If state is empty, confirm apply completed successfully.
Real-world connectionAccurate addressing is essential for imports, state operations, moved blocks and targeted diagnostics.
Avoid these traps
Common mistakes
- Using unconstrained provider versions in long-lived production modules.
- Confusing a resource local name with its remote ID.
- Editing .terraform provider plugin files manually.
Knowledge check
Can you explain it without looking back?
Open each answer only after you have tried to answer the question yourself.
1What does required_providers declare?
Provider source addresses and acceptable version constraints.
2What is terraform_data.service["api"]?
A Terraform resource instance address.
3Where is the selected provider version recorded?
In .terraform.lock.hcl after initialization.