Loading
Reza Chegini

Junior DevOps Engineer

Junior Cloud Engineer

Junior Site Reliability Engineer

Software Engineer

Backend Developer

Reza Chegini

Junior DevOps Engineer

Junior Cloud Engineer

Junior Site Reliability Engineer

Software Engineer

Backend Developer

Blog Post

Exploring Terraform on AWS: Setting Up ALB Security Groups

October 6, 2025 AWS, DevOps, Infrastructure, Terraform
Exploring Terraform on AWS: Setting Up ALB Security Groups

Recently, I was exploring Terraform on AWS and learned how to deploy an Application Load Balancer (ALB). In this post, I explain how I created security groups and used Terraform to get the latest Amazon Linux 2 AMI.

This post is for anyone who is learning Infrastructure as Code (IaC) and wants to understand AWS networking better.


What I Set Up

In this setup, I created:

  • Three security groups using the Terraform AWS Security Group module:
    • One for a public bastion host (for SSH access)
    • One for private EC2 instances
    • One for a public load balancer
  • A data block to get the latest Amazon Linux 2 AMI automatically

If you have not yet created a VPC with Terraform, you can check that part first before applying these modules.


1) Public Bastion Host Security Group

module "public_bastion_sg" {
  source  = "terraform-aws-modules/security-group/aws"
  version = "5.2.0"

  name        = "public-bastion-sg"
  description = "Security Group with SSH port open for everybody"
  vpc_id      = module.vpc.vpc_id

  ingress_rules       = ["ssh-tcp"]
  ingress_cidr_blocks = ["0.0.0.0/0"]
  egress_rules        = ["all-all"]
  tags                = local.common_tags
}

Explanation:

  • The source and version tell Terraform to use a ready-made module from the Terraform Registry and keep it stable with a specific version.
  • The name and description fields help you identify this group in the AWS console.
  • The vpc_id connects the security group to your main VPC.
  • The ingress_rules allow incoming SSH traffic (port 22) from anywhere. This is useful for connecting to your EC2 instance through a bastion host.
  • The egress_rules allow all outbound traffic so the instance can reach the internet (for updates or downloads).
  • The tags help with organization and make it easier to track resources in AWS.

This security group is used for your bastion host, which you can connect to for managing private instances.


2) Private EC2 Instances Security Group

module "private_sg" {
  source  = "terraform-aws-modules/security-group/aws"
  version = "5.2.0"

  name        = "private-sg"
  description = "Security Group with HTTP and SSH open inside the VPC"
  vpc_id      = module.vpc.vpc_id

  ingress_rules       = ["ssh-tcp", "http-80-tcp"]
  ingress_cidr_blocks = [module.vpc.vpc_cidr_block]
  egress_rules        = ["all-all"]
  tags                = local.common_tags
}

Explanation:

  • This group allows SSH (port 22) and HTTP (port 80) connections, but only from within the VPC range.
  • The ingress_cidr_blocks use the VPC CIDR block, which means only servers inside the same network can connect.
  • This setup improves security because it blocks all public access from the internet.
  • The egress_rules again allow all outbound traffic so your instance can connect to external services if needed.
  • This type of group is good for application servers or private services that are not open to the public.

3) Public Load Balancer Security Group

module "loadbalancer_sg" {
  source  = "terraform-aws-modules/security-group/aws"
  version = "5.2.0"

  name        = "loadbalancer-sg"
  description = "Security Group with HTTP open for the Internet"
  vpc_id      = module.vpc.vpc_id

  ingress_rules       = ["http-80-tcp"]
  ingress_cidr_blocks = ["0.0.0.0/0"]
  egress_rules        = ["all-all"]
  tags                = local.common_tags

  ingress_with_cidr_blocks = [
    {
      from_port   = 81
      to_port     = 81
      protocol    = 6
      description = "Allow Port 81 from Internet"
      cidr_blocks = "0.0.0.0/0"
    },
  ]
}

Explanation:

  • The load balancer needs to accept traffic from the internet, so ingress_cidr_blocks is set to 0.0.0.0/0, which means open to all IPs.
  • The rule http-80-tcp allows normal HTTP traffic on port 80 for websites.
  • The extra rule with port 81 shows how you can allow custom ports if your app uses them.
  • The egress_rules allow the load balancer to send responses back to users or forward traffic to backend servers.
  • This group is essential for public-facing applications such as web servers or APIs behind an ALB.

4) Security Group Outputs

output "public_bastion_sg_group_id" {
  description = "The ID of the security group"
  value       = module.public_bastion_sg.security_group_id
}

Explanation:

  • The output block lets Terraform print important values after applying the configuration.
  • For example, security_group_id can be reused in other Terraform files or modules (for EC2 instance connections, ALB targets, etc.).
  • Using outputs keeps your setup clean and helps you easily connect different modules together without hardcoding values.

5) Getting the Latest Amazon Linux 2 AMI

data "aws_ami" "amzlinux2" {
  most_recent = true
  owners      = ["amazon"]

  filter {
    name   = "name"
    values = ["amzn2-ami-hvm-*-gp2"]
  }
  filter {
    name   = "root-device-type"
    values = ["ebs"]
  }
  filter {
    name   = "virtualization-type"
    values = ["hvm"]
  }
  filter {
    name   = "architecture"
    values = ["x86_64"]
  }
}

Explanation:

  • This data block helps Terraform find the newest Amazon Linux 2 AMI automatically instead of entering a static AMI ID.
  • The filters tell Terraform what type of image to look for — here it searches only for 64-bit (x86_64) HVM images with EBS storage.
  • The most_recent = true option makes sure Terraform always picks the latest version available from Amazon.
  • This saves time and keeps your setup up to date whenever you deploy new instances.

Wrap-Up

This setup helps you manage AWS security groups easily with Terraform and keeps your infrastructure consistent.
You learned how to:

  • Create security groups for bastion hosts, private EC2s, and load balancers
  • Output key IDs for reuse
  • Automatically fetch the latest Amazon Linux 2 AMI

In the next step, I will deploy EC2 instances, attach these security groups, and connect them to the ALB to handle incoming traffic.

Tags:
Write a comment