Post

A Simple AWS Setup with Terraform

A step-by-step guide to deploying a VPC, EC2, and S3 on AWS using Terraform.


A Simple AWS Setup with Terraform

This post details my process of provisioning a basic AWS environment using Terraform, a tool I applied to manage a VPC, subnet, EC2 instance, and S3 bucket. Drawing on my experience with AWS and GCP, I documented the steps and challenges to demonstrate Infrastructure as Code in a familiar cloud setting.

Setting Up the Prerequisites

I started by installing Terraform and the AWS CLI, then configured AWS credentials with a dedicated IAM user.

Install Terraform:

  1. Visit https://developer.hashicorp.com/terraform/install.
  2. Download the binary for your OS (e.g., macOS, Windows).
  3. Unzip the file and move it to a directory in your PATH:
    • macOS/Linux: sudo mv terraform /usr/local/bin/ (ensure /usr/local/bin is in your PATH).
    • Windows: Add to C:\Program Files and update PATH in System Settings.
  4. Verify the installation: terraform --version (e.g., v1.9.x as of April 2025).

Install and Configure AWS CLI

Install the AWS CLI from https://aws.amazon.com/cli/, then configure it:

1
2
aws configure
# Enter Access Key, Secret Key, region (e.g., us-west-2), output (json)

Using an existing AWS account, I created an IAM user (terraform-demo-user) for Terraform to manage resources like EC2 and S3. Initial runs failed with “Access Denied” errors due to missing permissions. I resolved this by defining a minimal policy, following the principle of least privilege.

AWS error messages (e.g., not authorized to perform: s3:GetBucketAcl) indicate missing permissions—start with basic access and adjust as needed. For production, avoid storing Access Keys in plain text; use IAM roles or AWS Secrets Manager instead.

Writing the Terraform Configuration

I created a GitHub repository (terraform-aws-demo) and defined the resources in main.tf:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
provider "aws" {
  region = "us-west-2"
}

resource "aws_vpc" "main" {
  cidr_block = "10.0.0.0/16"
  tags = {
    Name = "demo-vpc"
  }
}

resource "aws_subnet" "public" {
  vpc_id     = aws_vpc.main.id
  cidr_block = "10.0.1.0/24"
}

resource "aws_instance" "web" {
  ami           = "ami-0c2ab3d2efb3b2f5" # Amazon Linux 2, us-west-2
  instance_type = "t2.micro"
  subnet_id     = aws_subnet.public.id
  tags = {
    Name = "demo-web"
  }
}

resource "aws_s3_bucket" "storage" {
  bucket = "my-demo-bucket-${random_string.suffix.result}"
  tags = {
    Name = "demo-bucket"
  }
}

resource "random_string" "suffix" {
  length  = 8
  special = false
  upper   = false
}

This configuration a VPC (10.0.0.0/16), a public subnet (10.0.1.0/24), an EC2 instance (t2.micro), and an S3 bucket with a random suffix.

Applying the Infrastructure

I deployed the resources using these commands:

1
2
3
terraform init
terraform plan -out=plan.tfplan
terraform apply "plan.tfplan"

Save the plan file terraform plan -out=plan.tfplan to ensure the reviewed plan matches what’s applied, reducing the risk of errors.

The first terraform apply failed due to an invalid AMI ID (ami-0c55b159cbfafe1f0). I had to update it to a valid Amazon Linux 2 AMI for us-west-2 (ami-0c2ab3d2efb3b2f5). The S3 bucket name also failed validation due to uppercase characters in the random suffix, so I set upper = false in the random_string resource.

Visualizing the Architecture

To better understand my setup, I created an architecture diagram using draw.io. The diagram shows the VPC, public subnet, EC2 instance, and S3 bucket, with an Internet Gateway to enable public access to S3:

Desktop View Terraform-Generated AWS Cloud Infrastructure Diagram

Cleaning Up

I removed the resources to avoid AWS charges:

1
terraform destroy

Always run terraform destroy after testing to prevent unexpected costs, especially with cloud resources.

Conclusion

This Terraform project provided a straightforward way to apply Infrastructure as Code on AWS. Addressing issues like AMI IDs and S3 naming refined my approach to provisioning cloud resources. It’s a useful exercise for exploring DevOps and SRE workflows in a controlled setup.

This post is licensed under CC BY 4.0 by the author.