Power of Terraform
I was recently approached by the sales team to explain the benefits of the cloud and, more importantly, why automation is such a game-changer. It struck me that the concept of DevOps still isn’t fully understood by everyone.
To put things into perspective, I remembered how, back in the day, setting up a LAMP stack (Apache, MySQL, PHP) could easily take an entire day—especially if you were dealing with more challenging Linux distributions like Gentoo. Fast forward to today: thanks to tools like Terraform and platforms like AWS, that same setup can now be done in mere minutes.
But enough theory—let’s get practical. Below is the code that demonstrates the power of automation. This script will:
- Create a VPC
- Set up subnets
- Add an Internet Gateway (IGW)
- Configure security groups
- Provision an RDS instance
- Deploy an Ubuntu VM and configure it to present data from a database on a simple webpage.
The speed and reliability that automation brings not only save time but also redefine how teams approach infrastructure and operations.
Please note this is a simple demo and does not goes in depth with security or containers. ( maybe in another episode)
NB: for obvious reasons please use more complex passwords
resource "aws_vpc" "demo_vpc" {
cidr_block = "10.100.0.0/16"
}
resource "aws_subnet" "demo_subnet_a" {
vpc_id = aws_vpc.demo_vpc.id
cidr_block = "10.100.1.0/24"
availability_zone = "eu-central-1a"
map_public_ip_on_launch = true
}
resource "aws_subnet" "demo_subnet_b" {
vpc_id = aws_vpc.demo_vpc.id
cidr_block = "10.100.2.0/24"
availability_zone = "eu-central-1b"
map_public_ip_on_launch = true
}
resource "aws_security_group" "demo_sg" {
vpc_id = aws_vpc.demo_vpc.id
ingress {
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
ingress {
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
ingress {
from_port = 3306
to_port = 3306
protocol = "tcp"
cidr_blocks = ["10.100.0.0/16"] # Allow DB access from within the VPC
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
}
resource "aws_db_subnet_group" "demo_subnet_group" {
name = "demo-subnet-group"
subnet_ids = [
aws_subnet.demo_subnet_a.id,
aws_subnet.demo_subnet_b.id
]
}
# Create an Internet Gateway
resource "aws_internet_gateway" "demo_igw" {
vpc_id = aws_vpc.demo_vpc.id
}
# Create a Route Table for the VPC
resource "aws_route_table" "demo_route_table" {
vpc_id = aws_vpc.demo_vpc.id
route {
cidr_block = "0.0.0.0/0"
gateway_id = aws_internet_gateway.demo_igw.id
}
}
# Associate the Route Table with the Subnets
resource "aws_route_table_association" "demo_subnet_a" {
subnet_id = aws_subnet.demo_subnet_a.id
route_table_id = aws_route_table.demo_route_table.id
}
resource "aws_route_table_association" "demo_subnet_b" {
subnet_id = aws_subnet.demo_subnet_b.id
route_table_id = aws_route_table.demo_route_table.id
}
resource "aws_db_instance" "demo_rds" {
allocated_storage = 20
engine = "mysql"
engine_version = "8.0.39" # Replace with a supported version
instance_class = "db.t3.micro" # Use a valid instance class
username = "root"
password = "password123"
publicly_accessible = false
vpc_security_group_ids = [aws_security_group.demo_sg.id]
db_subnet_group_name = aws_db_subnet_group.demo_subnet_group.name
skip_final_snapshot = true
}
resource "aws_instance" "demo_vm" {
ami = "ami-0745b7d4092315796" # Ubuntu 22.04 AMI for us-east-1
instance_type = "t2.micro"
subnet_id = aws_subnet.demo_subnet_a.id
vpc_security_group_ids = [aws_security_group.demo_sg.id]
associate_public_ip_address = true
user_data = <<-EOF
#!/bin/bash
# Update package lists and install necessary packages
apt-get update -y
apt-get install -y apache2 php mysql-client php-mysql
RDS_HOST="`echo ${aws_db_instance.demo_rds.endpoint} | cut -d ':' -f 1`"
# Enable and start Apache
systemctl enable apache2
systemctl start apache2
# Create and populate the table
mysql -h "$RDS_HOST" -u root -p'password123' -e "
CREATE DATABASE demo_db;
USE demo_db;
CREATE TABLE demo_table (id INT AUTO_INCREMENT PRIMARY KEY, value VARCHAR(255));
INSERT INTO demo_table (value) VALUES ('-- World --');
"
# Create sample PHP application
cat < /var/www/html/index.php
<!--?php \$conn = new mysqli('${aws_db_instance.demo_rds.endpoint}', 'root', 'password123', 'demo_db'); if (\$conn->connect_error) { die('Connection failed: ' . \$conn->connect_error); }
\$result = \$conn->query('SELECT value FROM demo_table LIMIT 1');
if (\$result->num_rows > 0) {
while(\$row = \$result->fetch_assoc()) { echo '</p>
<h2><center>Hello ' . \$row['value']; echo '</h2>
<p></center>'; }
} else { echo 'No data found'; }
\$conn->close();
?-->
EOT
# Adjust permissions
chown -R www-data:www-data /var/www/html
chmod -R 755 /var/www/html
rm /var/www/html/index.html
EOF
tags = {
Name = "Demo-VM"
}
}
output "ec2_public_ip" {
value = aws_instance.demo_vm.public_ip
}
output "rds_endpoint" {
value = aws_db_instance.demo_rds.endpoint
}