Step-by-Step Guide: Configuring Terraform for AWS

Terraform has become the go-to tool for infrastructure as code, allowing teams to define, provision, and manage cloud resources efficiently. In this tutorial, we’ll walk through configuring Terraform for AWS, covering workspaces, remote backends, modules, variables with validations, and .tfvars management.
Prerequisites
Before starting, ensure you have:
- Terraform installed
- An AWS account with IAM credentials configured
- AWS CLI installed and configured
1. Setting Up Terraform Workspaces
Terraform workspaces allow you to manage multiple environments (e.g., dev, staging, prod) from the same configuration.
# Initialize Terraform
terraform init
# Create a new workspace for dev
terraform workspace new dev
# Switch between workspaces
terraform workspace select dev
# List all workspaces
terraform workspace list
Each workspace maintains its own state file, enabling isolated environments.
2. Configuring a Remote Backend with S3
Storing Terraform state in an S3 bucket with optional DynamoDB for state locking is recommended for team collaboration.
Example backend.tf:
terraform {
backend "s3" {
bucket = "my-terraform-states"
key = "project/terraform.tfstate"
region = "us-east-1"
dynamodb_table = "terraform-lock"
encrypt = true
}
}
- bucket: The S3 bucket to store state files
- key: The path within the bucket
- dynamodb_table: Optional, for state locking to prevent conflicts
- encrypt: Ensure state files are encrypted
After defining the backend:
terraform init
Terraform will automatically migrate your local state to the remote backend.
3. Using Terraform Modules
Modules allow you to encapsulate and reuse configurations.
Example: Creating an S3 Module
modules/s3/main.tf:
resource "aws_s3_bucket" "this" {
bucket = var.bucket_name
acl = var.acl
}
output "bucket_id" {
value = aws_s3_bucket.this.id
}
modules/s3/variables.tf:
variable "bucket_name" {
type = string
description = "Name of the S3 bucket"
}
variable "acl" {
type = string
description = "Access control list"
default = "private"
}
Use the module in your main configuration:
module "my_s3_bucket" {
source = "./modules/s3"
bucket_name = "my-app-bucket"
}
4. Defining Variables and Validations
Terraform variables improve configuration flexibility and safety.
Example variables.tf:
variable "environment" {
type = string
description = "Deployment environment"
validation {
condition = contains(["dev", "staging", "prod"], var.environment)
error_message = "Environment must be one of dev, staging, or prod"
}
}
variable "instance_count" {
type = number
description = "Number of EC2 instances"
default = 1
validation {
condition = var.instance_count > 0
error_message = "Instance count must be greater than 0"
}
}
This ensures that incorrect values are caught early.
5. Managing .tfvars Files
Terraform variables can be injected via .tfvars files or environment variables.
Example dev.auto.tfvars:
environment = "dev"
instance_count = 2
- .auto.tfvars files are automatically loaded by Terraform.
- Other .tfvars files can be passed explicitly:
terraform plan -var-file="staging.tfvars"
You can also inject variables via environment variables:
export TF_VAR_environment=prod
export TF_VAR_instance_count=3
terraform apply
This flexibility allows secure and environment-specific configuration without changing the main Terraform code.
Conclusion
By combining workspaces, remote S3 backends, reusable modules, variables with validations, and flexible .tfvars injection, you can build a robust and maintainable Terraform setup for AWS. These practices ensure:
- Environment isolation
- Team collaboration with state locking
- Reusable infrastructure components
- Safe and predictable deployments
Terraform becomes a powerful tool when these patterns are implemented correctly.