Skip to content

[BE][feat]: 테라폼 기반 인프라 laC#1053

Open
2Jin1031 wants to merge 1 commit intodevelop-befrom
feat/1052
Open

[BE][feat]: 테라폼 기반 인프라 laC#1053
2Jin1031 wants to merge 1 commit intodevelop-befrom
feat/1052

Conversation

@2Jin1031
Copy link
Contributor

@2Jin1031 2Jin1031 commented Dec 11, 2025

🔗 관련 이슈

📝 작업 내용

  • dev 환경 테라폼 IaC 작업

주요 변경사항

📸 스크린샷 (Optional)

Summary by CodeRabbit

릴리스 노트

  • Chores
    • 개발 및 프로덕션 환경을 위한 클라우드 인프라 자동화 구성 추가
    • Docker 지원 및 모니터링 기능이 포함된 서버 인스턴스 배포 설정 완료
    • 네트워크 및 보안 정책 구성으로 안정적인 배포 환경 구축

✏️ Tip: You can customize this high-level summary in your review settings.

@github-actions github-actions bot changed the title feat: dev 인프라 테라폼 기능 [BE][feat]: 테라폼 기반 인프라 laC Dec 11, 2025
@github-actions github-actions bot added the BE 백엔드 관련 이슈입니다. label Dec 11, 2025
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 11, 2025

Note

.coderabbit.yaml has unrecognized properties

CodeRabbit is using all valid settings from your configuration. Unrecognized properties (listed below) have been ignored and may indicate typos or deprecated fields that can be removed.

⚠️ Parsing warnings (1)
Validation error: Unrecognized key(s) in object: 'tools'
⚙️ Configuration instructions
  • Please see the configuration documentation for more information.
  • You can also validate your configuration using the online YAML validator.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Walkthrough

이 PR은 Terraform 기반 인프라 코드(IaC)를 도입하는 변경입니다. 네트워크 모듈에서 VPC, 서브넷, 인터넷 게이트웨이, 라우트 테이블, 보안 그룹을 정의하고, 컴퓨트 모듈에서 Nginx/WAS/DB용 EC2 인스턴스와 IAM 역할, Elastic IP를 구성합니다. 개발(dev)과 프로덕션(prod) 환경별로 별도의 설정 파일을 작성하여 각 환경의 변수와 프로바이더를 정의한 후 모듈을 호출합니다.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~35 minutes

주의깊게 검토할 영역:

  • 환경별 변수 관리의 일관성

    • Dev 환경에서는 key_name_was, key_name_db로 분리되어 있으나, Prod 환경에서는 단일 key_name 변수 사용 (임시값 "mulkkam-prod-~~(tmp)" 포함)
    • 두 환경의 변수 네이밍 규칙을 통일하고, Prod의 임시값을 실제 키 페어명으로 교체해야 합니다.
  • 보안 그룹 규칙의 개방 수준

    • Nginx와 WAS 보안 그룹에서 인바운드 트래픽을 0.0.0.0/0에서 허용하고 있습니다.
    • Prod 환경에서는 필요한 경우 소스 IP를 더 제한하거나, 환경별로 다른 CIDR 블록을 허용하는 방식을 고려하세요.
    • 예: WAF/로드밸런서 앞단에 Nginx를 배치한다면 내부 보안 그룹 간 트래픽만 허용하는 것이 권장됩니다.
  • EC2 인스턴스의 공통 User Data 스크립트

    • 현재 세 인스턴스(Nginx, WAS, DB)가 동일한 common_user_data 스크립트를 사용합니다.
    • 각 인스턴스의 역할이 다르다면(DB는 Docker를 필요하지 않을 수 있음), 역할별로 user_data를 분리하는 것이 관리 효율성과 보안 관점에서 나을 수 있습니다.
    • 선택지: (1) 현재대로 유지하되 불필요한 패키지 설치 허용, (2) 역할별 조건부 user_data 스크립트 작성, (3) 초기화 후 SSM Session Manager로 수동 구성
  • 모듈 간 출력값 누락

    • Compute 모듈에서 EC2의 모든 속성을 노출하고 있는데, 주요 출력값(VPC ID, 서브넷 ID, 보안 그룹 ID)에 대한 일관된 명명 규칙 확인이 필요합니다.
    • 또한 Prod 환경의 main.tf에서 compute 모듈 호출 코드가 raw_summary에 누락되어 있으니, 실제 구현 시 네트워크 모듈의 출력값이 올바르게 컴퓨트 모듈에 전달되는지 검증하세요.
  • AWS 프로바이더 버전 고정

    • ~> 6.12 제약 조건으로 마이너 버전 업데이트는 가능하지만, 향후 주요 API 변경에 대비하여 정기적인 버전 검토 계획이 필요합니다.

Pre-merge checks and finishing touches

❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Description check ⚠️ Warning PR 설명은 템플릿 구조를 따르고 관련 이슈(#1052)를 명시하며 작업 내용을 언급했으나, 주요 변경사항의 세부 항목(1., 2., 3.)이 비워져 있어 불완전합니다. 주요 변경사항 섹션에 구체적인 변경 내용을 기재하세요. 예: 1. 네트워크 모듈 추가, 2. 컴퓨트 모듈 추가, 3. dev/prod 환경 설정 구성 등
Linked Issues check ❓ Inconclusive PR이 #1052에서 요청한 테라폼 기반 인프라 IaC 구현을 실현하고 있으나, 연결된 이슈에 구체적인 체크리스트나 요구사항이 기재되지 않아 완전한 검증이 어렵습니다. 이슈 #1052의 상세 작업 내용 섹션에 체크리스트나 구체적 요구사항을 명시하여 변경 사항의 완성도를 검증할 수 있는 기준을 제공하세요.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed PR 제목은 '테라폼 기반 인프라 IaC'라는 변경 사항의 핵심을 요약하고 있으며, 실제 변경 내용(dev/prod 환경의 테라폼 네트워크 및 컴퓨트 모듈 추가)과 일치합니다.
Out of Scope Changes check ✅ Passed 모든 변경사항(network, compute 모듈 및 dev/prod 환경 설정)이 테라폼 기반 인프라 IaC 구현이라는 범위 내에 있으며, 외부 스코프 변경은 없습니다.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/1052

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 8

🧹 Nitpick comments (7)
backend/terraform/modules/network/outputs.tf (1)

1-19: 출력값에 설명(description)을 추가하고, 누락된 리소스 재검토가 필요합니다.

현재 모든 출력값이 설명 없이 정의되어 있어, 이를 사용하는 다른 모듈이나 환경에서 각 값의 용도를 명확히 이해하기 어렵습니다. Terraform의 모범 사례에 따라 각 출력값에 description 필드를 추가하는 것이 권장됩니다.

 output "vpc_id" {
   value = aws_vpc.main.id
+  description = "VPC ID"
 }

 output "subnet_id" {
   value = aws_subnet.public.id
+  description = "Public subnet ID for EC2 instances"
 }

또한 네트워크 모듈에서 생성한 IGW(aws_internet_gateway.igw)도 필요시 출력값으로 노출하는 것을 검토하시기 바랍니다.

backend/terraform/environment/dev/provider.tf (1)

1-14: AWS 프로바이더 버전과 추가 구성 검토를 권장합니다.

현재 설정은 기본적으로 작동하지만, AWS 프로바이더 버전 호환성과 태그 일관성 개선을 위해 다음을 검토하시기 바랍니다:

  1. AWS 프로바이더 버전: ~> 6.12 버전이 현재 프로젝트의 요구사항과 부합하는지 확인이 필요합니다. 최신 버전 사용 시 새로운 기능과 보안 패치의 이점을 받을 수 있습니다.

  2. 기본 태그 구성: 모든 리소스에 일관되게 적용할 기본 태그를 정의하면, 비용 추적과 리소스 관리가 용이해집니다.

 provider "aws" {
   region = var.region
+  
+  default_tags {
+    tags = {
+      Environment = var.environment
+      Project     = var.project
+    }
+  }
 }
backend/terraform/environment/prod/provider.tf (1)

1-14: Dev 환경과의 일관성 유지를 위해 공통 설정 검토를 권장합니다.

Prod 프로바이더 설정이 Dev과 동일한 구조를 따르고 있어 일관성이 좋습니다. 다만 두 환경에서 동일한 설정(버전 요구사항, 기본 태그 등)이 중복되고 있으므로, Terraform 모듈이나 로컬 변수를 활용한 공통화를 고려하시기 바랍니다.

또한 Dev 환경의 프로바이더 리뷰 코멘트에서 제안한 기본 태그(default_tags) 추가도 Prod에도 적용하시기 바랍니다.

backend/terraform/environment/dev/variables.tf (1)

1-49: 환경 변수 정의가 잘 구조화되었으나, 사전 요구사항 명시가 필요합니다.

개발 환경에 적합한 기본값들이 잘 설정되어 있습니다. 다만 다음 사항을 검토하시기 바랍니다:

1. EC2 Key Pair 사전 요구사항
key_name_waskey_name_db는 AWS에 사전에 생성된 EC2 키 페어를 참조합니다. 만약 해당 키 페어가 존재하지 않으면 배포가 실패합니다. README나 배포 문서에 이러한 사전 요구사항을 명시하시기 바랍니다.

# 사전 요구사항
다음 EC2 키 페어가 사전에 AWS 콘솔에서 생성되어야 합니다:
- mulkkam-dev-was
- mulkkam-dev-db

2. 선택적 개선사항
프로덕션 환경에서의 확장성을 고려하면, 키 페어 이름을 변수로 받아서 일관되게 생성하는 방식도 고려할 수 있습니다:

 variable "key_name_was" {
   type    = string
   default = "mulkkam-dev-was"
+  description = "EC2 Key Pair name for WAS instance (must pre-exist)"
 }
backend/terraform/modules/compute/main.tf (2)

41-55: CloudWatch 상세 모니터링 활성화 권장

세 인스턴스 모두 기본 모니터링만 활성화되어 있습니다(5분 단위 메트릭). 프로덕션 환경과 향후 성능 분석을 위해 상세 모니터링(1분 단위)을 활성화하세요:

monitoring = true

이렇게 하면 CPU, 네트워크, 디스크 I/O 등을 더 세밀하게 추적할 수 있어, 성능 문제 조기 발견이 가능합니다. 비용은 약간 증가하지만 프로덕션 인프라로서는 가치 있는 투자입니다.

Also applies to: 57-72, 74-89


106-120: User data 스크립트 개선: SSM agent 설치 방식 재검토

현재 SSM agent를 snap으로 설치하고 있습니다:

snap install amazon-ssm-agent --classic

문제점:

  • Ubuntu Jammy 22.04는 Debian/APT 기반 배포판인데, snap은 컨테이너 기반 패키징으로 시작이 느리고 안정성이 낮을 수 있음
  • Debian 공식 리포지토리에서 amazon-ssm-agent deb 패키지 설치가 표준

개선안:

apt-get install -y amazon-ssm-agent
systemctl enable amazon-ssm-agent
systemctl start amazon-ssm-agent

또한 user data 상단에 set -e 외에도 전체 오류 처리를 강화하세요:

#!/bin/bash
set -euo pipefail
trap 'echo "Error on line $LINENO"' ERR

apt-get update -y
apt-get install -y docker.io amazon-ssm-agent

systemctl enable docker docker
systemctl enable amazon-ssm-agent
systemctl start docker
systemctl start amazon-ssm-agent

이렇게 하면 스크립트 실행 중 오류 발생 시 정확한 라인을 파악할 수 있고, 더 안정적인 agent 설치가 가능합니다.

backend/terraform/modules/compute/variables.tf (1)

46-52: key_name 변수에 설명(description) 추가 필요

key_name_waskey_name_db 변수는 다른 변수들과 달리 description 필드가 없습니다. 운영자 입장에서 이 변수들의 용도를 명확히 이해해야 합니다.

개선안:

variable "key_name_was" {
  type        = string
  description = "EC2 key pair name for WAS instance SSH access"
}

variable "key_name_db" {
  type        = string
  description = "EC2 key pair name for DB instance SSH access"
}

추가 고려사항:

현재 두 변수 모두 기본값이 없습니다. 이는 사용자가 반드시 값을 제공해야 한다는 의미인데, 이것이 의도라면 명확히 문서화하는 게 좋습니다. 또는 다음 예시처럼 기본값을 제공할 수도 있습니다:

variable "key_name_was" {
  type        = string
  description = "..."
  default     = "mulkkam-was-key"
}

변수 정의의 일관성은 운영 팀의 인프라 이해도를 높이고, 자동화 스크립트 작성을 쉽게 하므로 중요합니다.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f5720e9 and a70f97c.

📒 Files selected for processing (11)
  • backend/terraform/environment/dev/main.tf (1 hunks)
  • backend/terraform/environment/dev/provider.tf (1 hunks)
  • backend/terraform/environment/dev/variables.tf (1 hunks)
  • backend/terraform/environment/prod/provider.tf (1 hunks)
  • backend/terraform/environment/prod/variables.tf (1 hunks)
  • backend/terraform/modules/compute/main.tf (1 hunks)
  • backend/terraform/modules/compute/outputs.tf (1 hunks)
  • backend/terraform/modules/compute/variables.tf (1 hunks)
  • backend/terraform/modules/network/main.tf (1 hunks)
  • backend/terraform/modules/network/outputs.tf (1 hunks)
  • backend/terraform/modules/network/variables.tf (1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
backend/**

⚙️ CodeRabbit configuration file

backend/**: - 1. 팀 및 공식 컨벤션, 가독성, 예외처리, 테스트/확장/유지보수성, 모듈화, API/DB/보안 설계 기준을 기반으로 리뷰해주세요.

    1. 최신 트렌드, 불필요한 로직, 클린코드, 리팩토링, 서비스/도메인 설계, 공통 예외 처리, 확장성도 함께 확인해주세요.
    1. 각 피드백은 문제점·대안·장단점을 짧고 논리적으로, 예시 코드가 있다면 간결히 포함해 주세요.
    1. 팀 내 스타일 통일성도 확인해주세요.
    1. 미작성한 테스트 코드 케이스가 있다면, 어떤 테스트가 필요한지 제안해주세요. (예: 컨트롤러는 인수 테스트, 나머지는 단위 테스트)
    1. 리뷰 남겨주는 부분은 해당 라인 범위의 코멘트에 작성해주세요.

Files:

  • backend/terraform/modules/network/outputs.tf
  • backend/terraform/modules/network/main.tf
  • backend/terraform/environment/dev/variables.tf
  • backend/terraform/environment/dev/main.tf
  • backend/terraform/environment/prod/provider.tf
  • backend/terraform/modules/compute/variables.tf
  • backend/terraform/environment/dev/provider.tf
  • backend/terraform/modules/network/variables.tf
  • backend/terraform/modules/compute/main.tf
  • backend/terraform/modules/compute/outputs.tf
  • backend/terraform/environment/prod/variables.tf
🪛 Checkov (3.2.334)
backend/terraform/modules/compute/main.tf

[medium] 41-55: Ensure that detailed monitoring is enabled for EC2 instances

(CKV_AWS_126)


[high] 41-55: EC2 instance should not have public IP.

(CKV_AWS_88)


[high] 41-55: Ensure Instance Metadata Service Version 1 is not enabled

(CKV_AWS_79)


[medium] 57-72: Ensure that detailed monitoring is enabled for EC2 instances

(CKV_AWS_126)


[high] 57-72: EC2 instance should not have public IP.

(CKV_AWS_88)


[high] 57-72: Ensure Instance Metadata Service Version 1 is not enabled

(CKV_AWS_79)


[medium] 74-89: Ensure that detailed monitoring is enabled for EC2 instances

(CKV_AWS_126)


[high] 74-89: EC2 instance should not have public IP.

(CKV_AWS_88)


[high] 74-89: Ensure Instance Metadata Service Version 1 is not enabled

(CKV_AWS_79)

🔇 Additional comments (3)
backend/terraform/environment/dev/main.tf (1)

1-26: 모듈 구성 및 의존성 관리가 잘 이루어졌습니다.

네트워크 모듈과 컴퓨트 모듈 간의 관계가 명확하게 정의되어 있으며, 네트워크 모듈의 출력값이 컴퓨트 모듈의 입력으로 올바르게 연결되어 있습니다. 모듈 간 의존성도 출력값을 통해 자동으로 관리되고 있어 좋습니다.

backend/terraform/modules/network/variables.tf (1)

1-24: 변수 정의가 명확하고 일관성 있게 작성되었습니다.

모든 변수가 적절한 설명과 함께 타입이 명시되어 있어, 이 모듈을 사용하는 환경에서 필요한 입력값을 명확히 이해할 수 있습니다.

backend/terraform/modules/network/main.tf (1)

55-84: Nginx 보안 그룹은 예상되로 설정되었습니다.

Nginx 보안 그룹이 외부에서의 80/443 포트 접근을 올바르게 허용하고 있습니다.

Comment on lines +41 to +44
variable "key_name" {
type = string
default = "mulkkam-prod-~~(tmp)"
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

프로덕션 key_name 임시값 정리 필수

key_name 변수에 "mulkkam-prod-~~(tmp)"라는 표식이 있습니다. 이는 아직 실제 AWS 키 페어 이름으로 교체되지 않은 임시값입니다.

해결 필요 사항:

  1. AWS에서 실제 키 페어 이름 확인 또는 생성 (예: mulkkam-prod-key, mulkkam-prod-app 등)
  2. 변수 기본값을 실제 키 이름으로 교체
variable "key_name" {
  type    = string
  default = "mulkkam-prod-key"  # 실제 키 페어 이름으로 변경
}

또는 기본값을 제거하고 terraform.tfvars 또는 CLI에서 명시적으로 전달하는 방식도 좋습니다:

variable "key_name" {
  type = string
  # description을 추가하면 운영자에게 명확함
  description = "AWS EC2 key pair name for SSH access"
}

그 후 배포 시:

terraform apply -var="key_name=mulkkam-prod-key"

현재 상태로는 prod 환경 배포가 불가능하므로, 먼저 실제 키 페어를 준비한 후 변수값을 확정하세요.

🤖 Prompt for AI Agents
backend/terraform/environment/prod/variables.tf lines 41-44: 현재 key_name 변수에
"mulkkam-prod-~~(tmp)"라는 임시값이 남아 있어 프로덕션 배포 불가 상태입니다; 해결 방법은 실제 AWS EC2 키 페어
이름으로 기본값을 교체하거나 기본값을 제거하고 description을 추가한 뒤 terraform.tfvars 또는 CLI로 명시적으로
key_name을 전달하도록 변경하세요; 구체적으로는 AWS에서 프로덕션용 키 페어 이름을 확인하거나 새로 생성한 뒤 해당 이름을 기본값에
설정하거나 기본값을 삭제해 운영자가 apply 시 -var 또는 tfvars로 값을 넘기게 하세요.

Comment on lines +41 to +89
resource "aws_instance" "nginx" {
ami = data.aws_ami.ubuntu.id
instance_type = var.instance_type_nginx
subnet_id = var.subnet_id
vpc_security_group_ids = [var.nginx_sg_id]
iam_instance_profile = aws_iam_instance_profile.ec2_ssm_profile.name

associate_public_ip_address = true
user_data = local.common_user_data

tags = {
Name = "${var.project}-${var.environment}-nginx"
Env = var.environment
}
}

resource "aws_instance" "was" {
ami = data.aws_ami.ubuntu.id
instance_type = var.instance_type_was
subnet_id = var.subnet_id
vpc_security_group_ids = [var.was_sg_id]
key_name = var.key_name_was
iam_instance_profile = aws_iam_instance_profile.ec2_ssm_profile.name

associate_public_ip_address = true
user_data = local.common_user_data

tags = {
Name = "${var.project}-${var.environment}-was"
Env = var.environment
}
}

resource "aws_instance" "db" {
ami = data.aws_ami.ubuntu.id
instance_type = var.instance_type_db
subnet_id = var.subnet_id
vpc_security_group_ids = [var.db_sg_id]
key_name = var.key_name_db
iam_instance_profile = aws_iam_instance_profile.ec2_ssm_profile.name
associate_public_ip_address = true

user_data = local.common_user_data

tags = {
Name = "${var.project}-${var.environment}-db"
Env = var.environment
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

IMDSv1 비활성화 및 보안 메타데이터 옵션 추가 필수

현재 EC2 인스턴스 설정에 metadata_options가 없어, 기본적으로 IMDSv1이 활성화되어 있습니다. 이는 SSRF(Server-Side Request Forgery) 공격에 노출되는 보안 취약점입니다. IMDSv2는 토큰 기반 인증이 필수라 한 번의 요청으로 권한을 탈취할 수 없으므로, 모든 EC2 인스턴스에서 IMDSv2를 강제해야 합니다.

세 인스턴스 모두에 다음을 추가하세요:

metadata_options {
  http_endpoint               = "enabled"
  http_tokens                 = "required"  # IMDSv2 강제
  http_put_response_hop_limit = 1
}
🧰 Tools
🪛 Checkov (3.2.334)

[medium] 41-55: Ensure that detailed monitoring is enabled for EC2 instances

(CKV_AWS_126)


[high] 41-55: EC2 instance should not have public IP.

(CKV_AWS_88)


[high] 41-55: Ensure Instance Metadata Service Version 1 is not enabled

(CKV_AWS_79)


[medium] 57-72: Ensure that detailed monitoring is enabled for EC2 instances

(CKV_AWS_126)


[high] 57-72: EC2 instance should not have public IP.

(CKV_AWS_88)


[high] 57-72: Ensure Instance Metadata Service Version 1 is not enabled

(CKV_AWS_79)


[medium] 74-89: Ensure that detailed monitoring is enabled for EC2 instances

(CKV_AWS_126)


[high] 74-89: EC2 instance should not have public IP.

(CKV_AWS_88)


[high] 74-89: Ensure Instance Metadata Service Version 1 is not enabled

(CKV_AWS_79)

🤖 Prompt for AI Agents
In backend/terraform/modules/compute/main.tf around lines 41 to 89, the
aws_instance resources for nginx, was and db lack a metadata_options block so
IMDSv1 remains allowed; add a metadata_options block to each aws_instance with
http_endpoint = "enabled", http_tokens = "required" and
http_put_response_hop_limit = 1 to enforce IMDSv2 (token-based) for all
instances.

Comment on lines +41 to +55
resource "aws_instance" "nginx" {
ami = data.aws_ami.ubuntu.id
instance_type = var.instance_type_nginx
subnet_id = var.subnet_id
vpc_security_group_ids = [var.nginx_sg_id]
iam_instance_profile = aws_iam_instance_profile.ec2_ssm_profile.name

associate_public_ip_address = true
user_data = local.common_user_data

tags = {
Name = "${var.project}-${var.environment}-nginx"
Env = var.environment
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# First, let's explore the terraform directory structure
find backend/terraform -type f -name "*.tf" | head -20

Repository: woowacourse-teams/2025-mul-kkam

Length of output: 615


🏁 Script executed:

# Let's read the main.tf file to see the full context
cat -n backend/terraform/modules/compute/main.tf

Repository: woowacourse-teams/2025-mul-kkam

Length of output: 4020


🏁 Script executed:

# Check the variables.tf file to see key_name definitions
cat -n backend/terraform/modules/compute/variables.tf

Repository: woowacourse-teams/2025-mul-kkam

Length of output: 1523


🏁 Script executed:

# Look for local variable definitions, especially local.common_user_data
grep -n "local.common_user_data\|locals\|user_data" backend/terraform/modules/compute/main.tf | head -30

Repository: woowacourse-teams/2025-mul-kkam

Length of output: 292


nginx 인스턴스의 SSH 접근 설정 불일치 검토

현재 구성에서 nginx 인스턴스는 key_name 속성이 없는 반면, was와 db 인스턴스는 각각 var.key_name_was, var.key_name_db를 사용하고 있습니다. 이로 인해 nginx는 SSH 키 기반 접근이 불가능한 상태입니다.

왜 이것이 문제인가:

  • 세 인스턴스가 서로 다른 접근 정책을 가져 운영 복잡도가 증가합니다
  • 긴급 상황이나 트러블슈팅 시 nginx 접근 방식이 다르면 일관성 있는 대응이 어렵습니다
  • 현재 설정이 의도적인 보안 정책인지, 아니면 누락인지 불명확합니다

현재 상태 분석:

  • 세 인스턴스 모두 SSM Session Manager용 IAM 역할(AmazonSSMManagedInstanceCore)을 보유하고 있습니다
  • 모든 인스턴스에서 local.common_user_data를 통해 SSM 에이전트가 설치됩니다 (snap 경로)
  • 따라서 현재로서는 SSM을 통한 접근만 가능합니다

권장 선택지:

선택지 1 (일관성 중심): nginx에도 key_name 변수 추가

  • 모든 인스턴스가 SSH와 SSM 모두로 접근 가능하게 통일
  • 운영 관점에서 인스턴스 간 접근 방식의 일관성 확보
  • 구현: variables.tfvariable "key_name_nginx" 추가 후 nginx 리소스에 key_name = var.key_name_nginx 설정

선택지 2 (보안 중심): nginx는 SSM 전용으로 운영하고, was/db도 SSM으로 통일

  • SSH 포트를 열지 않음으로써 공격 표면 축소
  • 모든 접근이 AWS CloudTrail로 감시되므로 감시/감사 강화
  • 다만 초기 구성 후 SSH 미포함 접근이 필요한 경우, SSM 에이전트 정상 작동이 필수

다음 단계:
의도된 설계가 무엇인지 명확히 한 후, 그에 맞춰 세 인스턴스의 접근 정책을 통일하세요. 선택지 1이라면 key_name_nginx 변수를 추가하고, 선택지 2라면 was와 db에서도 key_name 속성을 제거하는 것이 일관성 있습니다. 선택 사항을 코드 주석이나 문서로 명시하면 향후 운영 시 혼동을 방지할 수 있습니다.

🧰 Tools
🪛 Checkov (3.2.334)

[medium] 41-55: Ensure that detailed monitoring is enabled for EC2 instances

(CKV_AWS_126)


[high] 41-55: EC2 instance should not have public IP.

(CKV_AWS_88)


[high] 41-55: Ensure Instance Metadata Service Version 1 is not enabled

(CKV_AWS_79)

🤖 Prompt for AI Agents
In backend/terraform/modules/compute/main.tf around lines 41-55 the nginx
aws_instance lacks a key_name while was/db instances use key_name variables,
causing inconsistent SSH access; decide the intended design and make instances
consistent: if you want SSH+SSM for all, add variable "key_name_nginx" to
variables.tf and set key_name = var.key_name_nginx on the nginx resource (and
document it); if you want SSM-only, remove key_name usage from the was and db
instance resources (and update docs/variables to reflect no SSH keys); also
ensure security group rules and README reflect the chosen approach.

Comment on lines +57 to +89
resource "aws_instance" "was" {
ami = data.aws_ami.ubuntu.id
instance_type = var.instance_type_was
subnet_id = var.subnet_id
vpc_security_group_ids = [var.was_sg_id]
key_name = var.key_name_was
iam_instance_profile = aws_iam_instance_profile.ec2_ssm_profile.name

associate_public_ip_address = true
user_data = local.common_user_data

tags = {
Name = "${var.project}-${var.environment}-was"
Env = var.environment
}
}

resource "aws_instance" "db" {
ami = data.aws_ami.ubuntu.id
instance_type = var.instance_type_db
subnet_id = var.subnet_id
vpc_security_group_ids = [var.db_sg_id]
key_name = var.key_name_db
iam_instance_profile = aws_iam_instance_profile.ec2_ssm_profile.name
associate_public_ip_address = true

user_data = local.common_user_data

tags = {
Name = "${var.project}-${var.environment}-db"
Env = var.environment
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

공개 IP 할당 전략 재검토 필요

현재 구성에서 **was와 db 인스턴스도 associate_public_ip_address = true**로 설정되어 있습니다. 이는 불필요한 보안 노출입니다:

  • nginx: 리버스 프록시로 외부 트래픽을 받아야 하므로 공개 IP 필요 ✓
  • was: 애플리케이션 서버로 nginx를 통해서만 접근하면 되므로 공개 IP 불필요
  • db: 데이터베이스는 내부 네트워크만 통신해야 하므로 공개 IP는 매우 위험

개선 방향:

  1. was 인스턴스 (Line 65): associate_public_ip_address = false 또는 제거
  2. db 인스턴스 (Line 81): 반드시 associate_public_ip_address = false로 설정

아키텍처 관점에서 was/db는 private subnet에 배치하고, 보안 그룹으로만 인스턴스 간 통신을 제어하는 것이 정석입니다. 현재 구성이 모두 동일 subnet에 있다면, 최소한 공개 IP는 비활성화하세요.

# was: 공개 IP 제거
# associate_public_ip_address = true  제거

# db: 명시적으로 비활성화
associate_public_ip_address = false
🧰 Tools
🪛 Checkov (3.2.334)

[medium] 57-72: Ensure that detailed monitoring is enabled for EC2 instances

(CKV_AWS_126)


[high] 57-72: EC2 instance should not have public IP.

(CKV_AWS_88)


[high] 57-72: Ensure Instance Metadata Service Version 1 is not enabled

(CKV_AWS_79)


[medium] 74-89: Ensure that detailed monitoring is enabled for EC2 instances

(CKV_AWS_126)


[high] 74-89: EC2 instance should not have public IP.

(CKV_AWS_88)


[high] 74-89: Ensure Instance Metadata Service Version 1 is not enabled

(CKV_AWS_79)

🤖 Prompt for AI Agents
In backend/terraform/modules/compute/main.tf around lines 57 to 89, the was and
db aws_instance resources are assigning public IPs which is a security risk;
update the was instance (around line 65) to remove or set
associate_public_ip_address = false and explicitly set
associate_public_ip_address = false for the db instance (around line 81); ensure
instances are placed in private subnets and rely on nginx/proxies and security
groups for external access rather than public IPs.

Comment on lines +1 to +27
output "nginx_instances" {
value = aws_instance.nginx
}

output "was_instances" {
value = aws_instance.was
}

output "db_instances" {
value = aws_instance.db
}

output "nginx_eips" {
value = aws_eip.nginx_eip.public_ip
}

output "nginx_public_ip" {
value = aws_instance.nginx.public_ip
}

output "was_private_ip" {
value = aws_instance.was.private_ip
}

output "db_private_ip" {
value = aws_instance.db.private_ip
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

출력값의 일관성 및 보안 개선이 필요합니다 (중요).

현재 컴퓨트 모듈의 출력값들이 세 가지 문제를 안고 있습니다:

1. 전체 리소스 객체 노출의 문제
aws_instance 전체 객체를 노출하면, 모듈의 내부 구현이 외부에 결합되고, 의도하지 않은 모든 속성(비밀번호, 보안 설정 등)이 노출될 위험이 있습니다. 보안 그룹 접근 시 특정 필요한 속성만 노출하는 것이 모범 사례입니다.

2. 출력값의 불일치
일부는 전체 리소스(nginx_instances), 일부는 특정 속성(nginx_public_ip)을 노출하고 있어 일관성이 없습니다. 이는 모듈 사용자에게 혼동을 초래합니다.

3. 설명 부재
모든 출력값에 설명이 없어서 각 값의 목적을 이해하기 어렵습니다.

개선 방안:

특정 필요한 속성만 개별적으로 노출하도록 리팩토링하는 것을 강력히 권장합니다:

-output "nginx_instances" {
-  value = aws_instance.nginx
-}
-
-output "was_instances" {
-  value = aws_instance.was
-}
-
-output "db_instances" {
-  value = aws_instance.db
-}
-
 output "nginx_eips" {
-  value = aws_eip.nginx_eip.public_ip
+  value = aws_eip.nginx_eip.public_ip
+  description = "Elastic IP address for Nginx instance"
 }

 output "nginx_public_ip" {
   value = aws_instance.nginx.public_ip
+  description = "Public IP address of Nginx instance (via EC2)"
 }

 output "was_private_ip" {
   value = aws_instance.was.private_ip
+  description = "Private IP address of WAS instance"
 }

 output "db_private_ip" {
   value = aws_instance.db.private_ip
+  description = "Private IP address of DB instance"
 }

추가로, 각 인스턴스의 ID나 기타 필요한 속성은 별도의 명시적 출력값으로 정의하시기 바랍니다.

🤖 Prompt for AI Agents
backend/terraform/modules/compute/outputs.tf lines 1-27: 현재 전체 aws_instance 객체를
출력하고 일부만 속성을 노출해 일관성 및 보안 문제가 있으므로 전체 리소스 객체 출력(aws_instance.nginx,
aws_instance.was, aws_instance.db)을 제거하고 각 인스턴스별로 필요한 속성만 출력하도록 변경하세요(예: id,
arn, public_ip 또는 private_ip, 보안그룹 IDs 등), 모든 출력값에 간단한 description을 추가해 목적을 명확히
하고 네이밍을 일관되게 맞추며 EIP는 aws_eip 리소스의 명시적 속성(public_ip, allocation_id 등)만 노출하도록
리팩터링하세요.

Comment on lines +1 to +57
variable "project" {
type = string
description = "Project name"
}

variable "environment" {
type = string
description = "environment (dev, prod, etc)"
}

variable "subnet_id" {
type = string
description = "Subnet ID where EC2 instances will be launched"
}

variable "nginx_sg_id" {
type = string
description = "Security group ID for nginx"
}

variable "was_sg_id" {
type = string
description = "Security group ID for WAS"
}

variable "db_sg_id" {
type = string
description = "Security group ID for DB"
}

variable "instance_type_nginx" {
type = string
description = "Instance type for nginx"
}

variable "instance_type_was" {
type = string
description = "Instance type for WAS"
}

variable "instance_type_db" {
type = string
description = "Instance type for DB"
}

variable "key_name_was" {
type = string
}

variable "key_name_db" {
type = string
}

variable "region" {
type = string
description = "AWS region (e.g., ap-northeast-2)"
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

find . -path "*/terraform/modules/compute/main.tf" -type f

Repository: woowacourse-teams/2025-mul-kkam

Length of output: 118


🏁 Script executed:

find . -path "*/terraform/modules/compute/*" -type f | head -20

Repository: woowacourse-teams/2025-mul-kkam

Length of output: 214


🏁 Script executed:

cat -n ./backend/terraform/modules/compute/main.tf

Repository: woowacourse-teams/2025-mul-kkam

Length of output: 4020


🏁 Script executed:

# Check if there's any documentation or README explaining the terraform design
find ./backend/terraform -name "README*" -o -name "*.md" | xargs grep -l "nginx\|key_name\|SSM" 2>/dev/null

Repository: woowacourse-teams/2025-mul-kkam

Length of output: 59


🏁 Script executed:

# Check the root terraform directory structure
ls -la ./backend/terraform/

Repository: woowacourse-teams/2025-mul-kkam

Length of output: 299


🏁 Script executed:

# Check environment configuration
find ./backend/terraform/environment -type f | head -20

Repository: woowacourse-teams/2025-mul-kkam

Length of output: 359


🏁 Script executed:

# Search for key_name references in the entire terraform directory
rg "key_name" ./backend/terraform/ -A 2 -B 2

Repository: woowacourse-teams/2025-mul-kkam

Length of output: 2862


nginx 인스턴스의 SSH 접근 방식 불일치 검토 필요

terraform 코드를 확인한 결과, 귀사의 지적이 정확합니다. compute 모듈의 세 인스턴스가 서로 다른 접근 방식을 사용하고 있습니다:

  • nginx: key_name 미설정 → SSM 전용 접근
  • was: key_name = var.key_name_was → SSH + SSM 접근 가능
  • db: key_name = var.key_name_db → SSH + SSM 접근 가능

이러한 비대칭적 설계는 의도된 것으로 보입니다(nginx를 공개 IP 기반 리버스 프록시로 보호하면서, was/db는 직접 SSH 접근을 허용). 다만 운영 관점에서 고려할 점들이 있습니다:

현재 설계의 함의:

  1. 접근 방식의 일관성 부재: 세 서버에 다른 접근 절차를 적용해야 하므로 운영 복잡도 증가
  2. 향후 확장성 제약: nginx에 SSH 접근이 필요해지면 모듈 구조부터 수정해야 함
  3. 팀 내 표준화 부족: 접근 방식 선택의 이유가 명확히 문서화되지 않아 새로운 팀원의 이해도 저하

권장사항:
다음 중 하나를 명확히 선택하고 설계 결정을 주석으로 기록하세요:

  • 옵션 1 (권장): 모든 인스턴스에 key_name 제공 → 일관된 운영 절차, nginx도 필요시 직접 접근 가능
  • 옵션 2: nginx만 SSM 전용, was/db도 key_name 제거 → 보안 강화, 단 운영상 비용 증가

현재 snap 기반 SSM 에이전트 설치 방식도 패키지 관리자(apt)를 통한 공식 설치로 변경하면 더욱 안정적입니다.

Comment on lines +86 to +109
# WAS: nginx만 접근 가능
resource "aws_security_group" "was_sg" {
name = "${var.project}-was-sg"
vpc_id = aws_vpc.main.id

ingress {
from_port = 8080
to_port = 8080
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
description = "Allow all traffic to 8080"
}

egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}

tags = {
Name = "${var.project}-was-sg"
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

WAS 보안 그룹의 인바운드 규칙이 의도와 일치하지 않습니다 (심각).

코멘트에는 "WAS: nginx만 접근 가능"이라 명시되어 있으나, 실제로는 cidr_blocks = ["0.0.0.0/0"]로 설정되어 인터넷의 모든 곳에서 8080 포트에 접근 가능한 상태입니다. 이는 심각한 보안 문제입니다.

문제점:

  • 의도(코멘트)와 구현이 일치하지 않음
  • 불필요한 공격 표면(attack surface) 노출
  • 보안 정책 위반

해결 방안:
보안 그룹 간 참조(source_security_group_id)를 사용하여 Nginx 보안 그룹에서만 접근하도록 제한해야 합니다. 보안 그룹에서 특정 보안 그룹의 트래픽만 허용하려면 source_security_group_id를 사용하는 것이 모범 사례입니다.

-# WAS: nginx만 접근 가능
 resource "aws_security_group" "was_sg" {
   name   = "${var.project}-was-sg"
   vpc_id = aws_vpc.main.id

   ingress {
     from_port                = 8080
     to_port                  = 8080
     protocol                 = "tcp"
-    cidr_blocks              = ["0.0.0.0/0"]
-    description              = "Allow all traffic to 8080"
+    source_security_group_id = aws_security_group.nginx_sg.id
+    description              = "Allow traffic from Nginx only"
   }

   egress {
     from_port   = 0
     to_port     = 0
     protocol    = "-1"
     cidr_blocks = ["0.0.0.0/0"]
   }

   tags = {
     Name = "${var.project}-was-sg"
   }
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
# WAS: nginx만 접근 가능
resource "aws_security_group" "was_sg" {
name = "${var.project}-was-sg"
vpc_id = aws_vpc.main.id
ingress {
from_port = 8080
to_port = 8080
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
description = "Allow all traffic to 8080"
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
tags = {
Name = "${var.project}-was-sg"
}
}
resource "aws_security_group" "was_sg" {
name = "${var.project}-was-sg"
vpc_id = aws_vpc.main.id
ingress {
from_port = 8080
to_port = 8080
protocol = "tcp"
source_security_group_id = aws_security_group.nginx_sg.id
description = "Allow traffic from Nginx only"
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
tags = {
Name = "${var.project}-was-sg"
}
}
🤖 Prompt for AI Agents
In backend/terraform/modules/network/main.tf around lines 86-109, the WAS
security group currently allows 0.0.0.0/0 on port 8080 which contradicts the
comment "WAS: nginx만 접근 가능"; replace the cidr_blocks ingress rule with a
security-group-only rule by removing cidr_blocks and adding
source_security_group_id = aws_security_group.nginx_sg.id (or the actual nginx
SG resource reference), update the description to reflect "Allow traffic from
nginx SG only", and ensure the ingress block only permits TCP port 8080 from
that security group; keep the egress unchanged.

Comment on lines +111 to +133
# DB: WAS만 접근 가능
resource "aws_security_group" "db_sg" {
vpc_id = aws_vpc.main.id
name = "${var.project}-db-sg"

ingress {
from_port = 3306
to_port = 3306
protocol = "tcp"
cidr_blocks = [var.vpc_cidr]
}

egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}

tags = {
Name = "${var.project}-db-sg"
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

DB 보안 그룹 규칙을 더욱 제한적으로 개선할 것을 권장합니다.

현재 DB 보안 그룹이 VPC CIDR 전체에서의 3306 포트 접근을 허용하고 있습니다. 이는 동작하지만, 최소 권한 원칙(principle of least privilege) 관점에서는 개선의 여지가 있습니다.

현재 상태의 문제점:

  • VPC 내 모든 인스턴스가 DB에 접근 가능
  • WAS 인스턴스만 DB에 접근 필요한데, 다른 리소스도 접근 가능
  • 향후 VPC에 다른 리소스가 추가될 때 불필요한 노출 위험

개선 방안:
WAS 보안 그룹의 규칙 수정과 함께, DB 보안 그룹도 WAS 보안 그룹을 명시적 소스로 지정하는 것이 권장됩니다:

 # DB: WAS만 접근 가능
 resource "aws_security_group" "db_sg" {
   vpc_id = aws_vpc.main.id
   name   = "${var.project}-db-sg"

   ingress {
     from_port   = 3306
     to_port     = 3306
     protocol    = "tcp"
-    cidr_blocks = [var.vpc_cidr]
+    source_security_group_id = aws_security_group.was_sg.id
+    description              = "Allow traffic from WAS only"
   }

   egress {
     from_port   = 0
     to_port     = 0
     protocol    = "-1"
     cidr_blocks = ["0.0.0.0/0"]
   }

   tags = {
     Name = "${var.project}-db-sg"
   }
 }

장점:

  1. 최소 권한 원칙 준수
  2. 코드 의도와 구현의 일치
  3. VPC 구조 변경 시에도 보안 정책 자동 유지
  4. 보안 감사 및 이해가 용이
🤖 Prompt for AI Agents
In backend/terraform/modules/network/main.tf around lines 111 to 133, the DB
security group currently allows MySQL (3306) from the entire VPC CIDR; change
the ingress to allow port 3306 only from the WAS security group instead. Replace
cidr_blocks = [var.vpc_cidr] with a security_groups (or
source_security_group_id) reference to the WAS security group resource (e.g.,
aws_security_group.was_sg.id or a passed-in was_sg_id variable), ensure the WAS
SG resource/variable exists and is created before the DB SG, and keep the egress
unchanged; update tags/comments accordingly to reflect the tighter rule.

@2Jin1031 2Jin1031 closed this Dec 16, 2025
@2Jin1031 2Jin1031 reopened this Dec 16, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

BE 백엔드 관련 이슈입니다.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant