From 14aa0e800651e0b5ec56d82ff2e999924f591a26 Mon Sep 17 00:00:00 2001 From: lvalentine6 Date: Sat, 20 Sep 2025 21:21:39 +0900 Subject: [PATCH 1/3] =?UTF-8?q?feat:=20waf=20=EC=B6=94=EA=B0=80=20?= =?UTF-8?q?=EB=B0=8F=20alb=20=EC=97=B0=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- terraform/common/locals.tf | 5 + terraform/common/main.tf | 12 +++ terraform/common/waf/main.tf | 156 ++++++++++++++++++++++++++++++ terraform/common/waf/outputs.tf | 3 + terraform/common/waf/variables.tf | 12 +++ 5 files changed, 188 insertions(+) create mode 100644 terraform/common/waf/main.tf create mode 100644 terraform/common/waf/outputs.tf create mode 100644 terraform/common/waf/variables.tf diff --git a/terraform/common/locals.tf b/terraform/common/locals.tf index dffddf45..5fa48ae8 100644 --- a/terraform/common/locals.tf +++ b/terraform/common/locals.tf @@ -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", @@ -248,3 +249,7 @@ locals { } } } + +locals { + request_threshold = 200 +} diff --git a/terraform/common/main.tf b/terraform/common/main.tf index e255bba6..d42559f5 100644 --- a/terraform/common/main.tf +++ b/terraform/common/main.tf @@ -51,3 +51,15 @@ 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 +} diff --git a/terraform/common/waf/main.tf b/terraform/common/waf/main.tf new file mode 100644 index 00000000..e432dd1b --- /dev/null +++ b/terraform/common/waf/main.tf @@ -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 +} diff --git a/terraform/common/waf/outputs.tf b/terraform/common/waf/outputs.tf new file mode 100644 index 00000000..c1479658 --- /dev/null +++ b/terraform/common/waf/outputs.tf @@ -0,0 +1,3 @@ +output "web_acl_arn" { + value = aws_wafv2_web_acl.this.arn +} diff --git a/terraform/common/waf/variables.tf b/terraform/common/waf/variables.tf new file mode 100644 index 00000000..78ab66de --- /dev/null +++ b/terraform/common/waf/variables.tf @@ -0,0 +1,12 @@ +variable "project_name" { + type = string +} + +variable "request_threshold" { + type = number + description = "Rate-Limit 규칙에 적용할 5분당 IP별 최대 요청 수" +} + +variable "tags" { + type = map(string) +} From 488c7728fda0a88ccc3b8817f9c1ca95c9ad976c Mon Sep 17 00:00:00 2001 From: lvalentine6 Date: Sat, 20 Sep 2025 21:57:00 +0900 Subject: [PATCH 2/3] =?UTF-8?q?feat:=20waf=20=EB=A1=9C=EA=B7=B8=20?= =?UTF-8?q?=EA=B7=B8=EB=A3=B9=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- terraform/common/main.tf | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/terraform/common/main.tf b/terraform/common/main.tf index d42559f5..2052d1b9 100644 --- a/terraform/common/main.tf +++ b/terraform/common/main.tf @@ -63,3 +63,15 @@ 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 +} From f1355b05242a1a887ddde6b44a74b1118c7cb2fe Mon Sep 17 00:00:00 2001 From: lvalentine6 Date: Sat, 20 Sep 2025 22:27:29 +0900 Subject: [PATCH 3/3] =?UTF-8?q?fix:=20prod=20Infrastructure=20Metrics=20?= =?UTF-8?q?=EC=88=98=EC=A7=91=ED=95=98=EB=8F=84=EB=A1=9D=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- terraform/prod/terraform.tfvars | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/terraform/prod/terraform.tfvars b/terraform/prod/terraform.tfvars index 75867e36..1c31f77c 100644 --- a/terraform/prod/terraform.tfvars +++ b/terraform/prod/terraform.tfvars @@ -11,7 +11,7 @@ ecs_services = { datadog = { task_definition = "datadog" launch_type = "EC2" - scheduling_strategy = "REPLICA" + scheduling_strategy = "DAEMON" } } @@ -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"