Skip to content

Instantly share code, notes, and snippets.

@MoeAhmed11
Last active April 29, 2024 17:25
Show Gist options
  • Save MoeAhmed11/8eece9a9cb055c5f06fc91e45fd21c1e to your computer and use it in GitHub Desktop.
Save MoeAhmed11/8eece9a9cb055c5f06fc91e45fd21c1e to your computer and use it in GitHub Desktop.
ASG on AWS
#main.tf
# Terraform Resources
#Create a new VPC in AWS
resource "aws_vpc" "vpc" {
cidr_block = var.vpc_cidr
tags = {
Name = "TerraformVPC"
}
}
#AWS Availability Zones
data "aws_availability_zones" "available" {
state = "available"
}
# Security Group for ALB allowing requests from any IP address
resource "aws_security_group" "alb_security_group" {
name = "${var.environment}-alb-security-group"
description = "ALB Security Group"
vpc_id = aws_vpc.vpc.id
ingress {
description = "HTTP from Internet"
from_port = 80
to_port = 80
protocol = "tcp"
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 = "${var.environment}-alb-security-group"
}
}
# Security Group for ASG allowing requests only from ALB
resource "aws_security_group" "asg_security_group" {
name = "${var.environment}-asg-security-group"
description = "ASG Security Group"
vpc_id = aws_vpc.vpc.id
ingress {
description = "HTTP from ALB"
from_port = 80
to_port = 80
protocol = "tcp"
security_groups = [aws_security_group.alb_security_group.id]
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
tags = {
Name = "${var.environment}-asg-security-group"
}
}
#Internet Gateway to enable internet connectivity
resource "aws_internet_gateway" "internet_gateway" {
vpc_id = aws_vpc.vpc.id
tags = {
Name = "Terraform_internet_gateway"
}
}
#Create 2 Public Subnets
resource "aws_subnet" "public_subnet" {
count = 2
vpc_id = aws_vpc.vpc.id
cidr_block = var.public_subnet_cidr[count.index]
map_public_ip_on_launch = true
availability_zone = data.aws_availability_zones.available.names[count.index]
tags = {
Name = join("-", ["${var.environment}-public-subnet", data.aws_availability_zones.available.names[count.index]])
}
}
#Route table for public subnets, this ensures that all instances launched in public subnet will have access to the internet
resource "aws_route_table" "public_route_table" {
vpc_id = aws_vpc.vpc.id
route {
cidr_block = "0.0.0.0/0"
gateway_id = aws_internet_gateway.internet_gateway.id
}
tags = {
Name = "${var.environment}-public-route-table"
}
}
#public subnet will be associated with the public route table
resource "aws_route_table_association" "public_rt_assoc" {
count = 2
subnet_id = aws_subnet.public_subnet[count.index].id
route_table_id = aws_route_table.public_route_table.id
}
# Application Load Balancer Resources
resource "aws_lb" "alb" {
name = "${var.environment}-alb"
internal = false
load_balancer_type = "application"
security_groups = [aws_security_group.alb_security_group.id]
subnets = [for i in aws_subnet.public_subnet : i.id]
}
#creating a target group that listens on port 80 and uses the HTTP protocol.
resource "aws_lb_target_group" "target_group" {
name = "${var.environment}-TG"
port = 80
protocol = "HTTP"
vpc_id = aws_vpc.vpc.id
health_check {
path = "/"
matcher = 200
}
}
#Create a linstener for HTTP using port 80, attached to the ALB
resource "aws_lb_listener" "alb_listener" {
load_balancer_arn = aws_lb.alb.arn
port = "80"
protocol = "HTTP"
default_action {
type = "forward"
target_group_arn = aws_lb_target_group.target_group.arn
}
tags = {
Name = "${var.environment}-alb-listenter"
}
}
#Create an Auto Scaling Group, specifying the capacity, target group and launch template
resource "aws_autoscaling_group" "auto_scaling_group" {
name = "my-autoscaling-group"
desired_capacity = 1
max_size = 2
min_size = 1
vpc_zone_identifier = flatten([
aws_subnet.public_subnet.*.id,
])
target_group_arns = [
aws_lb_target_group.target_group.arn,
]
launch_template {
id = aws_launch_template.launch_template.id
version = aws_launch_template.launch_template.latest_version
}
}
#Data source to get the latest Amazon Linux 2 AMI
data "aws_ami" "app_ami" {
most_recent = true
filter {
name = "name"
values = [var.ami_filter.name]
}
filter {
name = "virtualization-type"
values = ["hvm"]
}
owners = [var.ami_filter.owner]
}
#Create a launch template to launch instances on the ASG
resource "aws_launch_template" "launch_template" {
name = "${var.environment}-launch-template"
image_id = data.aws_ami.app_ami.id
instance_type = var.instance_type
network_interfaces {
device_index = 0
security_groups = [aws_security_group.asg_security_group.id]
}
tag_specifications {
resource_type = "instance"
tags = {
Name = "${var.environment}-asg-ec2"
}
}
user_data = base64encode("${var.ec2_user_data}")
}
#outputs.tf
#Terraform Outputs
output "alb_public_url" {
description = "Public URL for Application Load Balancer"
value = aws_lb.alb.dns_name
}
#providers.tf
#Terraform Providers
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.47.0"
}
}
}
provider "aws" {
region = "us-east-1"
}
#variables.tf
#Variable used to specify AMI used for instances in the ASG
variable "ami" {
description = "ami of ec2 instance"
type = string
default = "ami-04e5276ebb8451442"
}
# Launch Template and ASG Variables
variable "instance_type" {
description = "launch template EC2 instance type"
type = string
default = "t2.micro"
}
#Variable used to filter marketplace AMIs to select Amazon Linux AMI
variable "ami_filter" {
description = "Name filter and owner for AMI"
type = object ({
name = string
owner = string
})
default = {
name = "al2023-ami-2023.4.20240416.0-kernel-6.1-x86_64"
owner = "137112412989"
}
}
#This user data variable indicates that the script configures Apache on a server.
variable "ec2_user_data" {
description = "variable indicates that the script configures Apache on a server"
type = string
default = <<EOF
#!/bin/bash
yum update -y
yum install -y httpd
systemctl start httpd
systemctl enable httpd
echo "<h1>Hello World from $(hostname -f)</h1>" > /var/www/html/index.html
EOF
}
# VPC Variables
variable "vpc_cidr" {
description = "VPC cidr block"
type = string
default = "10.10.0.0/16"
}
#These Public subnets are used for resources that need to be accessible from the internet
variable "public_subnet_cidr" {
description = "Public Subnet cidr block"
type = list(string)
default = ["10.10.0.0/24", "10.10.2.0/24"]
}
#Environement variable, specifying name if the environment
variable "environment" {
description = "Environment name for deployment"
type = string
default = "ASG-Terraform"
}
#Region Variable
variable "aws_region" {
description = "AWS region name"
type = string
default = "us-east-1"
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment