Skip to content

Instantly share code, notes, and snippets.

@arindam89
Created May 24, 2025 05:08
Show Gist options
  • Save arindam89/fa0f0ea17d74ddb5b40156b2d209db1c to your computer and use it in GitHub Desktop.
Save arindam89/fa0f0ea17d74ddb5b40156b2d209db1c to your computer and use it in GitHub Desktop.
Private EC2 SSL WAF
# OpenTofu/Terraform code for private EC2 behind ALB+WAF+CloudFront
provider "aws" {
region = "us-east-1"
}
# ---------------------
# VPC & Networking Setup
# ---------------------
module "vpc" {
source = "terraform-aws-modules/vpc/aws"
version = "5.1.0"
name = "secure-vpc"
cidr = "10.0.0.0/16"
azs = ["us-east-1a", "us-east-1b"]
private_subnets = ["10.0.1.0/24", "10.0.2.0/24"]
public_subnets = ["10.0.101.0/24", "10.0.102.0/24"]
enable_nat_gateway = true
single_nat_gateway = true
enable_dns_hostnames = true
tags = {
Project = "SecureEC2"
}
}
# ---------------------
# Security Groups
# ---------------------
resource "aws_security_group" "alb_sg" {
name = "alb-sg"
description = "Allow HTTP/HTTPS from anywhere"
vpc_id = module.vpc.vpc_id
ingress {
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
ingress {
from_port = 443
to_port = 443
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"]
}
}
resource "aws_security_group" "ec2_sg" {
name = "ec2-sg"
description = "Allow HTTP/HTTPS from ALB only"
vpc_id = module.vpc.vpc_id
ingress {
from_port = 80
to_port = 80
protocol = "tcp"
security_groups = [aws_security_group.alb_sg.id]
}
ingress {
from_port = 443
to_port = 443
protocol = "tcp"
security_groups = [aws_security_group.alb_sg.id]
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
}
# ---------------------
# EC2 Instance (Private)
# ---------------------
resource "aws_instance" "web" {
ami = "ami-0c02fb55956c7d316" # Amazon Linux 2
instance_type = "t3.micro"
subnet_id = module.vpc.private_subnets[0]
vpc_security_group_ids = [aws_security_group.ec2_sg.id]
associate_public_ip_address = false
tags = {
Name = "private-web"
}
}
# ---------------------
# ALB + Target Group + Listener
# ---------------------
resource "aws_lb" "alb" {
name = "secure-alb"
internal = false
load_balancer_type = "application"
security_groups = [aws_security_group.alb_sg.id]
subnets = module.vpc.public_subnets
}
resource "aws_lb_target_group" "tg" {
name = "ec2-tg"
port = 443
protocol = "HTTPS"
vpc_id = module.vpc.vpc_id
health_check {
path = "/"
protocol = "HTTPS"
matcher = "200"
interval = 30
timeout = 5
healthy_threshold = 2
unhealthy_threshold = 2
}
}
resource "aws_lb_target_group_attachment" "web_attach" {
target_group_arn = aws_lb_target_group.tg.arn
target_id = aws_instance.web.id
port = 443
}
resource "aws_lb_listener" "https" {
load_balancer_arn = aws_lb.alb.arn
port = 443
protocol = "HTTPS"
ssl_policy = "ELBSecurityPolicy-2016-08"
certificate_arn = "arn:aws:acm:us-east-1:123456789012:certificate/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
default_action {
type = "forward"
target_group_arn = aws_lb_target_group.tg.arn
}
}
# ---------------------
# AWS WAF WebACL for Origin Filtering
# ---------------------
resource "aws_wafv2_web_acl" "web_acl" {
name = "origin-filter"
scope = "REGIONAL"
description = "Allow only specific origins"
default_action {
block {}
}
rule {
name = "allow-allowed-origins"
priority = 1
action {
allow {}
}
statement {
byte_match_statement {
field_to_match {
single_header {
name = "origin"
}
}
positional_constraint = "EXACTLY"
search_string = "https://your-allowed-origin.com"
text_transformation {
priority = 0
type = "LOWERCASE"
}
}
}
visibility_config {
cloudwatch_metrics_enabled = false
metric_name = "allowedOrigins"
sampled_requests_enabled = true
}
}
visibility_config {
cloudwatch_metrics_enabled = false
metric_name = "originACL"
sampled_requests_enabled = true
}
}
resource "aws_wafv2_web_acl_association" "waf_alb_assoc" {
resource_arn = aws_lb.alb.arn
web_acl_arn = aws_wafv2_web_acl.web_acl.arn
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment