SG
이 리소스가 어떤 source와 port를 받아도 되는가를 묻는다. 허용 규칙만 있고 응답은 stateful하게 돌아간다.
ECS -> RDS, ALB -> ECS처럼 리소스 간 접근을 좁힐 때분류: Layer 3 - AWS 인프라 & 보안
Network Security는 애플리케이션 코드에 도달하기 전과 도달하는 동안의 트래픽을 허용, 차단, 완화, 암호화, 관측하는 인프라 보안 계층이다.
이 문서에서 붙잡을 핵심 도구는 여섯 가지다.
| 도구 | 첫 정의 | 주로 보는 것 |
|---|---|---|
| SG(Security Group) | ENI에 붙는 stateful 허용 규칙 | 리소스 단위 IP/포트 접근 |
| NACL(Network ACL) | Subnet에 붙는 stateless 허용/차단 규칙 | 서브넷 단위 IP/포트 접근 |
| WAF(Web Application Firewall) | HTTP 요청 내용을 검사하는 L7 방화벽 | URI, header, body, rate, managed rule |
| Shield | DDoS 트래픽을 탐지하고 완화하는 AWS 서비스 | L3/L4 대용량 공격, 일부 L7 방어 |
| TLS/ACM | 전송 구간 암호화와 인증서 관리 | HTTPS, 인증서 갱신, 종단 위치 |
| VPC Flow Logs | ENI/VPC/Subnet의 IP 트래픽 메타데이터 | 패킷 도착, ACCEPT/REJECT |
첫 회독에서는 “무엇이 더 강한가”보다 어느 계층에서 무엇을 볼 수 있는가를 먼저 구분한다. SG와 NACL은 HTTP body를 볼 수 없고, WAF는 TCP handshake 자체를 고치지 못하며, Flow Logs는 SQL Injection 패턴을 보여주지 않는다.
네트워크 보안 문서는 L3, L4, L7이라는 말을 자주 쓴다. 이 이름은 OSI 7계층 전체를 외우라는 뜻이 아니라, 방어 도구가 무엇을 근거로 판단하는지를 구분하기 위한 약속이다.
| 레이어 | 이 문서에서의 의미 | 판단 재료 | 대표 실패 |
|---|---|---|---|
| L3(Network) | IP 패킷이 어디에서 어디로 가는가 | source IP, destination IP, protocol | 대역폭 포화, 라우팅 오류, IP 범위 차단 |
| L4(Transport) | 어떤 포트와 연결 상태를 쓰는가 | TCP/UDP, port, SYN/ACK, connection state | SYN Flood, 포트 차단, idle timeout |
| L7(Application) | HTTP 요청이 어떤 의미를 갖는가 | method, path, query, header, body, cookie | SQLi/XSS 패턴, HTTP Flood, bot, rate abuse |
작은 요청 하나로 보면 차이가 선명하다.
GET /api/orders?status=open HTTP/1.1Host: api.example.comCookie: session=...client-ip -> alb-ip:443 같은 IP/포트 흐름을 본다./api/orders, query string, header, body의 패턴을 본다.여기서 WAF와 TLS의 관계를 물리 장비 순서처럼 읽으면 안 된다. HTTPS payload는 네트워크 위에서 암호문이므로 WAF가 ALB의 TLS termination 전에 암호문 속 body를 읽는 구조가 아니다. CloudFront나 ALB 같은 지원 리소스가 자기 서비스 경계에서 TLS를 종료해 HTTP 요청을 해석할 수 있게 만들고, 연결된 Web ACL이 그 논리적 요청을 평가한 뒤 허용된 요청만 origin이나 target으로 전달한다. TLS ClientHello에서 얻는 JA3/JA4 같은 신호는 예외적으로 복호화된 body가 아니라 handshake 메타데이터다.
즉 네트워크 보안은 “방화벽 하나 켜기”가 아니다. 서로 다른 관측 지점을 겹쳐서 단일 방어선 실패를 흡수하는 구조다.
lineage_oneliner는 “L1 웹 보안만으로는 DDoS·포트 스캔 같은 네트워크 공격 불가 → 인프라 필터링 필요”다. 이 문장이 의미하는 한계는 두 가지다.
첫째, L1 Web Security의 SQL Injection, XSS, CSRF 방어는 대부분 요청이 애플리케이션 코드까지 도달한 뒤 동작한다. 하지만 DDoS는 그 전에 대역폭, 로드밸런서, connection table, Node.js event loop, DB connection pool을 먼저 소모시킬 수 있다. 요청이 코드에 도달하지 못하면 코드 안의 validation도 실행되지 않는다.
둘째, VPC / Subnet / Security Group의 SG와 NACL은 기본적으로 IP/포트 중심이다. 정상 포트인 443으로 들어온 HTTP 요청 안에 악성 payload가 들어 있어도 SG는 “443이 열려 있다”까지만 판단한다. SG가 “누가 어느 포트로 들어오는가”를 묻는다면, WAF는 “그 요청 안에 무엇이 들어 있는가”를 묻는다.
이 토픽은 그래서 아래 네 계층을 묶는다.
Cloudflare Radar의 2025 Q3 DDoS 보고서는 그 분기에 Cloudflare가 8.3M건의 DDoS를 완화했고, 그중 network-layer가 71%, HTTP DDoS가 29%였으며 최대 공격은 29.7 Tbps였다고 보고했다. 이 숫자는 AWS 용량 산정 기준이 아니라 L3/L4와 L7 방어를 분리해서 설계해야 한다는 역사적 사례로만 읽는다.
네트워크 보안 문서가 어려운 이유는 제품명이 아니라 같은 트래픽을 부르는 이름이 많기 때문이다. 아래 용어는 이후 절에서 반복된다.
| 용어 | 뜻 | 이 문서에서 중요한 이유 |
|---|---|---|
| packet | 네트워크가 보내는 작은 데이터 단위 | Flow Logs와 NACL은 packet 관점에 가깝다 |
| connection | TCP처럼 상태를 가진 통신 흐름 | SG의 stateful 동작과 idle timeout을 이해할 때 필요하다 |
| request | HTTP method/path/header/body를 가진 L7 요청 | WAF는 request 내용을 검사한다 |
| flow | 같은 출발지/목적지/포트/프로토콜 묶음 | Flow Logs record를 읽는 기본 단위다 |
| edge | 사용자와 가까운 외곽 경계 | CloudFront, CDN, WAF, DDoS 완화가 먼저 작동한다 |
| origin | 실제 애플리케이션 서버나 ALB 뒤쪽 | edge에서 못 줄이면 origin 비용이 오른다 |
| allowlist | 허용할 대상 목록 | 예외를 줄 때 범위를 작게 유지해야 한다 |
| denylist | 차단할 대상 목록 | NACL deny나 WAF IP set에 쓰지만 관리가 어려워질 수 있다 |
| false positive | 정상 요청을 공격으로 오탐 | WAF Count mode가 필요한 이유다 |
| false negative | 공격 요청을 정상으로 놓침 | managed rules만 믿지 않고 app validation이 필요한 이유다 |
| fail-open | 장애 시 트래픽을 통과시킴 | 가용성은 지키지만 공격도 통과할 수 있다 |
| fail-closed | 장애 시 트래픽을 차단함 | 보안은 강하지만 정상 사용자 장애가 커질 수 있다 |
작은 차이를 예로 들면 timeout은 보통 네트워크 경로나 target 응답 문제를 의심하게 만들고, 403은 WAF나 애플리케이션이 의도적으로 거부했다는 신호에 가깝다. 이 둘을 같은 “API 호출 실패”로 묶으면 잘못된 계층을 고치게 된다.
아래 흐름은 외부 사용자가 API를 호출해 DB를 읽는 전형적인 구조다. 각 계층이 같은 요청을 다른 질문으로 본다.
flowchart TD
User["사용자"] --> Shield["AWS edge / Shield: DDoS 완화"]
Shield --> Reach{"지원 리소스 경계까지 도달?"}
Reach -->|ALB 경로의 NACL/SG 거부| Drop["L3/L4에서 차단"]
Reach -->|Yes| Resource["CloudFront 또는 ALB HTTPS 경계"]
Resource --> Tls["서비스가 TLS 종료: HTTP 요청 해석 가능"]
Tls --> Waf{"연결된 WAF Web ACL 평가"}
Waf -->|Block| WafBlock["L7에서 차단"]
Waf -->|Allow| Forward["cache / listener rule / origin 전달"]
Forward --> SgIn{"target SG 허용?"}
SgIn -->|No| DropResource["target 앞에서 차단"]
SgIn -->|Yes| App["ECS/EC2 애플리케이션"]
App --> DbSg{"RDS SG 허용?"}
DbSg -->|Yes| Db["RDS"]
App -.-> Flow["Flow Logs: ACCEPT/REJECT 메타데이터"]
Waf -.-> WafLogs["WAF Logs: rule/action/matched data"] CloudFront와 ALB를 모두 거쳐야 한다는 뜻이 아니라, WAF를 연결한 지원 리소스 안에서 TLS 종료 후 논리적 HTTP 요청을 평가한다는 모델이다.
이 흐름에서 자주 나오는 오해는 “앞단에 WAF가 있으니 SG를 넓게 열어도 된다”다. 그렇지 않다. 트래픽이 WAF 적용 경로를 지나지 않거나, 내부에서 직접 호출되거나, 잘못된 리소스에 WAF가 붙어 있으면 SG가 마지막 경계가 된다. 반대로 SG를 정확히 닫아도, 허용된 443 트래픽 안의 SQL Injection 패턴은 WAF나 애플리케이션 validation이 봐야 한다.
이 리소스가 어떤 source와 port를 받아도 되는가를 묻는다. 허용 규칙만 있고 응답은 stateful하게 돌아간다.
ECS -> RDS, ALB -> ECS처럼 리소스 간 접근을 좁힐 때이 Subnet 경계에서 어떤 IP/port를 명시적으로 허용하거나 차단할 것인가를 묻는다. inbound와 outbound가 별도다.
서브넷 전체 IP 차단, 사고 대응용 deny, 방어 심층화가 필요할 때HTTP 요청이 규칙과 매칭되는가를 묻는다. URI, header, body, rate를 검사한다.
SQLi, XSS, bot, HTTP flood, 특정 path rate limit을 다룰 때DDoS 트래픽을 자동으로 탐지하고 완화한다. Standard는 기본, Advanced는 지원·가시성·비용 보호 요구가 있을 때 검토한다.
대용량 트래픽으로 정상 사용자가 접근하지 못하는 위험을 줄일 때하나의 요청을 각 계층이 어떻게 다르게 기록하는지 ledger처럼 써 보면 진단 순서가 명확해진다.
사용자 요청:GET https://api.example.com/orders?status=open
경로:Client -> CloudFront TLS termination -> CloudFront-associated WAF -> ALB TLS listener -> ECS Task -> RDS| 계층 | 관측 가능 신호 | 정상일 때 | 실패할 때 |
|---|---|---|---|
| DNS/edge | 도메인이 edge로 해석되는가 | CloudFront 또는 ALB DNS로 연결 | 잘못된 DNS, 오래된 CNAME |
| Shield | 트래픽 양과 패턴이 비정상인가 | 별도 event 없음 | DDoS event, request/packet spike |
| TLS/ACM | 인증서와 handshake가 맞는가 | HTTPS 200/3xx | cert error, TLS handshake failure |
| WAF | 복호화된 request가 rule에 매칭되는가 | AllowedRequests 증가 | BlockedRequests, terminatingRuleId |
| NACL | subnet inbound/outbound가 통과하는가 | Flow Logs ACCEPT 또는 관련 로그 없음 | REJECT, 특히 ephemeral port 누락 |
| SG | resource inbound가 source를 허용하는가 | ALB SG -> ECS SG 허용 | timeout, target unhealthy |
| App | route, auth, business rule이 맞는가 | 2xx/4xx 의도된 응답 | 5xx, app log error |
| DB SG | app SG가 DB port로 들어오는가 | query 성공 | DB connection timeout |
이 표에서 4xx는 항상 나쁜 신호가 아니다. 인증되지 않은 사용자가 보호된 API에 접근해 401이나 403을 받는 것은 애플리케이션이 정상적으로 거부한 결과일 수 있다. 반면 WAF가 정상 사용자의 editor payload를 403으로 막는 것은 false positive다. 같은 status code라도 어느 계층이 만든 응답인지가 더 중요하다.
아래 반례는 “한 계층만 잘하면 된다”는 직관을 깨기 위한 것이다.
| 빠진 계층 | 반례 | 왜 문제인가 |
|---|---|---|
| SG | WAF가 붙은 ALB 뒤 ECS가 0.0.0.0/0:8080을 받는다 | 내부 경로나 실수로 직접 노출될 때 원본이 열린다 |
| WAF | SG는 443만 열었지만 /search?q=...에 공격 패턴이 들어온다 | SG는 443 허용 여부만 보고 HTTP 의미를 모른다 |
| TLS redirect | 443은 정상인데 80 listener가 forward다 | 사용자가 HTTP로 세션/토큰을 보낼 수 있다 |
| Flow Logs | 장애 때 SG를 계속 열어 본다 | 패킷 미도달인지 정책 차단인지 구분하지 못한다 |
| Count rollout | managed rules를 바로 Block한다 | 정상 요청 오탐이 장애로 드러난다 |
좋은 네트워크 보안 문서는 제품 체크리스트가 아니라 이런 반례를 줄이는 구조다.
공격 규모를 rps 하나로만 보면 어느 방어선이 필요한지 결정하기 어렵다. 다음은 HTTP flood가 들어오는 학습용 가상 서비스다.
공격 트래픽: 10,000 requests/s평균 요청 크기: 2 KiB애플리케이션 처리 비용: 요청당 CPU 20 ms애플리케이션 가용 CPU: 8 cores먼저 payload 대역폭만 계산하면 10,000 * 2 KiB * 8이므로 약 164 Mbps다. 프로토콜 overhead를 빼고도 이 값은 “인터넷 회선을 수십 Gbps로 채우는 공격”과는 다른 규모다. 하지만 애플리케이션이 모든 요청을 처리하면 초당 10,000 * 20 ms = 200 CPU-seconds가 필요하다. 8 cores는 이상적으로도 초당 CPU 8초만 제공하므로, 네트워크 대역폭이 남아도 애플리케이션은 먼저 포화된다.
이때 각 계층의 판단은 다르다.
| 계층 | 이 숫자에서 보는 질문 | 할 수 없는 일 |
|---|---|---|
| Shield | 패킷·연결 규모가 AWS edge에서 자동 완화 대상인가 | 비싼 /report와 싼 /health의 앱 비용을 모른다 |
| SG/NACL | source IP와 443 포트가 허용 범위인가 | 허용된 443 안의 10,000 rps 의미를 구분하지 못한다 |
| WAF | path·IP 등으로 flood를 origin 전에 줄일 수 있는가 | 사용자별 quota와 DB transaction 의미를 모른다 |
| TLS | 요청이 암호화되고 기대한 서버에 도착했는가 | 암호화된 요청의 양이나 처리 비용을 줄이지 않는다 |
| App/cache | 요청당 CPU·DB 비용을 줄이고 사용자별 정책을 지키는가 | edge 대역폭이 이미 포화된 뒤에는 실행되지 못한다 |
WAF와 cache가 origin 요청을 90% 줄여 1,000 rps만 남기면 앱 비용도 초당 CPU 200초에서 20초로 10분의 1이 된다. 그래도 8 cores보다 크므로 queue, 더 높은 cache hit, app rate limit, autoscaling 중 추가 수단이 필요하다. 반대로 10 Gbps UDP flood에는 WAF가 읽을 HTTP 요청 자체가 없으므로 같은 처방을 쓸 수 없다.
요청 byte가 작다고 처리 비용도 작은 것은 아니다. 2 KiB짜리 POST /report 하나가 CPU 500 ms와 큰 DB scan을 유발한다면 100 rps만으로도 초당 CPU 50초가 필요하다. 이 반례 때문에 전체 IP별 요청 수만 제한하지 않고, 비용이 큰 path를 별도 WAF rule과 app quota로 분리한다. 계층 경계는 패킷 크기만이 아니라 그 요청이 다음 계층에서 증폭시키는 비용까지 이어서 봐야 한다.
이 예시는 Defense in Depth가 도구를 많이 켜는 행위가 아니라 서로 다른 비용이 고갈되기 전에 각 계층이 자신이 볼 수 있는 신호로 부하를 줄이는 구조임을 보여준다. 숫자를 볼 때는 대역폭 -> connection state -> HTTP 요청 수 -> 요청당 app/DB 비용 순서로 병목을 번역한다.
SG(Security Group)는 EC2, ECS Task, RDS 같은 리소스의 ENI에 붙는 stateful 방화벽이다. “stateful”은 요청 방향이 허용되면 그 연결의 응답 방향은 별도 규칙 없이 돌아간다는 뜻이다.
NACL(Network ACL)은 Subnet 단위에 붙는 stateless 방화벽이다. “stateless”는 들어오는 방향과 나가는 방향을 각각 독립적으로 평가한다는 뜻이다. 그래서 HTTP inbound 443을 허용해도, 응답이 나갈 ephemeral port 범위를 outbound에서 막으면 통신이 깨질 수 있다.
| 비교 | SG | NACL |
|---|---|---|
| 적용 위치 | ENI/리소스 | Subnet |
| 상태성 | Stateful | Stateless |
| 규칙 성격 | Allow만 가능 | Allow와 Deny 가능 |
| 기본값 | 새 SG는 inbound 없음, outbound 허용 | 기본 NACL은 inbound/outbound 허용 |
| 주 용도 | 서비스 간 최소 권한 | 서브넷 단위 보조 차단 |
| 학습 우선순위 | 먼저 본다 | SG/route가 맞는데도 막히면 본다 |
API 서버가 RDS PostgreSQL에 연결한다고 하자.
ECS Task SG: sg-apiRDS SG: sg-rds
RDS SG inbound:- TCP 5432- Source: sg-api이 규칙이 있으면 sg-api가 붙은 ECS Task는 RDS의 5432 포트로 연결할 수 있다. RDS가 응답할 때는 SG connection tracking 덕분에 RDS outbound를 별도로 49152 같은 client ephemeral port까지 열지 않아도 된다.
반대로 NACL에서는 이 mental model이 통하지 않는다.
DB Subnet NACL inbound:- allow TCP 5432 from app subnet
DB Subnet NACL outbound:- deny all이 경우 요청은 DB Subnet으로 들어오지만 응답이 나가지 못한다. 클라이언트에서는 connection timeout처럼 보일 수 있다. “SG는 맞는데 왜 안 되지?”라는 상황에서 NACL outbound를 봐야 하는 이유다.
실무에서는 10.0.11.0/24 같은 IP 대역보다 다른 SG ID를 source로 쓰는 편이 안전하다.
RDS Security Group inbound:- Port: 5432- Source: sg-ecs-task
ECS Task Security Group outbound:- Port: 5432- Destination: sg-rds이 패턴은 세 가지를 얻는다.
SG가 기본 방어선이다. 대부분의 서비스 간 접근 제어는 SG로 충분하다. NACL을 먼저 복잡하게 만들면 정상 응답의 ephemeral port를 막거나, 운영자가 어느 규칙이 실제 차단 지점인지 추적하기 어려워진다.
NACL을 검토하는 조건은 더 좁다.
| 조건 | 판단 |
|---|---|
| 특정 외부 CIDR을 서브넷 전체에서 즉시 차단해야 한다 | NACL deny가 SG보다 빠르게 넓은 범위에 먹힌다 |
| 규정상 Subnet 경계의 명시적 deny가 필요하다 | SG와 별도 방어층으로 둔다 |
| SG와 Route Table이 맞는데 Flow Logs가 REJECT를 보인다 | NACL inbound/outbound를 같이 본다 |
| 단순 서비스 간 통신을 제한하려는 목적이다 | SG-as-source가 먼저다 |
| 증상 | 의미 | 먼저 볼 곳 |
|---|---|---|
| RDS 연결이 timeout으로 끝난다 | 패킷이 거부되거나 경로가 없다 | RDS SG inbound, DB Subnet route, NACL |
| 같은 VPC 안인데도 연결되지 않는다 | VPC 내부는 자동 신뢰 경계가 아니다 | 수신 SG의 source SG 규칙 |
| Flow Logs에 REJECT가 반복된다 | 패킷은 ENI/Subnet까지 왔고 정책에서 막혔다 | SG, NACL |
| Flow Logs 레코드가 없다 | 패킷 미도달 또는 로그 수집 공백일 수 있다 | 수집 범위·지연·log-status, DNS, route |
| 규칙 변경 직후 기존 연결이 끊긴다 | connection tracking 상태나 untracked flow 영향일 수 있다 | SG 변경 이력, idle timeout |
WAF(Web Application Firewall)는 HTTP 요청의 의미를 검사한다. SG와 NACL이 client -> 443까지 본다면, WAF는 POST /login, header, query string, body, cookie, 요청 빈도 같은 L7 정보를 본다.
WAF를 붙일 수 있는 대표 위치는 CloudFront, ALB, API Gateway다. 원칙은 “원본 서버에 닿기 전, 가장 바깥의 지원 서비스 경계에서 해석된 HTTP 요청을 검사한다”다. HTTPS라면 그 서비스가 TLS를 처리한 뒤 Web ACL에 논리적 요청을 전달한다.
flowchart TD User["인터넷 사용자"] --> CF["CloudFront"] User --> ALB["ALB"] User --> API["API Gateway"] CF --> Origin["Origin"] ALB --> Target["Target Group"] API --> App["Application"] WAF1["WAF 적용 가능"] -.-> CF WAF2["WAF 적용 가능"] -.-> ALB WAF3["WAF 적용 가능"] -.-> API
세 경로는 대안이다. WAF는 CloudFront, ALB, API Gateway 같은 지원 경계에 연결하며, 임의의 backend process에 직접 붙는 도구가 아니다.
WAF의 단위는 위에서 아래로 읽는다.
| 단위 | 의미 | 예 |
|---|---|---|
| Web ACL | 리소스에 연결되는 최상위 정책 묶음 | prod-api-web-acl |
| Rule Group | 여러 규칙을 묶은 단위 | AWSManagedRulesCommonRuleSet |
| Rule | priority와 action을 가진 평가 단위 | BlockBadIpSet, RateLimitLogin |
| Statement | 실제 매칭 조건 | IPSet, URI match, SQLi match, rate-based |
중요한 점은 priority다. AWS WAF는 낮은 숫자의 priority부터 평가한다. Allow와 Block은 terminating action이라 매칭되면 뒤 규칙을 더 보지 않는다. Count는 non-terminating action이라 매칭 수를 남기고 다음 규칙으로 계속 진행한다.
Priority 0: 임시 허용 IP set -> AllowPriority 10: /login rate-based rule -> BlockPriority 20: AWSManagedRulesCommonRuleSet -> Block 또는 CountDefault action: Allow위 순서에서 priority 0의 허용 규칙이 너무 넓으면 관리형 규칙이 검사할 기회가 사라진다. 그래서 예외 규칙은 기간, 사유, 범위를 작게 잡아야 한다.
AWS Managed Rules는 OWASP 계열의 흔한 웹 공격, 알려진 악성 입력, SQL database 패턴, IP reputation 같은 탐지 규칙을 제공한다. 직접 모든 공격 패턴을 작성하지 않아도 시작할 수 있다는 장점이 있다.
하지만 관리형 규칙은 정상 요청도 차단할 수 있다. 이때 필요한 절차가 Count-mode rollout이다.
| 정상 트래픽 | 오탐 가능 규칙 | 왜 생기는가 |
|---|---|---|
| 긴 JSON body 또는 파일 업로드 | size restriction 계열 | body 크기 제한과 충돌 |
| WYSIWYG 에디터 HTML 저장 | XSS 계열 | <script>나 이벤트 속성처럼 보이는 문자열 |
| CI/CD 시스템의 URL 포함 config | RFI/LFI 계열 | 외부 URL 필드가 원격 파일 포함처럼 보임 |
| 사내 VPN 또는 공유 NAT 출구 | anonymous/reputation 계열 | 출구 IP 평판이 실제 사용자와 다를 수 있음 |
검색할 때는 SizeRestrictions_Body, CrossSiteScripting_BODY, GenericRFI_BODY 같은 구체 rule 이름이 단서가 된다. 이름을 외우는 것이 목적은 아니고, sampled requests에서 어떤 rule이 종료 action을 냈는지 찾기 위한 검색 키워드로 쓰면 된다.
Count 모드는 “차단하지 않고 매칭만 기록”한다. 신규 Web ACL이나 새 managed rule group은 staging에서 먼저 확인하고, production에서는 Count로 최소 한 배포 주기 또는 1~2주 정도 관찰한 뒤 Block으로 전환한다. AWS 공식 문서도 production traffic에 적용하기 전에 테스트와 튜닝, Count mode 검증을 권장한다.
Count -> Block의 핵심은 시간을 기다리는 것이 아니라 분류 오차를 실제 트래픽으로 측정한 뒤 차단 범위를 좁히는 것이다. 다음은 학습용 가상 사례다.
하루 전체 요청: 2,000,000건새 managed rule 매칭: 12,000건(전체의 0.6%)그중 정상 editor 저장 요청: 11,680건실제 공격으로 확인한 요청: 300건아직 분류하지 못한 요청: 20건12,000건은 전체 요청의 0.6%지만, 공격으로 확인된 요청은 그중 300건(2.5%)뿐이다. 이 상태에서 즉시 Block하면 공격으로 확인되지 않은 97.5%, 즉 정상 11,680건과 미분류 20건도 함께 막힌다. 따라서 “매칭 수가 많다”는 사실만으로 차단 근거가 되지 않는다. editor path와 예상 body 형식을 좁은 예외로 분리한 뒤 남은 매칭이 320건이고, 그중 300건이 공격·20건이 미분류라면 그때 Block 전환, 알람, rollback 조건을 함께 검토할 수 있다.
따라서 전환 기준은 관찰 기간 경과 하나가 아니다. 주요 사용자 흐름의 오탐이 허용 범위 안인지, 예외가 path·IP·signature처럼 좁은 조건인지, BlockedRequests 급증 시 되돌릴 신호가 있는지를 같이 본다. Count는 소극적인 미적용 상태가 아니라 정상과 공격의 경계를 보정하는 배포 단계다.
HTTP 호출 실패가 모두 같은 원인은 아니다. 403이 보인다고 무조건 애플리케이션 인가 문제도 아니고, 브라우저 콘솔에 CORS가 보인다고 항상 서버 CORS 설정만 문제인 것도 아니다.
| 증상 | 가능성이 높은 원인 | 확인 신호 |
|---|---|---|
| 응답 status가 403이고 WAF header 또는 WAF log에 Block이 있다 | WAF rule match | WAF sampled requests, terminatingRuleId |
| 브라우저가 응답을 읽지 못하고 CORS policy 메시지를 낸다 | CORS preflight 또는 response header 문제 | OPTIONS 응답, Access-Control-Allow-* |
| 요청이 timeout이고 HTTP 응답 자체가 없다 | SG, NACL, route, DNS 문제 | Flow Logs 유무, REJECT, Reachability Analyzer |
| ALB가 502/504를 준다 | target health, backend port, TLS/backend connection 문제 | Target Group health, SG, app logs |
이 표의 목적은 클라이언트 오류 메시지를 모으는 것이 아니라 L7 차단과 L3/L4 차단은 관측 신호가 다르다는 점을 잡는 것이다.
AWS WAF rate-based rule은 aggregation key별 요청 수가 설정한 limit 근처를 넘으면 action을 적용한다. 평가 window는 1분, 2분, 5분, 10분 중 고르고, 5분이 기본값이다. AWS 공식 문서가 안내하는 최소 limit 값은 바뀔 수 있으므로, 실제 설정 전에는 rate-based rule 문서를 다시 확인한다.
하지만 WAF rate limiting은 정밀한 초당 제한기가 아니다. AWS 문서는 설정값 근처에서 동작하지만 정확한 limit match를 보장하지 않는다고 설명한다. 변경 전파와 평가 지연 때문에 너무 높은 rate가 몇 초에서 수 분 동안 지나갈 수도 있다.
따라서 설계 기준은 다음처럼 잡는다.
| 대상 | 시작점 | 주의점 |
|---|---|---|
| 전체 API blanket | 평시 P99 IP별 요청량의 3~5배 | 기업 NAT 환경에서 정상 사용자가 묶일 수 있다 |
| 로그인/회원가입 | 전체 API보다 낮게 | IP 단독보다 IP + 계정 식별자를 같이 보라 |
| 비싼 검색/리포트 API | path scope-down으로 별도 rule | 정상 batch 작업과 충돌할 수 있다 |
| webhook endpoint | partner IP, signature 검증과 함께 | IP가 자주 바뀌는 SaaS는 예외 관리가 어렵다 |
작은 worked example을 보자.
평시 /login 요청:- P99: IP당 18 requests / 5 min- 기업 고객 NAT 피크: IP당 60 requests / 5 min
위험:- limit을 30으로 잡으면 기업 NAT 사용자가 차단될 수 있다.
시작 설계:- blanket: 500 requests / 5 min / IP- /login: 100 requests / 5 min / IP- 애플리케이션 내부: 계정 ID 기준 실패 횟수 제한WAF는 edge에서 대량 요청을 줄이는 장치이고, 계정 잠금이나 로그인 실패 정책은 애플리케이션 보안과 함께 설계해야 한다.
요금은 변할 수 있으므로 실제 견적은 항상 공식 pricing을 확인한다. 아래 표는 공식 pricing page의 공개 단가를 바탕으로 계산 방법을 익히기 위한 학습용 기준점이다.
가정:
| 구분 | 100만 req/월 | 1억 req/월 | 10억 req/월 |
|---|---|---|---|
| Web ACL | $5.00 | $5.00 | $5.00 |
| rules / managed rule groups 10개 | $10.00 | $10.00 | $10.00 |
| request 처리 | $0.60 | $60.00 | $600.00 |
| WAF 단독 소계 | $15.60 | $75.00 | $615.00 |
| Shield Advanced 월 구독 기준점 | $3,000.00 | $3,000.00 | $3,000.00 |
이 표가 주는 감각은 두 가지다.
마지막 행을 WAF 단독 소계에 더해 견적을 만들면 안 된다. 현재 Shield Advanced 구독은 Shield로 보호되는 WAF 리소스에 대해 payer ID당 월 최대 500억 요청, 기본 1,500 WCU와 기본 body inspection 범위의 Web ACL·rule·기본 request 요금을 포함한다. 500억 초과 요청, Bot/Fraud Control, CAPTCHA, 추가 body inspection, 1,500 WCU 초과, 보호하지 않은 리소스는 별도 과금될 수 있고 data transfer out 사용료와 1년 약정도 남는다. 학습 단계에서는 “WAF 단독은 요청 기반, Shield Advanced는 큰 구독비와 포함 조건이 있는 별도 가격 모델”이라는 차이를 먼저 잡고, 견적 시점에는 공식 pricing을 다시 확인한다.
비용 표는 “비싸다/싸다”를 말하려는 것이 아니라 어떤 요소가 비용을 움직이는지 보여준다.
예를 들어 월 1억 요청의 외부 API가 있다고 하자.
WAF 단독:- Web ACL: $5- rule/rule group 10개: $10- request 처리: $60- 대략 $75/월
추가 기능:- Bot Control, Fraud Control, CAPTCHA/Challenge는 별도 과금 가능- body inspection 크기와 WCU 초과도 비용을 바꿀 수 있음이 서비스가 단순 B2B admin API라면 WAF managed rules와 rate-based rule만으로 충분할 수 있다. 반대로 회원가입, 로그인, 공개 검색, scraping 대상 페이지가 많다면 Bot/Fraud Control 같은 추가 기능의 비용과 효과를 따로 검토한다.
반대로 Shield Advanced는 “월 1억 요청이니 켜자”가 아니다. 월 $3,000은 request 1억 건의 WAF 기본 비용보다 훨씬 크다. 이 비용을 정당화하는 근거는 트래픽 양 자체보다 DDoS 중단 손실, 24/7 대응 체계, 비용 보호, 고객 SLA다.
작은 판단 표로 정리하면 다음과 같다.
| 서비스 상황 | WAF 비용 판단 | Shield Advanced 판단 |
|---|---|---|
| 사내 admin, VPN 뒤 | WAF보다 SG/VPN/IAM이 먼저 | 보통 불필요 |
| 공개 B2B API, 월 1억 요청 | WAF 기본 비용은 감당 가능한 수준 | SLA와 DDoS 이력 없으면 후순위 |
| B2C 결제/로그인, DDoS 이력 있음 | WAF + rate + bot/fraud 검토 | SRT와 cost protection 요구가 있으면 검토 |
| 대규모 이벤트 트래픽 | WAF request 비용과 WCU를 미리 계산 | 이벤트 중단 손실과 비교 |
비용의 핵심은 “보안 도구 비용”과 “사고 비용”을 같은 표에 놓는 것이다. 도구 비용만 보면 비싸 보이고, 사고 비용만 보면 과투자하기 쉽다.
WAF가 필요한지 묻는 가장 짧은 질문은 “HTTP 요청 내용을 원본 서버 전에 검사해야 하는가”다.
| 상황 | 판단 |
|---|---|
| 인터넷에 노출된 ALB/API Gateway/CloudFront가 있다 | WAF를 기본 검토한다 |
| private VPC 내부 서비스만 호출한다 | SG와 인증/인가가 먼저고 WAF는 보통 후순위다 |
| 로그인, 검색, 업로드처럼 비용이 큰 endpoint가 있다 | path별 rate rule과 managed rules를 검토한다 |
| HTML editor, webhook, 큰 JSON body가 많다 | Count mode와 예외 설계 없이 Block부터 켜지 않는다 |
| 인증/인가 우회, 재고보다 많이 주문 같은 비즈니스 로직 공격 | WAF만으로 막지 못한다. 애플리케이션 로직이 필요하다 |
DDoS(Distributed Denial of Service)는 여러 출처가 동시에 트래픽을 보내 정상 사용자가 서비스를 쓰지 못하게 만드는 공격이다. DDoS를 레이어별로 보면 방어 방식이 달라진다.
| 유형 | 공격 방식 | 방어 초점 |
|---|---|---|
| L3 volumetric | 대역폭을 채우는 패킷 flood | edge와 네트워크 용량, 자동 완화 |
| L4 protocol | SYN Flood처럼 연결 상태를 소모 | connection state 보호, SYN 방어 |
| L7 HTTP flood | 정상 HTTP처럼 보이는 많은 요청 | WAF, rate-based rule, cache, app cost 절감 |
AWS Shield Standard는 AWS 사용 시 자동 제공되며 추가 비용 없이 network/transport layer DDoS 이벤트에 대한 기본 보호를 제공한다. AWS Shield Advanced는 유료 구독이며 더 높은 수준의 보호, 가시성, 비용 보호, SRT(Shield Response Team) 접근 같은 운영 요구에 연결된다.
| 항목 | Shield Standard | Shield Advanced |
|---|---|---|
| 비용 | 추가 비용 없음 | 월 $3,000 + data transfer out 등, 1년 약정 |
| 적용 | AWS 사용 시 자동 | 보호할 eligible resource에 활성화 |
| L3/L4 DDoS | 기본 완화 | 향상된 완화와 가시성 |
| L7 DDoS | WAF Anti-DDoS AMR을 별도 유료로 선택 가능 | Anti-DDoS AMR 포함 |
| 운영 지원 | 일반 지원 경로 | SRT 접근은 Business/Enterprise Support 필요 |
| 비용 보호 | 없음 | 조건 충족 시 DDoS cost protection |
| 리포트/가시성 | 제한적 | 공격 이벤트 가시성과 리포트가 강함 |
Advanced를 “트래픽이 크면 무조건 켠다”로 이해하면 비용 판단이 흐려진다. 더 좋은 질문은 다음이다.
조건 1~3이 아니라면 Standard + CloudFront/ALB + WAF rate rule + autoscaling + observability를 먼저 성숙시키는 편이 더 현실적일 수 있다.
AWS의 L7 자동 완화 경로는 2026년 3월 26일을 기준으로 바뀌었다. 이날부터 AWS WAF의 **Anti-DDoS Managed Rule Group(Anti-DDoS AMR)**이 HTTP request flood 보호의 기본 해법이 되었고, 기존 Shield Advanced의 **Layer 7 Automatic Mitigation(L7AM)**을 대체한다.
| 구분 | 현재 기본: Anti-DDoS AMR | Legacy: Shield Advanced L7AM |
|---|---|---|
| 구성 단위 | WAF Web ACL에 AWSManagedRulesAntiDDoSRuleSet을 추가한다. | Shield Advanced가 Web ACL 안에 Shield 관리 rule group과 event별 custom rule을 관리한다. |
| 반응 모델 | 리소스별 traffic baseline과 suspicion label을 사용해 Challenge 또는 Block하며, AWS는 수 초 내 탐지·완화를 목표로 설명한다. | baseline 편차를 감지한 뒤 event별 mitigation rule을 평가·배포하므로 공격별 배포 시간이 달랐다. |
| 용량 | 현재 rule group은 50 WCU를 사용한다. | 기존 automatic mitigation rule group은 150 WCU를 사용한다. |
| 신규 선택 | AWS WAF 단독 유료 기능으로도 쓰거나 Shield Advanced 구독에 포함해 쓴다. | 기존 Shield Advanced 고객은 계속 쓸 수 있지만 AWS는 AMR 전환을 권장한다. 신규 고객이 legacy가 필요하면 AWS Support에 요청해야 한다. |
둘을 동시에 “Shield의 같은 기능”으로 부르면 rollout과 비용을 잘못 계산한다. Anti-DDoS AMR는 일반 managed rule처럼 Web ACL priority, Count/Challenge/Block, 지원하지 않는 client의 challenge 영향까지 운영해야 한다. 특히 SPA fetch, native mobile API, webhook처럼 JavaScript challenge를 완료하지 못할 수 있는 client는 production Block 전에 label과 정상 사용자 영향을 확인한다.
2026년 7월 기준 공개 가격의 학습용 기준점은 다음과 같다. WAF 단독 Anti-DDoS AMR은 rule group당 월 $20(시간 비례)와 기본 WAF request 요금에 더해 100만 요청당 $0.15가 제시되어 있다. Shield Advanced에는 AMR와 보호된 WAF 리소스의 payer ID당 월 최대 500억 요청이 포함되며, 초과분·비표준 WAF 기능·data transfer out은 별도 조건을 따른다. AMR가 DDoS로 탐지해 실제 완화 중인 요청은 Count mode가 아닐 때 해당 request 과금/500억 집계에서 제외된다. 이 단가와 포함 범위는 바뀔 수 있으므로 설계 문서에는 확인 날짜를 남기고 AWS WAF·Shield pricing을 다시 조회한다.
Standard가 “무료라서 약하다”는 뜻은 아니다. 다만 운영자가 기대하는 기능과 실제 제공 범위를 섞으면 실패한다.
| 기대 | Standard에서의 경계 | 보완 |
|---|---|---|
| HTTP flood를 자동으로 모두 막아준다 | L7 요청은 WAF와 app 방어가 필요하다 | WAF rate-based rule, CloudFront cache, app rate limit |
| 공격 상세 리포트를 항상 볼 수 있다 | Advanced보다 가시성이 제한적이다 | WAF logs, ALB metrics, CloudWatch, GuardDuty |
| 공격 비용 증가를 돌려받는다 | cost protection은 Advanced 영역이다 | Advanced 검토 또는 비용 알람 |
| 단일 ALB/백엔드 용량까지 알고 조절한다 | 서비스별 병목은 별도 설계가 필요하다 | autoscaling, queue, cache, fail-open/fail-closed 판단 |
역사적 DDoS 보고서를 읽을 때도 같은 관점이 필요하다. Cloudflare 2025 Q3 보고서처럼 Tbps/Bpps 규모 사례가 보여주는 것은 “언제나 Shield Advanced가 필요하다”가 아니라 “인간이 수동으로 반응하기 전에 edge에서 자동 완화되는 계층이 있어야 한다”는 점이다.
정확한 용량은 서비스마다 다르지만, 첫 설계에서는 다음 네 숫자를 손으로 써 본다.
평시:- 평균 800 rps- P99 2,000 rps- 로그인 path P99 80 rps- 백엔드가 error 없이 버티는 최대 8,000 rps
질문:- CloudFront cache hit가 빠지면 origin rps는 얼마까지 오르는가?- WAF blanket rule은 평시 P99의 몇 배에서 시작할 것인가?- backend autoscaling이 새 capacity를 붙이기 전까지 몇 분이 필요한가?- DB connection pool은 HTTP flood 때 먼저 고갈되지 않는가?이 계산은 Shield와 WAF만의 문제가 아니다. DDoS는 네트워크, edge cache, 로드밸런서, 애플리케이션 비용, DB headroom을 동시에 건드린다. 네트워크 보안 문서에서 app cost를 언급하는 이유가 여기에 있다.
두 서비스를 비교해 보자.
서비스 A:- 월 3천만 요청- 업무 시간에만 사용- 장애 시 내부 사용자 불편, 직접 매출 손실 낮음- 운영자가 업무 시간 대응 가능
서비스 B:- 월 3천만 요청- 공개 결제 API- 30분 장애가 매출과 고객 신뢰에 직접 손실- 야간/주말 트래픽도 큼- 과거 DDoS성 트래픽으로 data transfer 비용 급증 경험 있음두 서비스의 요청량은 같지만 판단은 다르다. 서비스 A는 WAF, SG, TLS, Flow Logs, 알람을 먼저 갖추면 충분할 수 있다. 서비스 B는 요청량이 같아도 Shield Advanced를 검토할 근거가 있다. Advanced의 가치는 “더 많은 요청을 처리한다”보다 “공격 중 가시성, 대응 지원, 비용 보호를 산다”에 가깝기 때문이다.
WAF와 Shield가 있어도 애플리케이션 방어가 사라지지 않는다.
| 공격/오남용 | edge 계층 | app 계층 |
|---|---|---|
| 동일 IP의 초고속 요청 | WAF rate-based rule | 사용자별 quota, 계정 잠금 |
| 분산된 낮은 속도 로그인 시도 | Bot/Fraud Control 일부 도움 | 계정별 실패 횟수, MFA, risk scoring |
| 비싼 report API 반복 호출 | path rate rule | job queue, cache, per-user limit |
| 정상 인증 후 비즈니스 로직 남용 | 대부분 모름 | 도메인 규칙, 권한, 감사 로그 |
이 표가 중요한 이유는 “네트워크 보안이 있으면 애플리케이션 보안이 약해져도 된다”는 반례를 막기 위해서다. 네트워크 보안은 비용이 큰 트래픽을 줄이고, 애플리케이션 보안은 의미 있는 권한과 상태 전이를 검증한다.
TLS(Transport Layer Security)는 클라이언트와 서버 사이의 전송 구간을 암호화하고, 서버가 제시한 인증서를 통해 “내가 접속한 서버가 기대한 서버인가”를 검증하게 해준다. ACM(AWS Certificate Manager)은 AWS에서 TLS 인증서를 발급, 연결, 갱신하는 관리 서비스다.
TLS에서 가장 중요한 설계 질문은 암호화가 어디에서 끝나는가다.
패턴 A: ALB에서 TLS Termination
Client --HTTPS--> ALB --HTTP--> ECS/EC2
패턴 B: End-to-End TLS
Client --HTTPS--> ALB --HTTPS--> ECS/EC2| 비교 | ALB TLS Termination | End-to-End TLS |
|---|---|---|
| 백엔드 부담 | 낮다 | 인증서/암호화 부담이 늘어난다 |
| 인증서 관리 | ALB/CloudFront 중심 | 백엔드까지 관리 필요 |
| VPC 내부 구간 | 평문일 수 있다 | 내부도 암호화 |
| 디버깅 | 상대적으로 쉽다 | 인증서 chain, SNI, trust store까지 본다 |
| 적합한 경우 | 일반적인 웹/API 서비스 | 규정 준수, 민감 데이터, zero trust 요구 |
일반적인 웹 서비스는 CloudFront나 ALB에서 TLS를 종료하고 내부는 SG와 private subnet으로 보호한다. 금융, 의료, 강한 내부 암호화 요구가 있는 환경에서는 백엔드까지 TLS를 유지한다. 이때는 “보안이 더 좋다”만이 아니라 인증서 배포, 갱신 실패, health check, service mesh, 로그 해석 비용까지 같이 본다.
ACM은 Amazon-issued SSL/TLS 인증서의 managed renewal을 제공한다. DNS validation을 쓰고 인증서가 ELB나 CloudFront 같은 AWS 서비스에 연결되어 있으면 자동 갱신 대상이 된다. 그러나 imported certificate, 이미 만료된 인증서, 일부 private CA 발급 흐름은 managed renewal 조건이 다르다.
실패 신호는 명확하다.
| 증상 | 의미 | 먼저 볼 곳 |
|---|---|---|
브라우저 NET::ERR_CERT_DATE_INVALID | 인증서 만료 또는 시스템 시간 문제 | ACM certificate status, renewal status |
| 특정 오래된 클라이언트만 TLS 실패 | chain, cipher, TLS version 호환 문제 | SSL Labs, ALB security policy |
| HTTP로 접근 가능하다 | 80 listener가 redirect가 아니라 forward일 수 있다 | ALB listener rule |
| HTTPS 페이지에서 HTTP API를 호출한다 | Mixed Content 차단 | API base URL, redirect, HSTS |
| ALB health check만 실패한다 | backend protocol/port/TLS mismatch | Target group protocol, SG, app listener |
HTTP 80을 HTTPS 443으로 redirect하는 것은 “HTTP로 들어온 요청을 HTTPS로 다시 보내는” 동작이다. HSTS(HTTP Strict Transport Security)는 브라우저가 앞으로 해당 도메인을 HTTPS로만 접근하도록 기억하게 하는 정책이다.
첫 도입 순서는 보통 다음과 같다.
HSTS를 너무 빨리 켜면 잘못된 인증서나 누락된 subdomain 때문에 사용자가 우회하기 어려운 장애를 겪을 수 있다. TLS는 “켜면 끝”이 아니라 rollout 순서가 있는 변경이다.
VPC Flow Logs는 VPC, Subnet, ENI 수준에서 IP traffic metadata를 기록한다. AWS 공식 문서는 Flow Logs가 network interface로 들어오고 나가는 IP traffic 정보를 capture하고, CloudWatch Logs, S3, Data Firehose로 publish할 수 있다고 설명한다.
핵심 필드는 처음에는 아래만 보면 충분하다.
| 필드 | 의미 |
|---|---|
srcaddr | 출발지 IP |
dstaddr | 목적지 IP |
srcport | 출발지 포트 |
dstport | 목적지 포트 |
protocol | TCP/UDP 등 |
action | ACCEPT 또는 REJECT |
log-status | 로그 수집 상태 |
예시를 보자.
ACCEPT:2 123456789012 eni-0abc 10.0.11.5 10.0.21.3 49152 5432 6 25 7500 ACCEPT OK
의미:- 10.0.11.5:49152 -> 10.0.21.3:5432 흐름이 관측됐다.- SG/NACL 기준으로 허용됐다.- 애플리케이션이 성공했다는 뜻은 아니다.REJECT:2 123456789012 eni-0abc 10.0.11.5 10.0.21.3 49152 5432 6 0 0 REJECT OK
의미:- 패킷은 관측 지점까지 왔다.- SG 또는 NACL에서 거부됐다.- HTTP body나 SQLi 패턴은 여기서 알 수 없다.Flow Logs가 보여주는 것은 네트워크 정책의 결과다. WAF Logs가 보여주는 것은 HTTP 요청이 어떤 WAF rule에 매칭됐는지다. 둘을 섞으면 안 된다.
| 질문 | 볼 로그 |
|---|---|
| 패킷이 ENI까지 왔는가 | VPC Flow Logs |
| SG/NACL이 막았는가 | VPC Flow Logs의 REJECT, Reachability Analyzer |
| 어떤 WAF rule이 403을 만들었는가 | WAF sampled requests, WAF full logs |
| ALB가 backend를 unhealthy로 보는가 | ALB target health, ALB access logs |
| Shield가 DDoS event를 감지했는가 | Shield Advanced event, CloudWatch metric |
ACCEPT가 성공을 뜻하지 않는다는 점은 꼭 기억한다.
Flow Logs: ACCEPTClient: timeout이 조합은 이상하지 않다. 네트워크 정책은 통과했지만 애플리케이션 포트가 닫혀 있거나, DB가 connection을 받지 못하거나, TLS handshake가 실패했을 수 있다.
반대로 레코드 부재만으로 패킷 미도달을 확정하지 않는다. Flow Logs가 대상 ENI를 포함하는지, 수집 지연이 있는지, log-status가 OK인지 먼저 확인한 뒤 route와 목적지를 본다. 실제로 패킷이 대상 ENI까지 오지 않았는데 SG만 넓히면 문제도 안 풀리고 보안만 약해진다.
Defense in Depth는 “한 방어선이 실패해도 다음 방어선이 피해를 줄인다”는 설계 원리다. 아래는 모든 packet의 물리적 통과 순서가 아니라 HTTPS 요청을 처리하는 논리적 서비스 평가 순서다. Shield의 edge DDoS 완화는 HTTP 내용 평가와 별도 계층이고, WAF는 지원 서비스가 TLS를 종료해 HTTP 요청을 해석할 수 있게 된 뒤 평가한다.
Internet -> Shield Standard / Advanced: edge DDoS 완화 -> CloudFront 또는 ALB HTTPS 서비스 경계 -> TLS/ACM 종료 -> 연결된 WAF Web ACL의 HTTP 요청 평가 -> Allow된 요청을 origin/target으로 전달 -> origin/target NACL과 Security Group -> Application auth/validation -> DB SG / IAM / encryption -> Flow Logs / WAF Logs / metrics각 계층은 같은 일을 반복하지 않는다.
| 계층 | 맡는 일 | 경계 |
|---|---|---|
| Shield | DDoS 완화 | 비즈니스 로직 공격을 모른다 |
| TLS | 전송 중 기밀성과 서버 신뢰 | 요청 자체가 안전한지는 모른다 |
| WAF | HTTP 패턴과 rate 차단 | 인증/인가 정합성을 보장하지 않는다 |
| NACL | 서브넷 단위 보조 deny | HTTP 내용을 모른다 |
| SG | 리소스 간 최소 권한 | 정상 포트 안의 악성 payload를 모른다 |
| Flow Logs/WAF Logs | 관측과 진단 | 예방 장치가 아니다 |
신규 외부 API를 배포할 때 최소 기준은 아래 정도다.
이 기준에서 하나라도 빠졌다고 즉시 장애가 나는 것은 아니다. 하지만 빠진 계층이 많을수록 공격과 운영 실수의 blast radius가 커진다.
아래 트리는 “어떤 제품을 켜야 하나”보다 “어느 질문에 답해야 하나”를 중심으로 읽는다.
Q1. HTTP 요청 내용, path, header, body, 요청 빈도를 원본 전에 검사해야 하는가? -> Yes: WAF -> No : Q2
Q2. 리소스 단위로 누가 어떤 포트를 호출할 수 있는지 제한해야 하는가? -> Yes: Security Group -> No : Q3
Q3. 서브넷 전체에서 특정 IP/CIDR을 명시적으로 차단해야 하는가? -> Yes: NACL -> No : SG와 route부터 단순하게 유지
Q4. DDoS로 인한 가용성, 비용, 지원 리스크가 큰가? -> 기본: Shield Standard + WAF + cache + autoscaling -> SLA/SRT/cost protection 필요: Shield Advanced 검토
Q5. 사용자가 보는 도메인이 HTTPS로만 안전하게 동작해야 하는가? -> ACM + TLS listener + HTTP redirect + 필요 시 HSTS
Q6. 패킷이 실제로 왔는지, 정책에서 막혔는지 확인해야 하는가? -> VPC Flow Logs, WAF Logs, ALB access logs| 비교 | 핵심 차이 |
|---|---|
| SG vs NACL | SG는 리소스 단위 stateful allow, NACL은 subnet 단위 stateless allow/deny |
| WAF vs Shield | WAF는 HTTP 내용을 검사하고, Shield는 DDoS 완화 중심이다 |
| WAF vs app validation | WAF는 공통 패턴과 rate를 줄이고, app은 도메인 규칙과 권한을 판단한다 |
| TLS termination vs end-to-end | termination은 운영이 단순하고, end-to-end는 내부 구간까지 암호화한다 |
| Flow Logs vs WAF Logs | Flow Logs는 IP/port/action, WAF Logs는 HTTP rule/action |
| 403 vs timeout | 403은 L7 응답이 온 것이고, timeout은 네트워크/target 미도달일 수 있다 |
실패를 볼 때는 제품 설정을 무작정 열기보다 어느 경계까지 요청이 도달했는가를 먼저 판단한다. 아래 표는 긴 복구 절차가 아니라 다음 가설을 고르는 좌표다.
| 관측 신호 | 이미 통과했거나 실패한 경계 | 다음 가설 |
|---|---|---|
| WAF log와 함께 403이 반환된다 | DNS와 TCP/TLS를 거쳐 L7 rule이 응답함 | terminating rule, scope-down, app auth 구분 |
| timeout이고 대상 ENI의 Flow Logs 레코드도 없다 | 미도달 또는 로그 수집 공백 가능성 | 수집 범위·지연·log-status, DNS, route |
| Flow Logs에 REJECT가 있다 | ENI/Subnet까지 왔지만 정책에서 거부됨 | SG source/port, NACL 양방향 규칙 |
| Flow Logs는 ACCEPT인데 502/504 또는 timeout이다 | SG/NACL 판단은 통과함 | target health, app listener, backend TLS, DB |
| 인증서·handshake 오류가 난다 | TLS 신뢰 경계에서 실패함 | ACM 상태, chain, SNI, security policy |
| Block 전환 직후 특정 path의 403이 급증한다 | 새 WAF 정책이 사용자 흐름을 바꿈 | false positive와 좁은 예외, rollback 조건 |
| request/packet 급증과 origin 자원 고갈이 겹친다 | DDoS 완화 후에도 하위 병목이 남음 | cache hit, WAF rate, app CPU, DB pool, 비용 보호 |
403, timeout, REJECT, ACCEPT는 원인이 아니라 마지막으로 관측된 경계의 결과다. 예를 들어 ACCEPT + timeout에서 SG를 더 여는 것은 이미 통과한 계층을 약하게 만들 뿐이다. 반대로 WAF 403을 애플리케이션 인가 실패로 단정하면 정상 body를 막은 managed rule을 놓칠 수 있다.
따라서 최소 진단 질문은 세 가지면 충분하다.
임시 예외가 필요해도 전체 managed rule group 비활성화나 0.0.0.0/0 개방을 기본 복구로 삼지 않는다. path, source, port, 만료 시간처럼 작은 범위를 정하고, 상세 도입·진단 절차와 명령은 선택 부록에서 필요할 때만 펼쳐 본다.
ACCEPT는 앱 성공이 아니고, WAF 403은 SG timeout과 다르다.처음 읽을 때는 펼치지 않아도 된다. 본문의 원리와 선택 기준을 실제 변경·관찰에 옮길 때만 필요한 절차와 명령을 이곳에 한 번씩 모았다.
WAF는 가장 바깥의 지원 가능한 HTTP 경계를 고른 뒤 Count -> 예외 보정 -> Block 순서로 적용한다.
| 단계 | 목적 | 완료 기준 |
|---|---|---|
| 1. 리소스 선택 | CloudFront, ALB, API Gateway 중 어디에 붙일지 결정 | 원본에 가까운 곳이 아니라 가장 바깥 HTTP 경계가 선택됨 |
| 2. Count mode | 정상 트래픽 오탐 확인 | 주요 path의 sampled requests와 사용자 영향 확인 |
| 3. 예외 설계 | 정상 요청을 좁게 허용 | priority, scope-down, owner, 만료일 명시 |
| 4. Block 전환 | 실제 차단 시작 | BlockedRequests 알람과 rollback 조건 존재 |
| 5. 운영 감사 | 임시 허용의 영구화를 방지 | 오래된 예외의 사유·owner·만료일을 주기적으로 검토 |
Priority 0 - emergency-block-ipset -> BlockPriority 10 - temporary-partner-allow -> Allow, expires_at requiredPriority 20 - login-rate-limit -> Block or CAPTCHAPriority 30 - AWSManagedRulesCommonRuleSet -> Count during rollout, Block after tuningPriority 40 - AWSManagedRulesSQLiRuleSet -> Count during rollout, Block after tuningDefault - AllowSG 변경은 현재 경로를 source SG -> destination SG:port로 먼저 쓴다. IP CIDR보다 SG-as-source를 우선하고, inbound를 먼저 좁힌다. outbound 축소는 AWS endpoint와 외부 API 의존성을 확인한 뒤 진행하며, 변경 후에는 Flow Logs REJECT, target health, app error를 함께 본다.
TLS 변경은 다음 순서를 따른다.
ISSUED인지 확인하고 DNS validation record의 owner를 정한다.Flow Logs는 VPC 전체 또는 문제 Subnet/ENI에서 시작한다. 처음에는 REJECT를 중심으로 srcaddr, dstaddr, dstport, action을 묶고, WAF·ALB 로그와 시간대를 맞춘다. 장기 보관량과 조회 빈도에 따라 CloudWatch Logs와 S3를 나눈다.
aws ec2 describe-security-groups \ --filters Name=ip-permission.cidr,Values='0.0.0.0/0' \ --query 'SecurityGroups[].{GroupId: GroupId, GroupName: GroupName, Ports: IpPermissions[].FromPort}' \ --output table0.0.0.0/0 자체가 항상 오류는 아니다. public ALB의 80/443은 정상일 수 있지만 bastion 없는 22/3389, RDS, Redis 포트의 전체 공개는 줄여야 한다. IPv6를 쓰면 ::/0도 별도로 확인한다.
aws wafv2 get-sampled-requests \ --web-acl-arn arn:aws:wafv2:ap-northeast-2:123456789:regional/webacl/prod-api-waf/id \ --rule-metric-name AWSManagedRulesCommonRuleSet \ --scope REGIONAL \ --time-window StartTime=<start_epoch>,EndTime=<end_epoch> \ --max-items 50<start_epoch>와 <end_epoch>에는 최근 1시간처럼 짧은 Unix epoch 구간을 넣는다. 정상 path가 반복 매칭되면 바로 Block하지 않고, partner나 editor endpoint처럼 범위를 설명할 수 있을 때 scope-down을 검토한다.
fields @timestamp, srcAddr, dstAddr, dstPort, action| filter action = "REJECT"| stats count(*) by srcAddr, dstAddr, dstPort| sort count desc| limit 20같은 srcAddr -> dstPort 반복은 port scan일 수도, 잘못된 client 설정일 수도 있다. 내부 service IP가 RDS port에서 REJECT되면 SG-as-source와 NACL을 본다. 레코드가 없으면 Flow Logs 수집 범위·지연·log-status를 확인한 뒤 route, DNS, target IP를 본다.
aws acm describe-certificate \ --certificate-arn arn:aws:acm:ap-northeast-2:123456789:certificate/example \ --query 'Certificate.{Status: Status, RenewalStatus: RenewalSummary.RenewalStatus, NotAfter: NotAfter}'ISSUED와 SUCCESS는 정상 신호다. DNS validation record가 삭제되면 자동 갱신이 실패할 수 있고, imported certificate는 managed renewal 조건이 다르다.
SG/NACL 문제는 아래 순서로 범위를 줄인다.
1. source와 destination을 SG ID와 port로 쓴다.2. destination SG inbound가 source SG를 허용하는지 본다.3. source subnet route table에 목적지 경로가 있는지 본다.4. Flow Logs에 REJECT가 있는지 본다.5. NACL inbound/outbound를 같이 본다.6. ACCEPT인데 실패하면 app port, target health, TLS, DB 상태를 본다.WAF false positive는 전체 rule group을 끄지 않고 매칭 rule과 사용자 영향을 기록한 뒤, 해당 rule을 Count로 되돌리거나 좁은 예외를 둔다. 임시 예외가 영구 보안 약화로 남지 않게 다음 정보를 변경 기록이나 IaC review에 붙인다.
date:web_acl:resource:rule_id:action:affected_path:sampled_request_id:normal_user_impact:temporary_change:expires_at:owner:follow_up:DDoS 보고서의 Tbps, Bpps, rps를 곧바로 Shield Advanced 도입 근거로 쓰지 않는다. 본문의 29.7 Tbps 사례처럼 큰 숫자를 만나면 다음 질문으로 바꾼다.
AWS가 아닌 CDN/WAF도 제품명 대신 같은 경계 질문으로 비교한다.
| 질문 | 확인할 것 |
|---|---|
| L3/L4 DDoS는 누가 자동 완화하는가 | 기본 포함인지, 유료 plan인지 |
| L7 HTTP 검사는 어디에서 하는가 | CDN edge, regional LB, API gateway |
| managed rules는 Count/Log mode가 있는가 | false positive rollout 가능성 |
| rate limit aggregation key는 무엇인가 | IP, forwarded IP, session, user id |
| 인증서 갱신은 자동인가 | DNS validation, imported cert, ACME |
| 로그는 어디로 나가는가 | S3, CloudWatch, SIEM, sampling 여부 |
가격은 변하므로 본문의 비용 표를 갱신할 때는 Web ACL, rule/rule group, request, Anti-DDoS AMR standalone/Shield 포함 조건, 500억 요청 경계, WCU 초과, body inspection, Bot/Fraud/CAPTCHA/Challenge, Shield Advanced 구독·약정·data transfer out을 공식 pricing에서 다시 확인한다. 가격표의 목적은 견적을 고정하는 것이 아니라 설계 판단의 규모감을 제공하는 것이다.