Terraform Journey: From Zero to Launching EC2 on AWS
My hands-on journey learning Terraform by deploying EC2 instances on AWS, including challenges faced and security considerations.
Terraform Journey: From Zero to Launching EC2 on AWS
🧠 Why I Chose Terraform
Coming from a project management and academic background, I wanted to actually build things — infrastructure included. I chose Terraform because:
- Declarative Syntax: Write what you want, not how to get there
- Multi-Cloud Ready: Works with AWS, Azure, GCP and more
- DevSecOps Integration: Fits perfectly in CI/CD pipelines
- Community Support: 1,000+ providers and modules available
🛠️ Core Concepts I Learned
1. Infrastructure as Code Fundamentals
- Providers: The
aws
provider connects Terraform to AWS API - Resources: Building blocks like
aws_instance
,aws_vpc
- State Management: The critical
.tfstate
file - Plan/Apply Cycle:
terraform plan
→ review →terraform apply
2. AWS Networking Basics
1
2
3
4
5
6
7
8
# Network Foundation
resource "aws_vpc" "main" {
cidr_block = "10.0.0.0/16"
tags = {
Name = "Terraform-VPC"
}
}
🔧 EC2 Deployment Walkthrough
Step 1: Configure AWS Provider
1
2
3
4
5
6
provider "aws" {
region = "eu-central-1"
# Never hardcode credentials!
# Use environment variables or AWS CLI config
}
Step 2: Create Security Group
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
resource "aws_security_group" "allow_ssh" {
name = "allow_ssh"
description = "Allow SSH inbound traffic"
vpc_id = aws_vpc.main.id
ingress {
description = "SSH from anywhere"
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"] # Restrict this in production!
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
}
Step 3: Launch EC2 Instance
1
2
3
4
5
6
7
8
9
10
resource "aws_instance" "web" {
ami = "ami-0c55b159cbfafe1f0" # Amazon Linux 2
instance_type = "t2.micro"
key_name = "terraform-key"
vpc_security_group_ids = [aws_security_group.allow_ssh.id]
tags = {
Name = "Terraform-EC2"
}
}
🚧 Challenges & Solutions
Challenge | Symptom | Root Cause | Solution |
---|---|---|---|
SSH Timeout | Connection refused | Missing Internet Gateway | Added IGW and route table |
State File Lost | “Resource doesn’t exist” | Accidental deletion | Configured S3 backend |
Cost Surprise | Unexpected AWS charges | Left instances running | Added terraform destroy step |
🔒 Security Lessons
- Secrets Management
- Never commit
.tfvars
files with credentials - Use AWS Secrets Manager or environment variables
- Never commit
- Least Privilege
1 2 3 4 5
# Bad cidr_blocks = ["0.0.0.0/0"] # Good cidr_blocks = ["203.0.113.12/32"] # Your IP only
- State Protection
- Enable S3 bucket versioning
- Use DynamoDB for state locking
✅ What’s Next
- Advanced Terraform
- Modules for reusability
- Workspaces for environments
- Sentinel policies for governance
- DevSecOps Integration
graph LR
A[Terraform Code] --> B[GitHub PR]
B --> C[Checkov Scan]
C --> D[Jenkins Pipeline]
D --> E[AWS Deployment]
🔗 Resources
Thanks for reading. May your pipelines be green, your infra be tagged, and your security posture be strong!
🔗 Explore my other blogs at opsbygandal.dev
📁 Check out the GitHub repo [https://github.com/gandalops/portfolio-chirpy]
🔄 Let’s connect on LinkedIn
This post is licensed under
CC BY 4.0
by the author.