Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions terraform/common/locals.tf
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ data "aws_region" "current" {}
locals {
group_name = "power"
project_name = "eatda"
admin_email = "yappweb1server@gmail.com"

policy_arns = [
"arn:aws:iam::aws:policy/AdministratorAccess",
Expand Down Expand Up @@ -248,3 +249,7 @@ locals {
}
}
}

locals {
request_threshold = 200
}
24 changes: 24 additions & 0 deletions terraform/common/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -51,3 +51,27 @@ module "alb" {
certificate_arn = module.route53.certificate_arn
certificate_validation_complete = module.route53.certificate_validation_complete
}

module "waf" {
source = "./waf"
project_name = local.project_name
request_threshold = local.request_threshold
tags = local.common_tags
}

resource "aws_wafv2_web_acl_association" "this" {
resource_arn = module.alb.alb_arn
web_acl_arn = module.waf.web_acl_arn
}

resource "aws_cloudwatch_log_group" "waf_logs" {
name = "aws-waf-logs-${local.project_name}"
retention_in_days = 7

tags = local.common_tags
}

resource "aws_wafv2_web_acl_logging_configuration" "this" {
log_destination_configs = [trimsuffix(aws_cloudwatch_log_group.waf_logs.arn, ":*")]
resource_arn = module.waf.web_acl_arn
}
156 changes: 156 additions & 0 deletions terraform/common/waf/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
resource "aws_wafv2_web_acl" "this" {
name = "${var.project_name}-web-acl"
scope = "REGIONAL"

default_action {
allow {}
}

# Rate-based Rule (HTTP Flood)
rule {
name = "Rate-Limit-Rule"
priority = 1
action {
block {}
}
statement {
rate_based_statement {
limit = var.request_threshold
aggregate_key_type = "IP"
}
}
visibility_config {
cloudwatch_metrics_enabled = true
metric_name = "rate-limit-rule"
sampled_requests_enabled = true
}
}

# AWS Managed Core Rule Set
rule {
name = "AWS-Managed-Core-Rule-Set"
priority = 10
override_action {
none {}
}
statement {
managed_rule_group_statement {
vendor_name = "AWS"
name = "AWSManagedRulesCommonRuleSet"
}
}
visibility_config {
cloudwatch_metrics_enabled = true
metric_name = "aws-managed-common"
sampled_requests_enabled = true
}
}

# Scanners & Probes Protection
rule {
name = "AWS-Managed-Known-Bad-Inputs-Rule-Set"
priority = 20
override_action {
none {}
}
statement {
managed_rule_group_statement {
vendor_name = "AWS"
name = "AWSManagedRulesKnownBadInputsRuleSet"
}
}
visibility_config {
cloudwatch_metrics_enabled = true
metric_name = "aws-managed-bad-inputs"
sampled_requests_enabled = true
}
}

# Reputation Lists Protection
rule {
name = "AWS-Managed-Amazon-IP-Reputation-List"
priority = 30
override_action {
none {}
}
statement {
managed_rule_group_statement {
vendor_name = "AWS"
name = "AWSManagedRulesAmazonIpReputationList"
}
}
visibility_config {
cloudwatch_metrics_enabled = true
metric_name = "aws-managed-ip-rep"
sampled_requests_enabled = true
}
}

# Bad Bot Protection
rule {
name = "AWS-Managed-Bot-Control-Rule-Set"
priority = 40
override_action {
none {}
}
statement {
managed_rule_group_statement {
vendor_name = "AWS"
name = "AWSManagedRulesBotControlRuleSet"
}
}
visibility_config {
cloudwatch_metrics_enabled = true
metric_name = "aws-managed-bot-control"
sampled_requests_enabled = true
}
}

# Anonymous IP list
rule {
name = "AWS-Managed-Anonymous-IP-List"
priority = 50
override_action {
none {}
}
statement {
managed_rule_group_statement {
vendor_name = "AWS"
name = "AWSManagedRulesAnonymousIpList"
}
}
visibility_config {
cloudwatch_metrics_enabled = true
metric_name = "aws-managed-anonymous-ip"
sampled_requests_enabled = true
}
}

# SQL database
rule {
name = "AWS-Managed-SQLi-Rule-Set"
priority = 60
override_action {
none {}
}
statement {
managed_rule_group_statement {
vendor_name = "AWS"
name = "AWSManagedRulesSQLiRuleSet"
}
}
visibility_config {
cloudwatch_metrics_enabled = true
metric_name = "aws-managed-sql-db"
sampled_requests_enabled = true
}
}

visibility_config {
cloudwatch_metrics_enabled = true
metric_name = "${var.project_name}-web-acl"
sampled_requests_enabled = true
}

tags = var.tags
}
3 changes: 3 additions & 0 deletions terraform/common/waf/outputs.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
output "web_acl_arn" {
value = aws_wafv2_web_acl.this.arn
}
12 changes: 12 additions & 0 deletions terraform/common/waf/variables.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
variable "project_name" {
type = string
}

variable "request_threshold" {
type = number
description = "Rate-Limit 규칙에 적용할 5분당 IP별 최대 요청 수"
}

variable "tags" {
type = map(string)
}
5 changes: 4 additions & 1 deletion terraform/prod/terraform.tfvars
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ ecs_services = {
datadog = {
task_definition = "datadog"
launch_type = "EC2"
scheduling_strategy = "REPLICA"
scheduling_strategy = "DAEMON"
}
}

Expand Down Expand Up @@ -49,6 +49,9 @@ ecs_task_definitions_base = {
DD_LOGS_CONFIG_CONTAINER_COLLECT_ALL = "true"
DD_APM_RECEIVER_PORT = "8126"
DD_APM_NON_LOCAL_TRAFFIC = "true"
DD_EC2_USE_IMDSV2 = "true"
DD_COLLECT_EC2_TAGS = "true"
DD_COLLECT_EC2_METADATA = "true"
DD_SERVICE = "eatda-api-prod"
DD_ENV = "prod"
DD_VERSION = "v1"
Expand Down
Loading