Providers and Resources¶
Overview¶
This document covers Terraform providers, resource management, data sources, and dependency handling. Providers are the bridge between Terraform and cloud APIs, and understanding how they work is essential for the exam. This maps to parts of Domain 3 (Understand Terraform basics - 20%).
π Providers Overview - Provider system documentation
Providers¶
What Are Providers?¶
- Plugins that enable Terraform to interact with cloud platforms and services
- Each provider offers resources and data sources for a specific platform
- Distributed separately from Terraform core
- Downloaded and cached during
terraform init - Examples: aws, azurerm, google, kubernetes, docker, vault
Provider Configuration¶
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
azurerm = {
source = "hashicorp/azurerm"
version = ">= 3.0, < 4.0"
}
}
}
provider "aws" {
region = "us-east-1"
profile = "production"
}
π Provider Configuration - Provider setup and authentication π Provider Requirements - Required providers block syntax
Provider Source Addresses¶
- Format:
<HOSTNAME>/<NAMESPACE>/<TYPE> - Default hostname:
registry.terraform.io - Examples:
hashicorp/aws(short forregistry.terraform.io/hashicorp/aws)hashicorp/azurermhashicorp/googleintegrations/github
Version Constraints¶
| Operator | Meaning | Example |
|---|---|---|
= | Exact version | = 5.0.0 |
!= | Not equal to | != 5.0.0 |
> | Greater than | > 5.0.0 |
>= | Greater than or equal | >= 5.0.0 |
< | Less than | < 6.0.0 |
<= | Less than or equal | <= 5.9.9 |
~> | Pessimistic constraint | ~> 5.0 (allows 5.x, not 6.0) |
The ~> operator is critical for the exam: - ~> 5.0 allows 5.1, 5.2, ... but not 6.0 - ~> 5.0.0 allows 5.0.1, 5.0.2, ... but not 5.1.0 - Only the rightmost version component is allowed to increment
Provider Aliases¶
provider "aws" {
region = "us-east-1"
}
provider "aws" {
alias = "west"
region = "us-west-2"
}
# Use default provider
resource "aws_instance" "east" {
ami = "ami-east-12345"
instance_type = "t3.micro"
}
# Use aliased provider
resource "aws_instance" "west" {
provider = aws.west
ami = "ami-west-67890"
instance_type = "t3.micro"
}
- Only one default (non-aliased) provider per type
- Aliased providers must be explicitly referenced
- Useful for multi-region or multi-account deployments
π Provider Aliases - Multiple provider configurations
Dependency Lock File¶
.terraform.lock.hclis created duringterraform init- Records exact provider versions and checksums
- Should be committed to version control
- Ensures reproducible builds across team members
- Update with
terraform init -upgrade
π Dependency Lock File - Lock file management
Resources¶
Resource Block Structure¶
resource "<PROVIDER>_<TYPE>" "<LOCAL_NAME>" {
argument1 = "value1"
argument2 = "value2"
nested_block {
key = "value"
}
}
- Provider type prefix: The part before the underscore (e.g.,
awsinaws_instance) - Resource type: The full type name (e.g.,
aws_instance) - Local name: Used only within the Terraform configuration for references
- Arguments: Configuration values you set
- Attributes: Values computed by the provider after creation
Resource Behavior¶
| State | Config | Action |
|---|---|---|
| Not in state | In config | Create |
| In state | Not in config | Destroy |
| In state | In config (changed, mutable) | Update in-place |
| In state | In config (changed, immutable) | Destroy and re-create |
π Resource Behavior - How Terraform manages resource lifecycle
Meta-Arguments¶
depends_on¶
resource "aws_instance" "web" {
depends_on = [aws_iam_role_policy.web_policy]
# ...
}
π depends_on - Explicit dependencies
count¶
resource "aws_instance" "web" {
count = var.create_instances ? 3 : 0
ami = "ami-12345678"
instance_type = "t3.micro"
tags = { Name = "web-${count.index}" }
}
count.index provides the current iteration number (0-based) - Resources referenced as aws_instance.web[0], aws_instance.web[1], etc. - Removing items from the middle causes renumbering and recreation π count - Count meta-argument
for_each¶
resource "aws_instance" "web" {
for_each = toset(["alpha", "beta", "gamma"])
ami = "ami-12345678"
instance_type = "t3.micro"
tags = { Name = each.key }
}
each.key and each.value reference current item - Resources referenced as aws_instance.web["alpha"] - Safe for additions/removals (no renumbering) - Cannot use count and for_each together π for_each - For_each meta-argument
lifecycle¶
resource "aws_instance" "web" {
lifecycle {
create_before_destroy = true # Create replacement before destroying original
prevent_destroy = true # Prevent accidental destruction
ignore_changes = [tags] # Ignore external tag changes
replace_triggered_by = [null_resource.trigger.id]
}
}
π lifecycle - Lifecycle customization
count vs for_each Decision Guide¶
| Criteria | count | for_each |
|---|---|---|
| Resources are identical | Yes | Works but unnecessary |
| Resources have unique attributes | No (use index only) | Yes (use key/value) |
| Adding/removing items | Causes renumbering | Safe, no side effects |
| Conditional creation | count = condition ? 1 : 0 | Use with filtered map |
| Data type | Number | Set or map |
Data Sources¶
Purpose¶
- Query existing infrastructure not managed by current configuration
- Read external data for use in resource configuration
- Populated during the plan phase (before apply)
data "aws_vpc" "main" {
filter {
name = "tag:Name"
values = ["main-vpc"]
}
}
data "aws_subnets" "private" {
filter {
name = "vpc-id"
values = [data.aws_vpc.main.id]
}
filter {
name = "tag:Tier"
values = ["private"]
}
}
resource "aws_instance" "web" {
subnet_id = data.aws_subnets.private.ids[0]
# ...
}
π Data Sources - Data source configuration
Data Sources vs Resources¶
| Aspect | Resource | Data Source |
|---|---|---|
| Purpose | Create/manage infrastructure | Read existing infrastructure |
| State | Tracked in state file | Tracked in state file |
| Lifecycle | Create, update, destroy | Read-only, refreshed each plan |
| Reference | <type>.<name> | data.<type>.<name> |
Dependency Management¶
Implicit Dependencies¶
resource "aws_vpc" "main" {
cidr_block = "10.0.0.0/16"
}
resource "aws_subnet" "web" {
vpc_id = aws_vpc.main.id # Implicit dependency on VPC
cidr_block = "10.0.1.0/24"
}
Explicit Dependencies¶
resource "aws_instance" "web" {
depends_on = [aws_iam_role_policy.web_policy]
}
Resource Graph¶
- Terraform builds a directed acyclic graph (DAG) of all resources
- Determines creation order based on dependencies
- Enables parallel creation of independent resources
- View with
terraform graph(outputs DOT format)
π Resource Graph - Dependency graph internals
Key Exam Points¶
Provider Topics¶
- Provider source address format and default registry
- Version constraint operators, especially
~> - Provider aliases for multi-region deployments
- Lock file purpose and management
- Provider download during
terraform init
Resource Topics¶
- Resource behavior: create, update, replace, destroy
- Meta-arguments: count, for_each, depends_on, lifecycle, provider
- count vs for_each: when to use each
- Implicit vs explicit dependencies
- Data sources vs resources