Terraform
Intermediate 17 min read Terraform

Provisioning AWS with Terraform

The AWS provider turns Terraform into your AWS console. Configure credentials and region, declare VPCs, security groups, EC2 and S3, and reuse it all with modules, tags and remote state.

AWSprovidercredentialsVPCEC2S3security grouptagsdata sourcesimport
Introduction

What is this?

The hashicorp/aws provider lets Terraform manage thousands of AWS services. You configure the provider with a region and credentials, then declare network, compute and storage resources in HCL. Multiple provider blocks target multiple regions or accounts, and remote state stores the results so teams share one source of truth.

Motivation

Why do you need it?

  • Fully declarative AWS infrastructure — no click-ops and no one-off console changes.
  • Every change is planned and reversible through the state file.
  • Dev, staging and prod reuse one configuration with different variables.
  • Combined with the S3 backend, the whole team manages AWS through code.
Think about it

Mental model

Imagine

A site plan handed to a foreman

Think of

A Terraform AWS configuration

The foreman reads the plan and directs each trade to build a structure — foundation (VPC), framing (subnets), wiring (security groups). Terraform reads your .tf plan and directs each AWS service to build exactly what is drawn.

Mechanics

How it works

  • Configure provider "aws" with a region; credentials come from the shared credentials file, env vars, or an IAM role.
  • Declare the network layer: VPC, subnets, internet gateway and route tables.
  • Declare compute and storage: EC2 instances, security groups with rules, S3 buckets.
  • References wire resources together, for example subnet_id = aws_subnet.pub.id.
  • Tags label every resource; outputs expose IPs and ARNs; plan reviews before apply.

A small AWS stack built by Terraform.

AWS provider
VPC + subnets
Security group
EC2 + S3
Outputs
Reference

Key commands

aws sts get-caller-identity

Verify your AWS credentials are valid before planning.

terraform providers

Confirm the AWS provider version resolved by the config.

terraform plan

Preview what will be created in AWS.

terraform apply

Create the declared AWS resources.

terraform state show aws_instance.web

Inspect the recorded attributes of the EC2 instance.

terraform import aws_instance.web i-1234567890abcdef0

Adopt an existing AWS resource into state.

terraform plan -destroy

Preview what destroy would remove.

Hands-on

Examples

A minimal web server stack

A minimal web server stack
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
}
provider "aws" {
region = "us-east-1"
}
data "aws_ami" "ubuntu" {
most_recent = true
filter {
name = "name"
values = ["ubuntu/images/hvm-ssd/ubuntu-jammy-22.04-amd64-server-*"]
}
owners = ["099720109477"]
}
resource "aws_vpc" "main" {
cidr_block = "10.0.0.0/16"
tags = { Name = "dev-vpc" }
}
resource "aws_subnet" "pub" {
vpc_id = aws_vpc.main.id
cidr_block = "10.0.1.0/24"
tags = { Name = "dev-pub" }
}
resource "aws_security_group" "web" {
vpc_id = aws_vpc.main.id
ingress {
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
}
resource "aws_instance" "web" {
ami = data.aws_ami.ubuntu.id
instance_type = "t3.micro"
subnet_id = aws_subnet.pub.id
vpc_security_group_ids = [aws_security_group.web.id]
tags = { Name = "dev-web" }
}
output "web_public_ip" {
value = aws_instance.web.public_ip
}

The data source always looks up the current Ubuntu AMI instead of hardcoding one, the resources reference each other by attribute, and the output exposes the instance IP. This is the shape of a real, reviewable AWS deployment.

Real world

In production

  • Landing zones: VPCs, IAM roles, logging and guardrails defined as code.
  • Ephemeral test environments created per PR and destroyed on schedule.
  • Kubernetes and serverless infrastructure (EKS, Lambda) alongside classic EC2.
  • Cost control: enforced tagging plus scheduled destroys for non-prod stacks.
Guidelines

Best practices

  • Always tag resources (Name, environment, owner, cost-center).
  • Prefer IAM roles and assume-role over long-lived access keys.
  • Pin the provider version and use data sources for AMIs — never hardcode.
  • Keep credentials out of config; use profiles, env vars or a credentials file.
  • Use one provider block per region when deploying multi-region stacks.
Watch out

Common mistakes

  • Hardcoding region-specific AMI IDs that drift or don't exist elsewhere.
  • Committing AWS access keys to configuration or repository.
  • Not tagging resources, making cost attribution impossible.
  • Editing security group rules directly in the AWS console instead of the config.
Root cause analysis

Common issues

Error
Error: configuring Terraform AWS Provider: no valid credential sources
Root cause

No credentials or region found by the provider.

Fix

Run aws configure or set AWS_ACCESS_KEY_ID/AWS_SECRET_ACCESS_KEY and AWS_REGION, then retry.

Error
Error: creating EC2 Instance: InsufficientInstanceCapacity
Root cause

The chosen instance type has no capacity in that Availability Zone.

Fix

Change the instance type or AZ, or retry later.

Error
Error: InvalidAMIID.NotFound
Root cause

The AMI ID does not exist in the configured region.

Fix

Use a data source to look up the AMI dynamically instead of a hardcoded ID.

When things break

Debugging tips

  • terraform providers verifies the resolved provider version before debugging resources.
  • aws sts get-caller-identity isolates credential problems from config problems.
  • TF_LOG=DEBUG terraform plan shows the exact AWS API calls and throttling errors.
  • Read the provider docs for argument names; terraform validate catches typos fast.
Interviews

Interview checkpoint

Practice

Hands-on lab

Provision a Web Server on AWS
40 min · intermediate
In progress
Objectives
  • Verify AWS credentials and configure the provider
  • Build a VPC, subnet, security group and EC2 instance
  • Use a data source for the AMI and read outputs
  • Import an existing resource and clean up with destroy

Provision a Web Server on AWS

40 min · intermediate

0/6 steps
0%
sandbox · Linux sandbox
$
Try these commands
Test yourself

Quick quiz

0/3
1

Which provider block configuration sets the target region?

2

Terraform can adopt existing AWS resources with terraform import.

3

Which command confirms your AWS credentials are usable?

Quick reference

Cheat sheet

AWS + Terraform
aws configureStore credentials locally
aws sts get-caller-identityVerify credentials
provider "aws" { region = ... }Set region
data "aws_ami" "ubuntu" {}Look up current AMI
tags = { Name = "web" }Tag every resource
terraform import aws_instance.web i-123Adopt existing resource
Go deeper

Official documentation