API 서버 앞에 ALB를 구성하면서 문득 의문이 들었다. ALB의 Listener Rule만으로도 경로 분기, IP 제한, 심지어 헤더 기반 제어까지 가능한데, 왜 API Gateway와 WAF라는 계층이 추가로 필요한 걸까?
각 계층이 하는 일이 겹치는 것처럼 보였고, 비용도 추가되는데 정말 필요한지 확신이 서지 않았다.
역할: 도메인 이름을 실제 트래픽 진입점으로 연결하는 DNS 서비스
Route53은 사용자가 api.example.com을 입력했을 때 실제로 요청이 도달할 AWS 리소스의 IP 주소를 알려주는 역할만 한다. 보안 검사나 인증 같은 개념은 여기 없다. 단지 "이 도메인은 저기로 가세요"라고 안내하는 것이다.
역할: HTTP 요청 패턴을 검사해 악의적인 공격 차단
WAF는 애플리케이션 로직 이전에, HTTP 프로토콜 수준에서 위험한 패턴을 걸러낸다. SQL Injection, XSS, Bot 트래픽처럼 명백히 악의적인 요청은 이 단계에서 차단되므로, 뒤쪽 인프라에 부하를 주지 않는다.
ALB에서도 IP 기반 차단이 가능하지만, WAF는 요청 본문의 패턴까지 분석한다. DELETE FROM users WHERE 1=1 같은 쿼리가 들어있는지, <script> 태그가 포함됐는지를 검사하는 것은 WAF만 가능하다.
역할: 클라이언트와 맺는 API 계약을 관리하고, 인증·인가·제한 정책 적용
API Version 관리, Usage Plan, API Key, Lambda Authorizer 같은 개념은 서버가 아니라 이 계층의 책임이다. 서버는 이미 검증된 요청만 받아서 비즈니스 로직에 집중할 수 있다.
ALB의 Listener Rule로도 헤더 조건 검사는 가능하지만, "하루 10,000번만 호출 가능" 같은 Usage Plan이나 JWT 검증 후 백엔드로 사용자 정보 전달은 API Gateway만 처리할 수 있다. ALB는 "이 사용자가 누구인지"는 모른다.
역할: HTTP/HTTPS 트래픽을 여러 서버로 분산하고, Health Check로 서버 상태 관리
ALB의 Listener Rule은 Path, Host Header, HTTP Method, Source IP를 조건으로 트래픽을 분기할 수 있다. 예를 들어 /api/v1/*은 백엔드 서버로, /admin/*은 관리자 서버로 보내는 식이다. 하지만 ALB의 목적은 항상 동일하다. 서버를 살리는 것이다.
ALB는 "이 요청이 어떤 API 버전인지", "이 클라이언트가 하루에 몇 번 호출했는지"는 관심 없다. 단지 트래픽이 한 서버에 몰리지 않도록 분산하고, Health Check로 죽은 서버를 제외하는 데 집중한다.
각 계층의 역할을 이해하고 나니, "질문"으로 책임을 구분할 수 있었다:
[외부 요청]
↓
[WAF] ← "이 요청은 공격인가?"
↓
[API Gateway] ← "이 클라이언트는 자격이 있는가?"
↓
[ALB] ← "어느 서버로 보낼 것인가?"
↓
[EC2] ← "어떻게 처리할 것인가?"
| 계층 | 검사 대상 | 처리 불가능한 것 |
|---|---|---|
| WAF | 요청 패턴 (SQL Injection, XSS, Bot) | 사용자 자격 검증, 서버 상태 |
| API Gateway | API 자격 (JWT, Usage Plan, API Key) | 요청 본문 패턴 검사, 서버 분산 |
| ALB | 서버 상태 (Health Check, 트래픽 분산) | 사용자별 요청 제한, 패턴 검사 |
| EC2 | 비즈니스 로직 | 모든 검증은 이미 끝난 상태 |
WAF = "이 요청은 공격인가?" → 요청 패턴 검사
API Gateway = "이 클라이언트는 자격이 있는가?" → API 계약 검증
ALB = "어느 서버로 보낼 것인가?" → 서버 상태 관리
보안 경계 = 바깥에서 안쪽으로 점점 좁혀진다 (WAF → API GW → ALB → EC2)
각 계층이 자기 질문만 답한다 → 서버는 비즈니스 로직에 집중