Skip to content

Commit

Permalink
configure private zones dynamically within aws-network-setup and aws-alb
Browse files Browse the repository at this point in the history
  • Loading branch information
matihost committed Nov 16, 2023
1 parent dcedfe8 commit a2cfdab
Show file tree
Hide file tree
Showing 14 changed files with 195 additions and 139 deletions.
2 changes: 1 addition & 1 deletion terraform/aws/aws-alb/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ run: init ## setup VPC: make run [ENV=dev] [MODE=apply]


test: ## test ALB Nginx instance
curl http://$(shell cd stage/$(ENV) && terragrunt output alb_dns):80
curl http://$(shell cd stage/$(ENV) && terragrunt output public_alb_dns):80

show-auto-scalling-group-state: ## show AutoScalingGroup state(see DesiredCapacity for current amount of instances)
aws autoscaling describe-auto-scaling-groups --auto-scaling-group-name webserver
Expand Down
8 changes: 4 additions & 4 deletions terraform/aws/aws-alb/README.md
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
# Terraform :: Application Load Balancer usage example

Terraform scripts deploy sample webserver app in autoscalling mode in private subnet and expose public facing loadbalancer to it.
Terraform scripts deploy sample webserver app in autoscalling mode in private subnets and expose public facing loadbalancer to it.

In particular it creates:

- launch template for webserver (ubuntu with nginx acting as webserver)

- autoscalling group, plus simple autoscalling policy
- autoscaling group, plus simple autoscaling policy

- targetgroup for ALB usage - it is being populated via autoscalling group automatically (aka changes to instances count is reflected in target group)
- targetgroup for ALB usage - it is being populated via autoscaling group automatically (aka changes to instances count is reflected in target group)

- Application Load Balancer (ALB) with single listener forwarding all traffic to above target group

This setup use AWS resources eliglible to AWS Free Tier __only__.
This setup use AWS resources eligible to AWS Free Tier __only__.

## Prerequisites

Expand Down
53 changes: 53 additions & 0 deletions terraform/aws/aws-alb/module/public_alb.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
locals{
public_subnet_ids = [for subnet in data.aws_subnet.public: subnet.id]
}

data "aws_security_group" "public_lb_security_group" {
tags = {
Name = var.public_lb_security_group_name
}
}

# Exposes public-facing ALB to EC2 instances that have private IP addresses only.
# It works by setting up ALB to public subnets in the same Availability Zones as the private subnets that are used by your private instances.
# Then associate these public subnets to the internet-facing load balancer.
# In the below example, public facing subnets from zone a and b are allowing to route traffic to target_group of instances in private zones a and b.
# (In this example there is only one private network in zone a, but ALB requires at least two public subnets)
#
# Details: https://aws.amazon.com/premiumsupport/knowledge-center/public-load-balancer-private-ec2/
resource "aws_lb" "webserver" {
name = local.prefix
internal = false
load_balancer_type = "application"
security_groups = [data.aws_security_group.public_lb_security_group.id]

# TODO replace with subnet mapping to reserver EIP
subnets = local.public_subnet_ids
}

resource "aws_lb_listener" "webserver" {
load_balancer_arn = aws_lb.webserver.arn
port = "80"
protocol = "HTTP"

# TODO convert to TSL/SSL
# port = "443"
# protocol = "HTTPS"
# ssl_policy = "ELBSecurityPolicy-2016-08"
# certificate_arn = "arn:aws:iam::187416307283:server-certificate/test_cert_rab3wuqwgja25ct3n4jdj2tzu4"

default_action {
type = "forward"
target_group_arn = aws_lb_target_group.webserver.arn
}
}


output "public_alb_dns" {
value = aws_lb.webserver.dns_name
}

# The canonical hosted zone ID of the load balancer (to be used in a Route 53 Alias record)
output "public_alb_canonical_zone" {
value = aws_lb.webserver.zone_id
}
29 changes: 27 additions & 2 deletions terraform/aws/aws-alb/module/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ locals {
# tflint-ignore: terraform_unused_declarations
account_id = data.aws_caller_identity.current.account_id

prefix = var.env
prefix = "${var.env}-webserver"
}

variable "env" {
Expand All @@ -32,6 +32,7 @@ variable "ec2_architecture" {
default = "x86_64"
}

# tflint-ignore: terraform_unused_declarations
variable "zone" {
default = "us-east-1a"
type = string
Expand All @@ -46,8 +47,32 @@ variable "region" {
}


variable "instance_profile" {
variable "ec2_instance_profile" {
default = ""
type = string
description = "The name of instance_profile (dynamically provisioning access to role)"
}


variable "zones" {
type = set(string)
description = "AWS zones for VPC Subnetworks Deployment"
}


variable "ec2_ssh_key_id" {
default = ""
type = string
description = "The name of key allowed to login to the instance, usually the bastion key id"
}

# TODO create own?
variable "ec2_security_group_name" {
type = string
description = "The name of security group name assigned on EC2 webserver instances"
}

variable "public_lb_security_group_name" {
type = string
description = "The name of security group name assigned on Public LB"
}
104 changes: 24 additions & 80 deletions terraform/aws/aws-alb/module/webserver.tf
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
locals{
private_subnet_ids = [for subnet in data.aws_subnet.private: subnet.id]
}

data "aws_ami" "ubuntu" {
most_recent = true

Expand Down Expand Up @@ -25,91 +29,76 @@ data "aws_vpc" "default" {
default = true
}

data "aws_subnet" "private_subnet" {
vpc_id = data.aws_vpc.default.id
availability_zone = var.zone
tags = {
Tier = "private"
}
}

data "aws_subnet" "private_subnet2" {
data "aws_subnet" "private" {
for_each = var.zones
vpc_id = data.aws_vpc.default.id
availability_zone = "us-east-1b"
availability_zone = each.key
tags = {
Tier = "private"
}
}


data "aws_subnet" "public_subnet_1" {
data "aws_subnet" "public" {
for_each = var.zones
vpc_id = data.aws_vpc.default.id
availability_zone = var.zone
availability_zone = each.key
default_for_az = true
}

data "aws_subnet" "public_subnet_2" {
vpc_id = data.aws_vpc.default.id
availability_zone = "us-east-1b"
default_for_az = true
}

data "aws_security_group" "internal_access" {
data "aws_security_group" "webserver" {
tags = {
Name = "internal_access"
Name = var.ec2_security_group_name
}
}

data "aws_security_group" "http_from_single_computer" {
tags = {
Name = "http_from_single_computer"
}
}



resource "aws_launch_template" "webserver" {
name = "${local.prefix}-webserver"
name_prefix = "${local.prefix}-"
update_default_version = true

iam_instance_profile {
name = var.instance_profile
name = var.ec2_instance_profile
}

image_id = data.aws_ami.ubuntu.id

instance_type = var.ec2_instance_type

key_name = "${local.prefix}-bastion-ssh"
key_name = var.ec2_ssh_key_id

vpc_security_group_ids = [data.aws_security_group.internal_access.id]
vpc_security_group_ids = [data.aws_security_group.webserver.id]

tag_specifications {
resource_type = "instance"

tags = {
Name = "webserver"
Name = local.prefix
}
}

user_data = filebase64("${path.module}/webserver.cloud-init.yaml")
}

resource "aws_lb_target_group" "webserver" {
name = "webserver"
name = local.prefix
port = 80
protocol = "HTTP"
vpc_id = data.aws_vpc.default.id
}


resource "aws_autoscaling_group" "webserver" {
name = "webserver"
name = local.prefix
launch_template {
id = aws_launch_template.webserver.id
version = "$Latest"
}
# Subnets where to place instances
vpc_zone_identifier = [data.aws_subnet.private_subnet.id, data.aws_subnet.private_subnet2.id]
vpc_zone_identifier = local.private_subnet_ids

# ALBs Target Groups to place instances
target_group_arns = [aws_lb_target_group.webserver.arn]
Expand All @@ -119,61 +108,16 @@ resource "aws_autoscaling_group" "webserver" {

health_check_type = "ELB"
# The amount of time until EC2 Auto Scaling performs the first health check on new instances after they are put into service.
health_check_grace_period = 120
health_check_grace_period = 20

# maximum time for Terraform to wait for ASG reach
wait_for_capacity_timeout = "10m"
}

resource "aws_autoscaling_policy" "webserver" {
name = "webserver"
name = local.prefix
scaling_adjustment = 1
adjustment_type = "ChangeInCapacity"
cooldown = 300
cooldown = 20
autoscaling_group_name = aws_autoscaling_group.webserver.name
}


# Exposes public-facing ALB to EC2 instances that have private IP addresses only.
# It works by setting up ALB to public subnets in the same Availability Zones as the private subnets that are used by your private instances.
# Then associate these public subnets to the internet-facing load balancer.
# In the below example, public facing subnets from zone a and b are allowing to route traffic to target_group of instances in private zones a and b.
# (In this example there is only one private network in zone a, but ALB requires at least two public subnets)
#
# Details: https://aws.amazon.com/premiumsupport/knowledge-center/public-load-balancer-private-ec2/
resource "aws_lb" "webserver" {
name = "webserver"
internal = false
load_balancer_type = "application"
security_groups = [data.aws_security_group.http_from_single_computer.id]

# TODO replace with subnet mapping to reserver EIP
subnets = [data.aws_subnet.public_subnet_1.id, data.aws_subnet.public_subnet_2.id]
}

resource "aws_lb_listener" "webserver" {
load_balancer_arn = aws_lb.webserver.arn
port = "80"
protocol = "HTTP"

# TODO convert to TSL/SSL
# port = "443"
# protocol = "HTTPS"
# ssl_policy = "ELBSecurityPolicy-2016-08"
# certificate_arn = "arn:aws:iam::187416307283:server-certificate/test_cert_rab3wuqwgja25ct3n4jdj2tzu4"

default_action {
type = "forward"
target_group_arn = aws_lb_target_group.webserver.arn
}
}


output "alb_dns" {
value = aws_lb.webserver.dns_name
}

# The canonical hosted zone ID of the load balancer (to be used in a Route 53 Alias record)
output "alb_canonical_zone" {
value = aws_lb.webserver.zone_id
}
16 changes: 10 additions & 6 deletions terraform/aws/aws-alb/stage/dev/terragrunt.hcl
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,14 @@ terraform {


inputs = {
env = "dev"
external_access_ip = local.current_ip
instance_profile = "SSM-EC2"
ec2_instance_type = "t4g.small" # or t3.micro
ec2_architecture = "arm64" # or x86_64
aws_tags = { Env = "dev" }
env = "dev"
external_access_ip = local.current_ip
instance_profile = "SSM-EC2"
ec2_instance_type = "t4g.small" # or t3.micro
ec2_architecture = "arm64" # or x86_64
ssh_key_id = "dev-us-east-1-bastion-ssh"
ec2_security_group_name = "internal_access"
public_lb_security_group_name = "http_from_single_computer"
aws_tags = { Env = "dev" }
zones = ["us-east-1a", "us-east-1b", "us-east-1c"]
}
6 changes: 3 additions & 3 deletions terraform/aws/aws-network-setup/module/bastion.tf
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
resource "aws_key_pair" "vm_key" {
key_name = "${local.prefix}-bastion-ssh"
key_name = "${local.prefix}-${var.region}-bastion-ssh"
public_key = var.ssh_pub_key
}

Expand Down Expand Up @@ -89,7 +89,7 @@ resource "aws_security_group" "internal_access" {
resource "aws_instance" "bastion_vm" {
ami = data.aws_ami.ubuntu.id
instance_type = var.ec2_instance_type
subnet_id = data.aws_subnet.default.id
subnet_id = data.aws_subnet.default[var.zone].id
key_name = aws_key_pair.vm_key.key_name
vpc_security_group_ids = [aws_security_group.bastion_access.id, aws_security_group.internal_access.id]
user_data = templatefile("${path.module}/bastion.cloud-init.tpl", {
Expand All @@ -98,7 +98,7 @@ resource "aws_instance" "bastion_vm" {
}
)
tags = {
Name = "${local.prefix}-bastion"
Name = "${local.prefix}-${var.region}-bastion"
}
}

Expand Down
Loading

0 comments on commit a2cfdab

Please sign in to comment.