Provisioning AWS Resources
AWS is the most widely used Terraform provider, and the hashicorp/aws provider exposes hundreds of resource types covering compute, networking, storage, IAM, and managed services. Provisioning AWS infrastructure with Terraform follows a consistent pattern regardless of the specific service: configure the provider block with a region (and typically rely on credentials from the environment or an IAM role rather than hardcoding them), then declare resource blocks whose arguments map closely to the fields you'd otherwise set in the AWS console or via the AWS CLI.
Cricket analogy: Just as the IPL is the most-watched league with dozens of standardized match formats covering batting, bowling, and fielding roles, AWS is the most widely used provider with hundreds of resource types spanning every infrastructure need.
Configuring the provider
The aws provider block accepts a region argument and, optionally, a profile or explicit access key/secret pair, though the strongly recommended practice is to leave credentials out of the configuration entirely and let the AWS SDK's standard credential chain resolve them from environment variables, an EC2/ECS instance role, or an assumed role via STS. Pinning the provider version with a required_providers block prevents an unexpected major-version upgrade of the AWS provider from silently changing resource schemas between applies.
Cricket analogy: A visiting team doesn't carry cash to bribe local officials; they rely on the board's official accreditation chain to grant ground access, and they lock the tour itinerary's format version so a late rule change doesn't upend it.
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
}
provider "aws" {
region = "us-east-1"
# Credentials resolved from environment variables or an assumed IAM role,
# not hardcoded here.
}A typical compute and networking stack
A common baseline stack provisions a VPC, at least one subnet, a security group, and an EC2 instance, wired together through implicit dependencies. Real-world configurations almost always also attach an IAM instance profile so the instance can call other AWS services without embedded credentials, and use data sources like aws_ami to look up the latest approved AMI rather than hardcoding an AMI ID that will eventually go stale.
Cricket analogy: A domestic team fields a full XI with an opener, a wicketkeeper, and specialist bowlers wired together by role, and a well-run franchise also grants players a dedicated support staff badge rather than sharing one generic pass among everyone.
data "aws_ami" "amazon_linux" {
most_recent = true
owners = ["amazon"]
filter {
name = "name"
values = ["al2023-ami-*-x86_64"]
}
}
resource "aws_security_group" "web" {
name = "web-sg"
vpc_id = aws_vpc.main.id
ingress {
from_port = 443
to_port = 443
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
}
resource "aws_instance" "web" {
ami = data.aws_ami.amazon_linux.id
instance_type = "t3.micro"
subnet_id = aws_subnet.main.id
vpc_security_group_ids = [aws_security_group.web.id]
tags = {
Name = "web-server"
Environment = "production"
}
}Terraform's AWS provider is essentially a thin, declarative layer over the AWS API: nearly every resource argument maps directly to a field in the corresponding AWS API request, which is why the AWS API reference is often the fastest way to understand what an unfamiliar resource argument actually controls.
Storage resources such as aws_s3_bucket and aws_db_instance require extra care: an accidental terraform destroy or a misconfigured lifecycle can permanently delete data. Use prevent_destroy in a lifecycle block and enable versioning/deletion protection on stateful resources in production.
Managed services and IAM
Beyond raw compute, most production AWS stacks provision managed services — RDS databases, S3 buckets, Lambda functions, ECS/EKS clusters — alongside the IAM roles and policies that let those services talk to each other securely. Because IAM resources are cheap to create and central to least-privilege security, well-structured AWS Terraform configurations typically define a dedicated IAM role and a narrowly scoped policy document per workload rather than reusing broad, shared roles.
Cricket analogy: Beyond the playing XI, a franchise also runs an academy, a physio unit, and a media team, each given narrowly scoped access to specific facilities rather than every staff member sharing one master keycard to the whole complex.
- Pin the AWS provider version with required_providers to avoid unexpected schema changes on upgrade.
- Avoid hardcoding AWS credentials in configuration; rely on the standard credential chain (env vars, instance roles, assumed roles).
- Use data sources like aws_ami to avoid hardcoding values (like AMI IDs) that go stale over time.
- Wire compute, networking, and security group resources together through implicit dependencies on their attributes.
- Attach narrowly scoped IAM roles/policies per workload instead of reusing broad shared roles.
- Protect stateful resources (RDS, S3) with lifecycle prevent_destroy and versioning/deletion protection.
Practice what you learned
1. What is the recommended way to supply AWS credentials to the Terraform aws provider?
2. Why use the aws_ami data source instead of hardcoding an AMI ID?
3. What does required_providers with a version constraint like "~> 5.0" protect against?
4. What lifecycle setting helps prevent accidental deletion of a stateful resource like an RDS database?
5. What is a recommended IAM practice for AWS resources provisioned via Terraform?
Was this page helpful?
You May Also Like
Provisioning Azure and GCP Resources
Understand how the azurerm and google providers differ from AWS in structure and authentication, with practical examples of provisioning core resources on each cloud.
Providers Explained
Providers are Terraform plugins that translate HCL resource definitions into API calls against a specific platform, such as AWS, Azure, GCP, or Kubernetes.
Data Sources Explained
Learn how Terraform data sources let you read information about existing infrastructure or external systems without managing it, so configurations can reference real-world values.
Secrets Management in Terraform
Learn how to keep API keys, passwords, and certificates out of your Terraform code and state, using dedicated secret stores and encryption strategies.
Related Reading
Related Study Notes in DevOps
Browse all study notesNginx Study Notes
DevOps · 30 topics
DevOpsAnsible Study Notes
DevOps · 30 topics
DevOpsAdvanced Kubernetes Study Notes
Kubernetes · 30 topics
DevOpsAdvanced Bash Scripting Study Notes
Bash · 30 topics
DevOpsApache Kafka Study Notes
Kafka · 30 topics
DevOpsDocker & Kubernetes Study Notes
YAML · 40 topics