Last active
February 6, 2025 16:32
-
-
Save jaycdave88/4809f7eb30da38970444ae651dbf8cda to your computer and use it in GitHub Desktop.
(work in progress) Sets up AWS Terraform distributed app
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
# WARNING: Hardcoding credentials is not recommended! | |
export AWS_ACCESS_KEY_ID="YOUR_AWS_ACCESS_KEY_ID" | |
export AWS_SECRET_ACCESS_KEY="YOUR_AWS_SECRET_ACCESS_KEY" | |
export AWS_DEFAULT_REGION="us-east-1" | |
# This script creates the folder structure and Terraform files for the AWS demo environment. | |
# Run this script from your terminal: ./setup-demo.sh | |
set -e | |
# Base directory for the Terraform code | |
BASE_DIR="aws-demo-env" | |
echo "Creating directory structure in '${BASE_DIR}'..." | |
mkdir -p "${BASE_DIR}" | |
echo "Creating provider.tf..." | |
cat > "${BASE_DIR}/provider.tf" << 'EOF' | |
provider "aws" { | |
region = var.aws_region | |
} | |
EOF | |
echo "Creating variables.tf..." | |
cat > "${BASE_DIR}/variables.tf" << 'EOF' | |
variable "aws_region" { | |
description = "AWS region" | |
default = "us-east-1" | |
} | |
variable "key_name" { | |
description = "Name of the EC2 Key Pair to use for instances" | |
} | |
EOF | |
echo "Creating vpc.tf..." | |
cat > "${BASE_DIR}/vpc.tf" << 'EOF' | |
# Create the VPC | |
resource "aws_vpc" "demo_vpc" { | |
cidr_block = "10.0.0.0/16" | |
enable_dns_support = true | |
enable_dns_hostnames = true | |
tags = { | |
Name = "demo-vpc" | |
} | |
} | |
# Create an Internet Gateway for the VPC | |
resource "aws_internet_gateway" "igw" { | |
vpc_id = aws_vpc.demo_vpc.id | |
tags = { | |
Name = "demo-igw" | |
} | |
} | |
# Public subnet (for DMZ/network appliances) | |
resource "aws_subnet" "public_subnet" { | |
vpc_id = aws_vpc.demo_vpc.id | |
cidr_block = "10.0.1.0/24" | |
map_public_ip_on_launch = true | |
availability_zone = "${var.aws_region}a" | |
tags = { | |
Name = "demo-public-subnet" | |
} | |
} | |
# Private subnet (for VMs and observability) | |
resource "aws_subnet" "private_subnet" { | |
vpc_id = aws_vpc.demo_vpc.id | |
cidr_block = "10.0.2.0/24" | |
map_public_ip_on_launch = false | |
availability_zone = "${var.aws_region}a" | |
tags = { | |
Name = "demo-private-subnet" | |
} | |
} | |
# Separate private subnet for RDS (can be part of a DB subnet group) | |
resource "aws_subnet" "rds_subnet" { | |
vpc_id = aws_vpc.demo_vpc.id | |
cidr_block = "10.0.3.0/24" | |
map_public_ip_on_launch = false | |
availability_zone = "${var.aws_region}a" | |
tags = { | |
Name = "demo-rds-subnet" | |
} | |
} | |
# Create a NAT Gateway in the public subnet so private instances can access the Internet | |
resource "aws_eip" "nat_eip" { | |
domain = "vpc" | |
} | |
resource "aws_nat_gateway" "nat" { | |
allocation_id = aws_eip.nat_eip.id | |
subnet_id = aws_subnet.public_subnet.id | |
tags = { | |
Name = "demo-nat" | |
} | |
} | |
# Public route table (for public subnet) | |
resource "aws_route_table" "public_rt" { | |
vpc_id = aws_vpc.demo_vpc.id | |
route { | |
cidr_block = "0.0.0.0/0" | |
gateway_id = aws_internet_gateway.igw.id | |
} | |
tags = { | |
Name = "demo-public-rt" | |
} | |
} | |
resource "aws_route_table_association" "public_assoc" { | |
subnet_id = aws_subnet.public_subnet.id | |
route_table_id = aws_route_table.public_rt.id | |
} | |
# Private route table (for VMs and observability) | |
resource "aws_route_table" "private_rt" { | |
vpc_id = aws_vpc.demo_vpc.id | |
route { | |
cidr_block = "0.0.0.0/0" | |
nat_gateway_id = aws_nat_gateway.nat.id | |
} | |
tags = { | |
Name = "demo-private-rt" | |
} | |
} | |
resource "aws_route_table_association" "private_assoc" { | |
subnet_id = aws_subnet.private_subnet.id | |
route_table_id = aws_route_table.private_rt.id | |
} | |
# Route table for the RDS subnet | |
resource "aws_route_table" "rds_rt" { | |
vpc_id = aws_vpc.demo_vpc.id | |
route { | |
cidr_block = "0.0.0.0/0" | |
nat_gateway_id = aws_nat_gateway.nat.id | |
} | |
tags = { | |
Name = "demo-rds-rt" | |
} | |
} | |
resource "aws_route_table_association" "rds_assoc" { | |
subnet_id = aws_subnet.rds_subnet.id | |
route_table_id = aws_route_table.rds_rt.id | |
} | |
EOF | |
echo "Creating security_groups.tf..." | |
cat > "${BASE_DIR}/security_groups.tf" << 'EOF' | |
# Security Group for public instances (DMZ network appliances) | |
resource "aws_security_group" "public_sg" { | |
name = "demo-public-sg" | |
description = "Allow SSH and all traffic for DMZ" | |
vpc_id = aws_vpc.demo_vpc.id | |
ingress { | |
from_port = 22 | |
to_port = 22 | |
protocol = "tcp" | |
cidr_blocks = ["0.0.0.0/0"] | |
} | |
ingress { | |
from_port = 0 | |
to_port = 0 | |
protocol = "-1" | |
cidr_blocks = ["0.0.0.0/0"] | |
} | |
egress { | |
from_port = 0 | |
to_port = 0 | |
protocol = "-1" | |
cidr_blocks = ["0.0.0.0/0"] | |
} | |
tags = { | |
Name = "demo-public-sg" | |
} | |
} | |
# Security Group for private instances (VMs and observability) | |
resource "aws_security_group" "private_sg" { | |
name = "demo-private-sg" | |
description = "Allow SSH and application ports from within VPC" | |
vpc_id = aws_vpc.demo_vpc.id | |
ingress { | |
from_port = 22 | |
to_port = 22 | |
protocol = "tcp" | |
cidr_blocks = [aws_vpc.demo_vpc.cidr_block] | |
} | |
# Allow app ports (8080, 3000, 6379) and observability (9090, 3000) | |
ingress { | |
from_port = 8080 | |
to_port = 8080 | |
protocol = "tcp" | |
cidr_blocks = [aws_vpc.demo_vpc.cidr_block] | |
} | |
ingress { | |
from_port = 3000 | |
to_port = 3000 | |
protocol = "tcp" | |
cidr_blocks = [aws_vpc.demo_vpc.cidr_block] | |
} | |
ingress { | |
from_port = 6379 | |
to_port = 6379 | |
protocol = "tcp" | |
cidr_blocks = [aws_vpc.demo_vpc.cidr_block] | |
} | |
ingress { | |
from_port = 9090 | |
to_port = 9090 | |
protocol = "tcp" | |
cidr_blocks = [aws_vpc.demo_vpc.cidr_block] | |
} | |
ingress { | |
from_port = 3000 | |
to_port = 3000 | |
protocol = "tcp" | |
cidr_blocks = [aws_vpc.demo_vpc.cidr_block] | |
} | |
egress { | |
from_port = 0 | |
to_port = 0 | |
protocol = "-1" | |
cidr_blocks = ["0.0.0.0/0"] | |
} | |
tags = { | |
Name = "demo-private-sg" | |
} | |
} | |
# Security Group for RDS | |
resource "aws_security_group" "rds_sg" { | |
name = "demo-rds-sg" | |
description = "Allow PostgreSQL access from within the VPC" | |
vpc_id = aws_vpc.demo_vpc.id | |
ingress { | |
from_port = 5432 | |
to_port = 5432 | |
protocol = "tcp" | |
cidr_blocks = [aws_vpc.demo_vpc.cidr_block] | |
} | |
egress { | |
from_port = 0 | |
to_port = 0 | |
protocol = "-1" | |
cidr_blocks = ["0.0.0.0/0"] | |
} | |
tags = { | |
Name = "demo-rds-sg" | |
} | |
} | |
EOF | |
echo "Creating data_sources.tf..." | |
cat > "${BASE_DIR}/data_sources.tf" << 'EOF' | |
# Data source for Ubuntu 22.04 (VM1) | |
data "aws_ami" "ubuntu" { | |
most_recent = true | |
owners = ["099720109477"] | |
filter { | |
name = "name" | |
values = ["ubuntu/images/hvm-ssd/ubuntu-jammy-22.04-amd64-server-*"] | |
} | |
} | |
# Data source for Debian 12 (VM2) | |
data "aws_ami" "debian" { | |
most_recent = true | |
owners = ["136693071363"] | |
filter { | |
name = "name" | |
values = ["debian-12-*"] | |
} | |
} | |
# Data source for Rocky Linux 9 (VM3) | |
data "aws_ami" "rocky" { | |
most_recent = true | |
owners = ["689593380443"] # Adjust this owner ID if necessary. | |
filter { | |
name = "name" | |
values = ["Rocky-9*"] | |
} | |
} | |
EOF | |
echo "Creating instances.tf..." | |
cat > "${BASE_DIR}/instances.tf" << 'EOF' | |
# EC2 Instance for VM1 - Ubuntu 22.04 running APP1 (Web App on port 8080) | |
resource "aws_instance" "vm1" { | |
ami = data.aws_ami.ubuntu.id | |
instance_type = "t3.micro" | |
subnet_id = aws_subnet.private_subnet.id | |
security_groups = [aws_security_group.private_sg.id] | |
associate_public_ip_address = false | |
key_name = var.key_name | |
user_data = <<EOF_USERDATA | |
#!/bin/bash | |
apt-get update -y | |
apt-get install -y docker.io | |
systemctl start docker | |
docker run -d -p 8080:80 nginx | |
EOF_USERDATA | |
tags = { | |
Name = "VM1-Ubuntu-APP1" | |
} | |
} | |
# EC2 Instance for VM2 - Debian 12 running APP2 (API Service on port 3000) | |
resource "aws_instance" "vm2" { | |
ami = data.aws_ami.debian.id | |
instance_type = "t3.micro" | |
subnet_id = aws_subnet.private_subnet.id | |
security_groups = [aws_security_group.private_sg.id] | |
associate_public_ip_address = false | |
key_name = var.key_name | |
user_data = <<EOF_USERDATA | |
#!/bin/bash | |
apt-get update -y | |
apt-get install -y docker.io | |
systemctl start docker | |
# Run a simple Node.js API using the node:14-slim image | |
docker run -d -p 3000:3000 node:14-slim node -e "require('http').createServer((req,res)=>{res.end('Hello from API Service (APP2)!');}).listen(3000)" | |
EOF_USERDATA | |
tags = { | |
Name = "VM2-Debian-APP2" | |
} | |
} | |
# EC2 Instance for VM3 - Rocky Linux 9 running APP3 (Cache Service on port 6379) | |
resource "aws_instance" "vm3" { | |
ami = data.aws_ami.rocky.id | |
instance_type = "t3.micro" | |
subnet_id = aws_subnet.private_subnet.id | |
security_groups = [aws_security_group.private_sg.id] | |
associate_public_ip_address = false | |
key_name = var.key_name | |
user_data = <<EOF_USERDATA | |
#!/bin/bash | |
yum update -y | |
yum install -y docker | |
systemctl start docker | |
docker run -d -p 6379:6379 redis | |
EOF_USERDATA | |
tags = { | |
Name = "VM3-Rocky-APP3" | |
} | |
} | |
# EC2 Instance for Network Appliance: pfSense (simulated) in the public subnet | |
resource "aws_instance" "pfsense" { | |
ami = data.aws_ami.ubuntu.id # Using Ubuntu as a dummy base image | |
instance_type = "t3.micro" | |
subnet_id = aws_subnet.public_subnet.id | |
security_groups = [aws_security_group.public_sg.id] | |
associate_public_ip_address = true | |
key_name = var.key_name | |
user_data = <<EOF_USERDATA | |
#!/bin/bash | |
echo "Simulating pfSense Firewall" > /var/log/pfsense.log | |
while true; do sleep 3600; done | |
EOF_USERDATA | |
tags = { | |
Name = "pfSense-Simulated" | |
} | |
} | |
# EC2 Instance for Network Appliance: Open vSwitch (simulated) in the public subnet | |
resource "aws_instance" "ovs" { | |
ami = data.aws_ami.ubuntu.id # Using Ubuntu as a dummy base image | |
instance_type = "t3.micro" | |
subnet_id = aws_subnet.public_subnet.id | |
security_groups = [aws_security_group.public_sg.id] | |
associate_public_ip_address = true | |
key_name = var.key_name | |
user_data = <<EOF_USERDATA | |
#!/bin/bash | |
echo "Simulating Open vSwitch" > /var/log/ovs.log | |
while true; do sleep 3600; done | |
EOF_USERDATA | |
tags = { | |
Name = "OVS-Simulated" | |
} | |
} | |
# EC2 Instance for Observability Tools (Prometheus and Grafana) in the private subnet | |
resource "aws_instance" "observability" { | |
ami = data.aws_ami.ubuntu.id # Using Ubuntu as a base | |
instance_type = "t3.micro" | |
subnet_id = aws_subnet.private_subnet.id | |
security_groups = [aws_security_group.private_sg.id] | |
associate_public_ip_address = false | |
key_name = var.key_name | |
user_data = <<EOF_USERDATA | |
#!/bin/bash | |
apt-get update -y | |
apt-get install -y docker.io docker-compose git | |
systemctl start docker | |
mkdir -p /home/ubuntu/observability | |
cat << 'EOC' > /home/ubuntu/observability/docker-compose.yml | |
version: '3' | |
services: | |
prometheus: | |
image: prom/prometheus:latest | |
ports: | |
- "9090:9090" | |
grafana: | |
image: grafana/grafana:latest | |
ports: | |
- "3000:3000" | |
EOC | |
cd /home/ubuntu/observability | |
docker-compose up -d | |
EOF_USERDATA | |
tags = { | |
Name = "Observability-Stack" | |
} | |
} | |
EOF | |
echo "Creating rds.tf..." | |
cat > "${BASE_DIR}/rds.tf" << 'EOF' | |
# Create an RDS subnet group (using the private and RDS subnets) | |
resource "aws_db_subnet_group" "rds_subnet_group" { | |
name = "demo-rds-subnet-group" | |
subnet_ids = [aws_subnet.private_subnet.id, aws_subnet.rds_subnet.id] | |
tags = { | |
Name = "demo-rds-subnet-group" | |
} | |
} | |
# Create an RDS PostgreSQL Instance | |
resource "aws_db_instance" "postgres" { | |
allocated_storage = 20 | |
storage_type = "gp2" | |
engine = "postgres" | |
engine_version = "13.4" | |
instance_class = "db.t3.micro" | |
db_name = "demo_db" | |
username = "demo" | |
password = "demo1234" # Use a more secure password in production | |
db_subnet_group_name = aws_db_subnet_group.rds_subnet_group.name | |
vpc_security_group_ids = [aws_security_group.rds_sg.id] | |
skip_final_snapshot = true | |
publicly_accessible = false | |
multi_az = false | |
tags = { | |
Name = "Demo-Postgres" | |
} | |
} | |
EOF | |
echo "Creating outputs.tf..." | |
cat > "${BASE_DIR}/outputs.tf" << 'EOF' | |
output "vpc_id" { | |
value = aws_vpc.demo_vpc.id | |
} | |
output "public_subnet_id" { | |
value = aws_subnet.public_subnet.id | |
} | |
output "private_subnet_id" { | |
value = aws_subnet.private_subnet.id | |
} | |
output "rds_endpoint" { | |
value = aws_db_instance.postgres.endpoint | |
} | |
output "pfSense_public_ip" { | |
value = aws_instance.pfsense.public_ip | |
} | |
output "OVS_public_ip" { | |
value = aws_instance.ovs.public_ip | |
} | |
EOF | |
echo "Folder structure and Terraform files created in '${BASE_DIR}'." | |
echo "To continue, run the following commands:" | |
echo " cd ${BASE_DIR}" | |
echo " terraform init" | |
echo " terraform plan" | |
echo " terraform apply" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment