프로젝트 개요
동일한 애플리케이션 코드를 취약(Vulnerable)·보안(Secure) 두 AWS 환경에 배포하고, 7가지 실제 공격 시나리오를 동시에 실행해 보안 설정 차이의 효과를 실시간으로 비교하는 클라우드 보안 실습 플랫폼입니다.
공격 완료 후 수집된 HTTP 접근 로그를 Amazon Bedrock(Claude 3.5 Haiku)으로 자동 분석하여 취약·보안 환경의 차이를 AI가 해설합니다.
배경 및 동기
클라우드 보안 설정을 "올바르게 했다"는 사실보다, 설정 차이가 실제 공격에서 어떤 차이를 만드는지 직접 확인하는 것이 더 깊은 이해로 이어진다고 생각했습니다.
WAF가 SQLi를 막고, SG 제한이 Origin 직접 접근을 차단한다는 건 문서로 알 수 있습니다. 하지만 그 효과를 실제로 측정하려면 코드가 동일한 서비스를 인프라 구성만 달리해서 같은 공격에 노출시켜야 합니다. 변수를 인프라 하나로 고정하고 공격 시뮬레이션 결과를 비교하는 것이 이 프로젝트의 목표였습니다.
시스템 구조

세 개의 VPC로 구성됩니다. 애플리케이션 코드는 두 환경 모두 동일하며, 앞단 인프라 구성만 다릅니다.
취약 환경 VPC: EC2(백엔드 + Wazuh Agent) + PostgreSQL, S3 Block Public Access OFF, 보안 레이어 없이 Origin 직접 노출.
보안 환경 VPC: CloudFront → WAF(Managed Rules + Rate Limit) → Security Group(CloudFront 소스 제한) → EC2(백엔드 + Wazuh Agent) + PostgreSQL, S3 Block Public Access ON. IAM / KMS / Secret Manager / CloudTrail로 추가 보안 레이어 구성.
메인 대시보드 VPC: ECS Fargate로 배포된 공격 대시보드. Terraform + Prowler로 두 환경의 프로비저닝 및 컴플라이언스 점검을 수행. Private 서브넷에 Wazuh Manager + Elasticsearch + Kibana 스택을 구성해 양 환경의 로그를 중앙 수집.
배포 방식:
- 프론트엔드 (React): S3 정적 웹호스팅
- 백엔드 (Node.js): EC2 + SSM 배포
- 공격 대시보드 (Next.js): ECS Fargate
인프라 구성
세 VPC가 VPC Peering으로 연결됩니다. 공격 대시보드가 양 환경에 동시에 공격을 전송하고, Wazuh Agent가 수집한 로그는 메인 VPC의 Wazuh Manager로 집계됩니다.
기술 스택
주요 기능
7가지 공격 시나리오 실시간 실행
Origin 직접 접근 우회, 봇 경로 스캔, RCE/Log4Shell(JNDI 6종), SQLi/XSS(6종), 브루트포스 로그인(100 credential), S3 데이터 탈취 체인, SSRF/IMDS 탈취를 취약·보안 환경에 동시 전송하고 결과를 SSE 스트리밍으로 실시간 비교합니다.
InfraControl — 원클릭 배포/삭제
Attack Dashboard 내에서 GitHub Actions workflow_dispatch를 직접 트리거해 취약·보안 환경 전체를 프로비저닝하거나 삭제할 수 있습니다. 배포 완료 시 EC2 ID·EIP·CloudFront URL이 GitHub Secrets에 자동 주입되고, 프론트엔드 배포 워크플로우가 연쇄 실행됩니다.
AI 사후 분석
공격 세션 완료 시 HTTP 접근 로그 + 공격 결과를 S3에 자동 저장하고, Bedrock Claude 3.5 Haiku가 취약 환경 피해·보안 환경 방어 효과를 SSE 스트리밍으로 해설합니다. 한/영 토글을 지원합니다.
수동 배포 가이드
Terraform 자동 배포 외에 EC2·S3·CloudFront·WAF 각 리소스를 직접 생성하고 연결하는 단계별 가이드를 제공합니다. 두 환경을 직접 구축해보며 보안 설정 차이를 체감할 수 있습니다.
공격 대시보드에서 7가지 시나리오를 취약·보안 환경에 동시 실행하고 AI 분석을 수신하는 전체 흐름
구현 포인트
CloudFront custom_error_response 오탐 처리
WAF가 공격 요청에 403을 반환하면 CloudFront의 custom_error_response 설정이 이를 200 + HTML로 변환해 공격 대시보드가 "성공"으로 오판정하는 문제가 있었습니다. HTTP 상태코드만으로 판정하지 않고 Content-Type: text/html 여부를 추가 체크하는 재판정 로직으로 해결했습니다.
InfraControl — 배포 중 상태 보호
배포 도중 "초기화" 버튼을 누르면 GitHub Actions 워크플로우는 중단하지 않고 SSE 연결만 끊도록 의도적으로 설계했습니다. 중간 취소 시 리소스가 반쯤 생성된 상태로 남아 terraform destroy조차 실패하는 상황을 방지하기 위해서입니다.
취약·보안 환경을 동시에 apply할 경우 VPC 리소스 충돌이 발생할 수 있어, 한쪽 VPC 생성이 완료되지 않은 시점에는 반대 환경의 배포 버튼을 비활성화(applyLocked)합니다. VPC 준비 완료 신호 수신 시 자동 해제됩니다.
AI 분석 입력 설계 — 공격자 시점과 서버 시점의 교차 분석
AI가 "어느 레이어가 차단했는가"를 정확히 판단하려면 단일 데이터 소스로는 불충분합니다. 공격자가 받은 HTTP 응답만 있으면 WAF가 막은 건지 SG가 막은 건지 구분이 불가능하고, 서버 로그만 있으면 서버에 도달하지 않은 요청(WAF/SG 차단)은 아예 보이지 않습니다.
두 시점의 데이터를 동시에 넣고 교차 분석을 명시적으로 지시하는 구조로 설계했습니다:
- 공격자 시점 (
attackResults): 각 단계에서 받은 HTTP 상태코드 + 응답지연 - 서버 시점 (
rawLogs): EC2 백엔드가 실제 수신한 raw HTTP 요청 로그 (공격 시간대 슬라이싱)
프롬프트에서 AI에게 "공격자는 403을 받았지만 서버 로그에 없음 → WAF 선제 차단"처럼 두 데이터 간 불일치 자체를 근거로 쓰도록 명시했습니다.
서버 로그 수집 시간 윈도우도 앞뒤 버퍼를 추가했습니다(from = startTime - 10s, to = endTime + 30s). EC2 클럭이 대시보드보다 수 초 느릴 경우 공격 첫 요청이 startTime 이전 타임스탬프로 기록되어 누락될 수 있기 때문입니다.
시나리오별 컨텍스트 주입(getScenarioContext())에서는 "어느 레이어가 차단했는가"의 답을 직접 주지 않되, AI가 잘못된 전제로 추론하지 않도록 최소한의 구조 정보만 제공했습니다. 정답을 너무 많이 노출하면 분석 가치가 없어지고, 너무 적게 주면 엉뚱한 전제에서 출발한 오분석이 나오기 때문입니다.
WAF scope와 리전 분리
CloudFront에 연결하는 WAF는 scope가 CLOUDFRONT여서 반드시 us-east-1에 생성해야 합니다. Terraform에서 provider alias를 선언해 나머지 리소스(ap-northeast-2)와 분리 관리했습니다.
주요 성과
- 7가지 공격 시나리오 구현 (Origin 우회, 봇 스캔, RCE/Log4Shell, SQLi/XSS, 브루트포스, S3 탈취, SSRF/IMDS 탈취)
- Terraform 38개 AWS 리소스 자동 프로비저닝 (취약·보안 2개 환경)
- 보안 환경 4개 레이어 구성: CloudFront → WAF(Managed Rules + Rate Limit) → Security Group → S3 Block Public Access
- GitHub Actions 9개 워크플로우로 배포 전 과정 자동화 (빌드 검증 → ECR 푸시 → SSM 배포 → Secrets 주입 → 프론트엔드 연쇄 배포)
- Wazuh SIEM 구축: 양 환경 Wazuh Agent → Wazuh Manager → Elasticsearch + Kibana 중앙 수집
- Prowler 컴플라이언스 점검 및 Trivy CI/CD 이미지 취약점 스캔 통합