Skip to content
Open
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
47 changes: 32 additions & 15 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -157,29 +157,41 @@ jobs:
PLAN_TXT=plan.txt
PLAN_JSON=plan.json

# Run terraform plan
terraform plan -no-color -out=$PLAN_FILE > /dev/null 2> plan_error.txt || echo "PLAN_FAILED=true" >> $GITHUB_ENV

# Show plan text output
terraform show -no-color $PLAN_FILE > $PLAN_TXT 2>/dev/null || echo "Plan failed" > $PLAN_TXT

# Remove ANSI color codes
cat $PLAN_TXT | \
sed 's/`/\\`/g' | \
tr -d '\r' | \
sed -r "s/\x1B\[[0-9;]*[JKmsu]//g" \
> cleaned_plan.txt
if terraform plan -no-color -out=$PLAN_FILE > /dev/null 2> plan_error.txt; then
echo "PLAN_FAILED=false" >> $GITHUB_ENV
terraform show -no-color $PLAN_FILE > $PLAN_TXT
terraform show -json $PLAN_FILE > $PLAN_JSON || true
else
echo "PLAN_FAILED=true" >> $GITHUB_ENV
echo "Plan failed" > $PLAN_TXT
echo "{}" > $PLAN_JSON
fi

# 디버깅용 출력
echo "::group::Raw terraform show output"
cat $PLAN_TXT || echo "(empty)"
echo "::endgroup::"

sed 's/`/\\`/g' $PLAN_TXT | tr -d '\r' | sed -r "s/\x1B\[[0-9;]*[JKmsu]//g" > cleaned_plan.txt

PLAN_CONTENT=$(cat cleaned_plan.txt)
PLAN_ERROR=$(cat plan_error.txt || echo "No error captured")

# Save JSON plan for infracost
terraform show -json $PLAN_FILE > $PLAN_JSON || true
if [ -z "$PLAN_CONTENT" ]; then
PLAN_CONTENT="(no changes or output empty)"
fi

if [ -z "$PLAN_ERROR" ]; then
PLAN_ERROR="(no errors)"
fi

# Output plan content for PR comment
{
echo "PLAN_CONTENT<<EOF"
echo "$PLAN_CONTENT"
echo "EOF"
echo "PLAN_ERROR<<EOF"
echo "$PLAN_ERROR"
echo "EOF"
} >> $GITHUB_OUTPUT
working-directory: ${{ matrix.dir }}

Expand All @@ -203,6 +215,11 @@ jobs:
${{ steps.plan.outputs.PLAN_CONTENT }}
```

### Plan Error (if any)
```
${{ steps.plan.outputs.PLAN_ERROR }}
```

- name: Setup Infracost
uses: infracost/actions/setup@v2

Expand Down
117 changes: 103 additions & 14 deletions prod-team-account/deploy/waf/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,51 @@ provider "aws" {
region = "ap-northeast-2"
}

# rule 목록 정의
locals {
managed_rules = {
# 규칙이름 = { 우선순위, AWS 관리형 규칙 이름 }
"CommonRuleSet" = { priority = 10, name = "AWSManagedRulesCommonRuleSet" }
"KnownBadInputs" = { priority = 20, name = "AWSManagedRulesKnownBadInputsRuleSet" }
"SQLiRuleSet" = { priority = 30, name = "AWSManagedRulesSQLiRuleSet" }
"AmazonIpReputation" = { priority = 40, name = "AWSManagedRulesAmazonIpReputationList" }
}
}

# IP 기반 요청 제한 규칙 생성
resource "aws_wafv2_rule_group" "rate_limit_rule" {
name = "${var.project_name}-rate-limit-rule"
scope = "REGIONAL"
capacity = 50
rule {
name = "RateLimit5Min2000"
priority = 10

action {
block {}
}

statement {
rate_based_statement {
limit = 2000
aggregate_key_type = "IP"
}
}

visibility_config {
cloudwatch_metrics_enabled = true
metric_name = "RateLimitMetric"
sampled_requests_enabled = true
}
}

visibility_config {
cloudwatch_metrics_enabled = true
metric_name = "${var.project_name}-rate-limit-metric"
sampled_requests_enabled = true
}
}

# WAF
resource "aws_wafv2_web_acl" "alb_waf" {
name = "${var.project_name}-alb-waf"
Expand All @@ -22,32 +67,76 @@ resource "aws_wafv2_web_acl" "alb_waf" {
allow {}
}

visibility_config {
cloudwatch_metrics_enabled = true
metric_name = "waf-alb-metric"
sampled_requests_enabled = true
dynamic "rule" {
for_each = local.managed_rules
content {
name = "AWS-${rule.value.name}"
priority = rule.value.priority

override_action {
none {}
}

statement {
managed_rule_group_statement {
vendor_name = "AWS"
name = rule.value.name
}
}

visibility_config {
cloudwatch_metrics_enabled = true
metric_name = "waf-${rule.value.name}-metric"
sampled_requests_enabled = true
}
}
}

# 생성된 규칙을 사용하여 요청 제한 규칙 추가
rule {
name = "AWS-AWSManagedRulesCommonRuleSet"
priority = 1
override_action {
none {}
}
name = "RateLimitRule"
priority = 50

statement {
managed_rule_group_statement {
vendor_name = "AWS"
name = "AWSManagedRulesCommonRuleSet"
rule_group_reference_statement {
arn = aws_wafv2_rule_group.rate_limit_rule.arn
}
}

visibility_config {
cloudwatch_metrics_enabled = true
metric_name = "AWSManagedRulesCommonRuleSet"
metric_name = "RateLimitRuleMetric"
sampled_requests_enabled = true
}
}

visibility_config {
cloudwatch_metrics_enabled = true
metric_name = "waf-alb-metric"
sampled_requests_enabled = true
}

tags = {
Name = "${var.project_name}-alb-waf"
}
}
}

# S3로 로그 전송하도록 설정
resource "aws_wafv2_web_acl_logging_configuration" "waf_logging" {
resource_arn = aws_wafv2_web_acl.alb_waf.arn
log_destination_configs = ["arn:aws:s3:::${var.bucket_name}"]

logging_filter {
default_behavior = "DROP"
filter {
behavior = "KEEP"
requirement = "MEETS_ANY"
condition {
action_condition {
action = "BLOCK"
}
}
}
}
}

6 changes: 6 additions & 0 deletions prod-team-account/deploy/waf/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,10 @@ variable "project_name" {
description = "The name of the project"
type = string
default = "cloudfence"
}

variable "bucket_name" {
description = "The name of the S3 bucket for WAF logs"
type = string

}