Created
May 24, 2025 05:08
-
-
Save arindam89/fa0f0ea17d74ddb5b40156b2d209db1c to your computer and use it in GitHub Desktop.
Private EC2 SSL WAF
This file contains hidden or 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
# 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