CertNote/ 출퇴근 학습 노트
로드맵
KOEN
CLF-C02 · FoundationalCloud Practitioner - Foundational
DVA-C02 · AssociateDeveloper - Associate
SAA-C03 · AssociateSolutions Architect - Associate
SOA-C02 · AssociateCloudOps Engineer - Associate
SAP-C02 · ProfessionalSolutions Architect - Professional
DOP-C02 · ProfessionalDevOps Engineer - Professional
SCS-C03 · SpecialtySecurity - Specialty
  • Week 1
    • 1.공동 책임 모델과 SCS-C03 6개 도메인: 보안 엔지니어의 큰 그림
    • 2.IAM 핵심: 사용자·그룹·역할·정책과 정책 평가의 기본 흐름
    • 3.IAM 정책 심화: Identity vs Resource 정책, 조건 키, 최소 권한 설계
    • 4.STS와 임시 자격 증명: AssumeRole, 페더레이션, 역할 체이닝, Confused Deputy 방지
    • 5.Week 1 종합: IAM과 자격 증명을 시나리오로 통합 복습
  • Week 2
  • Week 3
    • 1.VPC 보안 설계: 네트워크가 첫 번째 방어선이다
    • 2.보안 그룹 vs 네트워크 ACL: 상태 저장과 비저장의 본질
    • 3.VPC Flow Logs와 트래픽 가시성: 로그로 침해를 읽는다
    • 4.프라이빗 연결: VPC 엔드포인트와 데이터 유출 봉쇄
    • 5.Week 3 종합: 네트워크 격리와 트래픽 통제를 하나로
  • Week 4
  • Week 5
  • Week 6
  • Week 7
  • Week 8
  • Week 9
  • Week 10
  • Week 11
  • Week 12
MLA-C01 · AssociateMachine Learning Engineer - Associate
AIF-C01 · FoundationalAI Practitioner - Foundational
DEA-C01 · AssociateData Engineer - Associate
MLS-C01 · SpecialtyMachine Learning - Specialty
합격 후기

© CertNote · 주간랩스

  • 소개
  • 수정 기록
  • 문의
  • 이용약관
  • 개인정보처리방침
← SCS-C03/Week 3/Day 2

기준: SCS-C03 시험 가이드·오류 제보

SCS-C03· AssociateWeek 3 · Day 2읽기 약 19분

Day 2 - 보안 그룹 vs 네트워크 ACL: 상태 저장과 비저장의 본질

VPC 안에 두 개의 방화벽 계층이 있다. 보안 그룹(Security Group)과 네트워크 ACL(NACL)이다. 두 개념을 정확히 구분하지 못하면 시험에서도, 실무 트러블슈팅에서도 반복해서 막힌다. "왜 SG는 다 열었는데 응답이 안 오지?", "NACL에서 인바운드만 열었는데 왜 통신이 안 되지?" 같은 질문은 거의 모두 상태 저장(stateful) vs 비저장(stateless)의 차이를 놓쳐서 생긴다.

오늘은 이 둘을 본질부터 정리한다. 평가 순서, 상태 추적의 차이, 그리고 실무에서 가장 흔한 트러블슈팅 시나리오까지 본다. SCS-C03 도메인 3에서 거의 매 회차 출제되는 핵심 주제다.

두 방화벽의 위치: 어디에 붙는가

인터넷
  │
[ NACL ]  ← 서브넷 경계에 붙음 (서브넷 단위)
  │
[ 보안 그룹 ]  ← ENI(인스턴스)에 붙음 (리소스 단위)
  │
[ EC2 인스턴스 ]
  • NACL: 서브넷 경계에서 동작. 서브넷을 드나드는 모든 트래픽을 검사한다.
  • 보안 그룹: ENI(Elastic Network Interface), 즉 인스턴스 단위로 동작. 리소스에 가장 가까운 방화벽.
항목보안 그룹 (SG)네트워크 ACL (NACL)
적용 대상ENI / 인스턴스서브넷
상태Stateful (상태 저장)Stateless (비저장)
규칙Allow만 가능Allow + Deny 가능
평가 방식모든 규칙 종합 평가규칙 번호 순서대로, 첫 매치에서 종료
기본 동작인바운드 차단 / 아웃바운드 허용(기본) 전체 허용 / (커스텀) 전체 차단

이 이중 구조는 네트워크 보안의 계층화(layering) 원칙이다. NACL은 서브넷 전체에 적용되는 광역 통제(coarse-grained), SG는 리소스별 정밀 통제(fine-grained)다. 전통적인 데이터센터에서 라우터 ACL(서브넷 경계)과 호스트 방화벽(서버별)을 나눈 것과 정확히 같은 사상이다. NACL로 서브넷 전체에 "이 포트는 절대 금지" 같은 강제 규칙을 걸고, SG로 각 리소스의 정밀한 허용을 관리한다.

Stateful vs Stateless: 가장 중요한 차이

이 한 가지가 NACL 문제의 바탕이다.

보안 그룹(Stateful): 인바운드를 허용하면, 그에 대한 응답(아웃바운드)은 규칙 없이 자동 허용된다. 연결 상태를 추적하기 때문이다. 반대도 마찬가지 — 아웃바운드로 나간 요청의 응답 인바운드는 자동 허용된다.

NACL(Stateless): 상태를 추적하지 않는다. 인바운드 요청을 허용했어도, 응답이 나가는 아웃바운드를 별도로 명시 허용해야 한다. 응답은 보통 임시 포트(ephemeral port, 1024~65535)로 나가므로, NACL 아웃바운드에 이 범위를 열어야 한다.

# 시나리오: 웹 서버(443)에 인터넷 접속

[보안 그룹]
  인바운드: TCP 443 from 0.0.0.0/0   ← 이것만 있으면 됨
  (응답 아웃바운드는 자동 허용 - stateful)

[NACL]  ← 둘 다 명시해야 함 (stateless)
  인바운드: 규칙100  TCP 443  from 0.0.0.0/0  ALLOW
  아웃바운드: 규칙100  TCP 1024-65535  to 0.0.0.0/0  ALLOW  ← 임시 포트 필수!

글로 읽으면 헷갈리므로, 같은 왕복 통신을 두 방화벽이 각각 어떻게 보는지 그림으로 겹쳐 놓는 편이 빠르다. 아래가 이 글 전체에서 가장 중요한 그림이다.

[ 같은 왕복(request/response)을 SG와 NACL이 보는 방식 ]

  클라이언트 203.0.113.10:51000        서버 10.0.1.20:443
        │                                      │
   ①요청 │  src 203.0.113.10:51000              │
        │  dst 10.0.1.20:443                   │
        ├──▶ [NACL 인바운드] 규칙에 443 ALLOW 필요 ─┐
        │                                        │
        │                          [SG 인바운드] 443 ALLOW 필요
        │                                        ▼
        │                                     서버 처리
   ②응답 │  src 10.0.1.20:443                   │
        │  dst 203.0.113.10:51000              │
        │                          [SG 아웃바운드] ← 평가하지 않음
        │                            (①을 기억하고 있으므로 자동 허용)
        │                                        │
        ◀── [NACL 아웃바운드] ──────────────────────┘
             1024-65535 ALLOW가 없으면 여기서 죽는다
             (NACL은 ①을 기억하지 못한다)

  ── 포트가 뒤바뀐 것에 주목: 응답의 목적지 포트는 443이 아니라
     클라이언트가 골랐던 51000이다. NACL 아웃바운드에 443만 열어 두면
     정확히 이 지점에서 응답이 막힌다.

이 그림이 말하는 핵심은 딱 하나다. SG는 ①을 기억하고 NACL은 기억하지 못한다. 상태 저장/비저장이라는 말은 결국 "①을 기억하는가"의 다른 표현이며, 기억하지 못하기 때문에 NACL은 응답을 새로운 트래픽으로 취급해 처음부터 다시 평가한다. 그리고 그 새로운 트래픽의 목적지 포트는 서비스 포트가 아니라 클라이언트가 임의로 고른 임시 포트다.

같은 이유로 아웃바운드에서 시작한 통신도 대칭적으로 뒤집힌다. 인스턴스가 외부 API(443)를 호출하면, 요청은 src 10.0.1.20:47000 → dst 1.2.3.4:443이고 응답은 src 1.2.3.4:443 → dst 10.0.1.20:47000이다. 이때 NACL 인바운드에 1024-65535가 열려 있어야 응답이 들어온다. "인바운드는 아무것도 열지 않았는데 왜 열어야 하지?"라는 의문이 여기서 생기는데, 답은 같다 — NACL에게 그 응답은 인바운드로 새로 들어오는 트래픽일 뿐이다.

⚠️ 함정: 대표적인 함정이 바로 이 임시 포트(ephemeral ports)다. "NACL 인바운드에 443을 열었는데 웹 응답이 안 온다"는 시나리오의 답은 거의 항상 "아웃바운드 임시 포트(1024-65535)가 막혀 있다"이다. SG였다면 stateful이라 이 문제가 없다. 운영체제마다 임시 포트 범위가 다르다는 점도 알아두자(Linux 32768-60999, Windows Server 2008+ 49152-65535, NAT Gateway 1024-65535). 그래서 보통 안전하게 1024-65535를 다 연다.

Stateful 추적의 한 가지 미묘한 예외가 있다. 보안 그룹에서 인바운드 규칙을 허용했다가 연결이 살아있는 도중에 규칙을 삭제하면 어떻게 될까? TCP의 경우 이미 수립된(established) 연결은 보안 그룹이 계속 추적하므로 유지될 수 있다. 반면 NACL은 stateless라 규칙을 바꾸면 즉시 다음 패킷부터 적용된다. 그래서 "긴급 차단(emergency block)"이 필요하면 SG보다 NACL의 Deny 규칙이 더 즉각적이다. 단, 추적 연결 정리(connection tracking)는 idle 타임아웃이나 특정 조건에서 풀린다.

연결 추적이 실제로 하는 일과, 하지 않는 일

"stateful"이라는 단어 뒤에는 연결 추적 테이블(connection tracking table) 이라는 실체가 있다. 보안 그룹이 트래픽을 허용할 때, 그 흐름의 5-tuple(출발지 IP·포트, 목적지 IP·포트, 프로토콜)이 항목으로 기록된다. 이후 그 흐름에 속하는 패킷은 규칙을 다시 평가하지 않고 테이블 조회만으로 통과한다. 이 사실에서 실무적으로 중요한 결과 셋이 나온다.

첫째, 규칙을 지워도 진행 중인 연결은 바로 끊기지 않는다. 사고 대응에서 "SG를 닫았는데 공격자 세션이 살아 있다"는 상황이 이래서 생긴다. 확실히 끊으려면 NACL Deny를 얹거나(다음 패킷부터 즉시 적용), 인스턴스를 격리 SG로 교체하고 세션을 강제 종료해야 한다.

둘째, 연결 추적 항목은 무한하지 않다. 항목 수가 인스턴스 유형별 한도에 가까워지면 새 연결이 실패하기 시작하는데, 이 실패는 애플리케이션 로그에는 "연결 타임아웃"으로만 보여 원인 파악이 어렵다. 그래서 대규모 연결을 다루는 워크로드에서는 어떤 규칙이 추적을 유발하는지 알아 둘 가치가 있다. 규칙이 인바운드·아웃바운드 모두에서 0.0.0.0/0으로 완전히 열려 있고 프로토콜·포트도 전체 허용인 흐름은 추적이 생략(untracked)될 수 있다. 즉 적당히 열린 규칙이 완전히 열린 규칙보다 추적 부담이 크다는 다소 역설적인 성질이 있다. 시험보다는 실무 지식이지만, "SG를 좁혔더니 연결 수가 많은 서버에서 문제가 생겼다"는 사례의 배경이 이것이다.

셋째, UDP와 ICMP도 추적된다. 연결이라는 개념이 없는 프로토콜인데도 SG는 흐름 단위로 상태를 만들어 응답을 허용한다. 그래서 "UDP는 stateless라 SG에서도 양방향을 열어야 한다"는 흔한 오해는 틀렸다. UDP 기반 서비스(DNS 53, NTP 123, QUIC 443)를 SG로 열 때는 인바운드 한 방향만 쓰면 된다. 반면 NACL에서는 UDP도 예외 없이 양방향을 명시해야 한다.

[ 긴급 차단이 필요할 때, 무엇이 언제 먹는가 ]

  이미 수립된 악성 세션                    새로 들어오는 연결
        │                                      │
  SG 규칙 삭제 ──────▶ 즉시 끊기지 않음        ──▶ 즉시 차단됨
  NACL Deny 추가 ────▶ 다음 패킷부터 차단      ──▶ 즉시 차단됨
  인스턴스 격리 SG 교체 ▶ 추적 초기화되며 끊김   ──▶ 즉시 차단됨
  인스턴스 분리·정지 ──▶ 확실히 끊김           ──▶ 확실히 차단됨

  → 사고 대응 순서: NACL Deny(광역·즉시) → 격리 SG(대상 한정) → 스냅샷·포렌식
     "차단"과 "증거 보존"의 순서를 뒤집지 않는 것이 요령이다.
     인스턴스를 먼저 종료하면 메모리 증거가 사라진다.

NACL의 평가 순서: 규칙 번호가 운명을 가른다

NACL은 SG와 결정적으로 다르다. 규칙 번호가 낮은 것부터 순서대로 평가하고, 첫 번째 매치에서 평가를 종료한다(first-match wins).

인바운드 NACL 규칙:
  규칙 90:   DENY  TCP 22 from 203.0.113.50/32   ← 특정 IP 차단
  규칙 100:  ALLOW TCP 22 from 0.0.0.0/0         ← SSH 허용
  규칙 *:    DENY  ALL                            ← 암묵적 마지막(변경 불가)

이 경우 203.0.113.50은 규칙 90에서 먼저 DENY를 만나 차단된다. 규칙 100의 ALLOW까지 가지 않는다. 순서가 거꾸로면(100이 먼저면) 차단이 동작하지 않는다.

이 "첫 매치 종료" 방식은 전통적인 라우터/방화벽 ACL과 동일하다(Cisco IOS ACL이 대표적). 그래서 규칙 번호를 보통 100 단위로 띄워 작성한다(100, 200, 300...). 나중에 사이에 규칙을 끼워 넣을 공간을 확보하기 위함이다. SG는 이런 순서가 없고 모든 규칙을 OR로 종합 평가하므로(어느 하나라도 허용하면 허용) 설계 사고가 완전히 다르다.

🎯 시나리오: "특정 악성 IP 한 개를 서브넷 전체에서 차단하고 싶다. SG로 가능한가?" — 불가능하다. SG는 Deny 규칙이 없다(Allow만 존재). 특정 IP를 차단하려면 NACL의 Deny 규칙을 낮은 번호로 추가해야 한다. 이것이 "SG로는 차단 불가, NACL로만 명시적 Deny 가능"이라는 핵심 차이다. 대규모 IP 차단이 필요하면 NACL 규칙 수 제한(기본 20, 최대 40)에 걸리므로 AWS Network Firewall이나 WAF를 쓴다.

규칙 번호를 설계한다는 것

NACL 규칙 번호는 단순한 라벨이 아니라 평가 순서 그 자체이므로, 번호 배치가 정책이 된다. 실무에서 굳어진 관례는 대역을 용도별로 나눠 두는 것이다.

번호 대역용도이유
1~99긴급·명시적 Deny(악성 IP 차단 등)어떤 Allow보다 먼저 평가되어야 한다
100~199정상 인바운드 Allow서비스 포트
200~299응답용 임시 포트 Allow잊기 쉬우므로 대역을 따로 둔다
300 이상예외·임시 규칙만료일을 태그로 남긴다
*암묵적 Deny(변경 불가)어떤 규칙에도 매치되지 않으면 여기

번호를 100 단위로 띄우는 이유는 사이에 끼워 넣을 자리를 남기기 위함이다. 그런데 더 중요한 규율은 "Deny를 나중에 추가할 때 반드시 기존 Allow보다 낮은 번호로 넣는다" 는 것이다. 급하게 차단하면서 편한 번호(예: 400)를 쓰면 이미 100번의 Allow에서 통과해 버려 아무 일도 일어나지 않고, 그 사실이 로그에도 잘 드러나지 않는다. 시험에서 "Deny 규칙을 추가했는데 여전히 통과한다"는 시나리오의 답은 언제나 규칙 번호다.

# 현재 NACL 규칙을 번호 순으로 확인 (인바운드/아웃바운드 함께)
aws ec2 describe-network-acls \
  --filters "Name=association.subnet-id,Values=subnet-0app1234" \
  --query 'NetworkAcls[].Entries[].{No:RuleNumber,Egress:Egress,Proto:Protocol,
             Cidr:CidrBlock,Ports:PortRange,Action:RuleAction}' \
  --output table
 
# 악성 IP를 가장 낮은 번호로 차단 (인바운드)
aws ec2 create-network-acl-entry \
  --network-acl-id acl-0abc1234 --rule-number 10 \
  --protocol -1 --cidr-block 203.0.113.50/32 \
  --rule-action deny --ingress
 
# 응답이 나갈 임시 포트를 아웃바운드에 열어 둔다 (잊으면 서브넷 전체가 먹통)
aws ec2 create-network-acl-entry \
  --network-acl-id acl-0abc1234 --rule-number 200 \
  --protocol tcp --port-range From=1024,To=65535 \
  --cidr-block 0.0.0.0/0 --rule-action allow --egress

⚠️ 함정: NACL 규칙에서 --protocol -1(모든 프로토콜)을 쓰면 포트 범위 지정이 무시된다. "모든 프로토콜의 443만"이라는 규칙은 성립하지 않는다 — 포트라는 개념 자체가 TCP/UDP에만 있기 때문이다. 차단 규칙을 급하게 넣을 때 -1을 쓰는 것은 의도적으로 전부 막겠다는 뜻이며, 그 IP에서 오는 정상 트래픽도 함께 사라진다는 점을 알고 써야 한다. 또 하나 — NACL 규칙 수에는 할당량이 있어(기본값 기준 방향당 20개, 상향 시 40개까지) 대규모 IP 차단 목록에는 맞지 않는다. 수백 개 IP를 막아야 하면 NACL이 아니라 AWS Network Firewall이나 WAF의 IP set이 답이다.

보안 그룹을 설계하는 도구들

SG는 "규칙을 나열하는 곳"이 아니라 관계를 표현하는 곳으로 쓸 때 강해진다. 세 가지 도구를 손에 쥐고 있어야 한다.

① SG 참조 — 소스에 IP 대신 다른 SG를 쓴다. sg-data의 인바운드 5432를 sg-app으로 열어 두면, App 인스턴스가 몇 대로 늘어나든 IP가 어떻게 바뀌든 규칙은 그대로다. 이것은 편의 기능이 아니라 최소 권한을 시간에 대해 유지하는 장치다. CIDR로 쓰면 오늘은 정확하지만 내일은 필연적으로 헐거워진다.

② 관리형 접두사 목록(prefix list) — 자주 쓰는 CIDR 묶음에 이름을 붙여 규칙에서 참조한다. 사내 대역이 늘어나면 목록만 고치면 되고, 그 목록을 참조하는 모든 SG·라우팅 규칙이 함께 갱신된다. AWS도 서비스별 접두사 목록(예: S3, DynamoDB, CloudFront)을 제공하며, 라우팅 테이블에서 Gateway Endpoint 경로가 pl-xxxx로 표시되는 것이 바로 이것이다.

③ 자기 참조(self-referencing) 규칙 — SG가 자기 자신을 소스로 참조하면, 그 SG에 속한 멤버끼리만 통신이 열린다. 클러스터 내부 통신(예: 노드 간 gossip 포트)을 표현하는 표준 방식이다.

# SG 참조로 규칙 추가 — CIDR을 쓰지 않는다
aws ec2 authorize-security-group-ingress \
  --group-id sg-data \
  --ip-permissions 'IpProtocol=tcp,FromPort=5432,ToPort=5432,
      UserIdGroupPairs=[{GroupId=sg-app,Description="app tier only"}]'
 
# 접두사 목록 참조
aws ec2 authorize-security-group-ingress \
  --group-id sg-bastion \
  --ip-permissions 'IpProtocol=tcp,FromPort=22,ToPort=22,
      PrefixListIds=[{PrefixListId=pl-corp-offices,Description="corp CIDR list"}]'
 
# 감사: 0.0.0.0/0 인바운드를 가진 SG만 뽑기
aws ec2 describe-security-groups \
  --filters "Name=ip-permission.cidr,Values=0.0.0.0/0" \
  --query 'SecurityGroups[].{Id:GroupId,Name:GroupName,VpcId:VpcId,
             Open:IpPermissions[?IpRanges[?CidrIp==`0.0.0.0/0`]].[IpProtocol,FromPort,ToPort]}' \
  --output json

SG 참조가 동작하는 방식은 "그 SG에 속한 인스턴스들의 IP 목록을 자동으로 관리해 주는 것"에 가깝다. 즉 최종적으로는 IP 기반 판정이지만, 그 목록의 유지 책임이 사람에게서 플랫폼으로 넘어간다. 보안 통제에서 반복적으로 확인되는 원리가 여기서도 보인다 — 사람이 손으로 동기화해야 하는 목록은 반드시 낡는다. 방화벽 규칙에 적힌 IP, 허용 목록에 남은 퇴사자 계정, 만료일 없는 예외 규칙이 모두 같은 실패 유형이다. 그래서 성숙한 설계는 "정확한 목록을 만드는 것"이 아니라 "목록이 스스로 따라오게 만드는 것"을 목표로 삼는다.

SG에도 할당량이 있다. ENI 하나에 붙일 수 있는 SG 개수, SG 하나에 넣을 수 있는 규칙 수, 그리고 이 둘의 곱에 대한 상한이 정해져 있다. 규칙을 잘게 쪼개 SG를 많이 붙이는 설계는 언젠가 이 상한에 부딪힌다. 대신 역할별로 SG를 나누고(웹/앱/DB/공통관리) 참조로 엮는 구조가 규칙 수를 선형으로 유지한다. 그리고 규칙마다 Description을 반드시 채우는 것이 실무 규율이다 — 설명 없는 규칙은 아무도 지우지 못해 영원히 남고, 그것이 권한 축적(permission creep)의 네트워크 버전이 된다.

평가 흐름: 패킷이 거치는 순서

인바운드 패킷이 EC2에 도달하기까지:

1. NACL 인바운드 (서브넷 진입)     → DENY면 여기서 끝
2. 보안 그룹 인바운드 (ENI 도착)    → 허용 안 되면 끝
3. EC2 처리 → 응답 생성
4. 보안 그룹 아웃바운드 (stateful → 자동 허용)
5. NACL 아웃바운드 (stateless → 명시 필요, 보통 임시 포트)

한 가지 자주 묻는 질문 — "두 인스턴스가 같은 서브넷 안에서 통신하면 NACL이 적용되나?" 답은 아니오다. NACL은 서브넷 경계를 넘는 트래픽만 검사한다. 같은 서브넷 내부 통신은 NACL을 거치지 않고 SG만 적용된다. 반대로 SG는 같은 서브넷이든 다른 서브넷이든 ENI에 도달하는 모든 트래픽에 적용된다. 그래서 "같은 서브넷 내 격리"가 필요하면 SG로만 가능하다.

SG는 소스로 다른 SG를 참조할 수 있다(예: "ALB의 SG에서 오는 트래픽만 허용"). 이는 IP가 아니라 논리적 그룹 참조라 인스턴스가 늘어나도 규칙이 유지되는 큰 장점이다. NACL은 IP/CIDR만 참조 가능하고 SG 참조 불가. 시험에서 "Auto Scaling으로 IP가 계속 바뀌는 백엔드에 ALB만 접근 허용"이라면 답은 NACL이 아니라 SG 간 참조다.

실무 트러블슈팅 매트릭스

증상의심 1순위확인 방법
연결 자체가 안 됨(timeout)라우팅 / SG 인바운드 / NACLReachability Analyzer
요청은 가는데 응답이 없음NACL 아웃바운드 임시 포트NACL 아웃바운드 1024-65535
특정 IP만 막고 싶은데 안 됨SG로 시도(불가)NACL Deny 규칙 사용
간헐적 차단NACL 규칙 순서(first-match)규칙 번호 정렬 확인
같은 서브넷 내 격리 안 됨NACL로 시도(미적용)SG로 격리
# Reachability Analyzer로 경로 분석 (트러블슈팅의 정석)
aws ec2 create-network-insights-path \
  --source i-source --destination i-dest \
  --protocol tcp --destination-port 443
 
aws ec2 start-network-insights-analysis \
  --network-insights-path-id nip-xxxx
# 결과에 어느 컴포넌트(SG/NACL/Route)에서 막혔는지 정확히 표시됨

좁혀 들어가는 순서를 고정해 둔다

트러블슈팅에서 시간을 잡아먹는 것은 지식 부족이 아니라 순서 없음이다. 생각나는 대로 SG를 열어 보고, 안 되면 NACL을 열어 보고, 그래도 안 되면 라우팅을 보는 식으로 하면 원인을 찾기 전에 환경이 먼저 헐거워진다. 순서를 고정해 두면 각 단계에서 "여기까지는 정상"이라는 판정이 쌓인다.

[ "연결이 안 된다"를 좁히는 고정 순서 ]

  0. 증상부터 분류한다
       timeout(응답 자체 없음)  → 연결 계층 문제 (1~4로)
       AccessDenied / 4xx      → 정책 계층 문제 (5~6으로, 4일차 주제)
       RST(즉시 거부)           → 목적지에 리스닝 프로세스 없음 (6번)

  1. 라우팅   : 출발지 서브넷에 목적지로 가는 경로가 있는가
                 → 없으면 여기서 끝. blackhole 여부도 확인
  2. NACL     : 양쪽 서브넷의 인바운드 + 아웃바운드(임시 포트!)
                 → 비대칭 실패를 만들 수 있는 유일한 계층
  3. SG(목적지): 인바운드에 서비스 포트가 열려 있는가
  4. SG(출발지): 아웃바운드가 좁혀져 있지 않은가 (기본은 전체 허용)
  5. 정책     : 엔드포인트 정책 → 리소스 정책 → IAM (4일차)
  6. 호스트   : OS 방화벽, 프로세스 listen 여부, 헬스체크

  → 1~4는 Reachability Analyzer가 한 번에 판정해 준다.
     그래도 순서를 외워 두는 이유는, 도구가 없는 시험장에서
     보기 네 개 중 하나를 골라야 하기 때문이다.

증상으로 계층을 먼저 가르는 0번이 실전에서 가장 값지다. timeout이면 네트워크, AccessDenied면 정책이라는 한 문장이 많은 문제를 즉시 정리한다. 정책이 거부하면 요청은 목적지까지 도달했다는 뜻이고, 도달했다는 것은 라우팅·NACL·SG가 모두 통과했다는 증거다. 반대로 timeout은 패킷이 어딘가에서 조용히 버려졌다는 뜻이며, 조용히 버리는 것은 정책이 아니라 네트워크 통제의 성질이다.

🎯 시나리오: "App 서브넷의 EC2에서 Data 서브넷의 RDS로 붙지 않는다. Reachability Analyzer는 경로가 정상이라고 나오고, SG도 sg-app 참조로 5432가 열려 있다. 무엇이 남았나?" — 1~4가 초록불이라면 남은 것은 5번과 6번이다. RDS라면 정책 계층이 관여할 여지가 적으므로 6번, 즉 DB 인스턴스가 실제로 그 포트에서 서비스 중인지, 파라미터 그룹이나 DB 사용자 인증이 거부하는 것은 아닌지를 본다. 증상이 timeout이 아니라 "인증 실패"라면 애초에 네트워크는 정상이었던 것이고, 이 경우 SG를 더 여는 것은 아무 효과 없이 노출만 늘린다. 증상이 바뀌지 않는 조치는 원인이 아니라는 신호로 읽는 습관이 트러블슈팅 속도를 좌우한다.

실무에서 새벽에 가장 흔하게 호출되는 장애가 "NACL 잘못 건드림"이다. 누군가 보안 강화를 한다며 NACL 아웃바운드를 좁히면, stateful이 아닌 NACL 특성상 모든 응답 트래픽이 막혀 서브넷 전체가 먹통이 된다. 그래서 많은 조직이 NACL은 거의 건드리지 않고 SG로만 정밀 통제하는 전략을 쓴다. NACL은 "절대 안 되는 것"(예: 특정 악성 IP, DB 포트의 인터넷 노출)만 막는 보조 장치로 남긴다.

정리

정리하면 세 가지다. 첫째, SG는 stateful이라 응답이 자동 허용되고 NACL은 stateless라 응답(임시 포트)을 명시 허용해야 한다 — 이 구분이 시험에서 답을 가른다. 상태 저장이라는 말은 결국 "요청을 기억하는가"이며, 기억하지 못하는 NACL에게 응답은 목적지 포트가 뒤바뀐 새 트래픽일 뿐이다. 둘째, NACL만 Deny가 가능하고 규칙 번호 순서로 first-match 평가하며, SG는 Allow만 종합 평가한다. 그래서 나중에 넣는 Deny는 반드시 기존 Allow보다 낮은 번호여야 한다. 셋째, SG는 다른 SG를 참조할 수 있고 같은 서브넷 내부도 통제하지만, NACL은 서브넷 경계만 보고 IP/CIDR만 참조한다.

여기에 오늘 덧붙인 실무 층위가 셋 더 있다. 연결 추적은 규칙을 지워도 진행 중인 세션을 바로 끊지 않으므로, 긴급 차단은 NACL Deny나 격리 SG 교체로 하되 증거 보존을 차단보다 뒤에 두지 않는다. UDP·ICMP도 SG에서는 추적되므로 한 방향만 열면 되고, NACL에서만 양방향이 필요하다. 그리고 SG는 규칙을 나열하는 곳이 아니라 관계를 표현하는 곳이다 — SG 참조, 접두사 목록, 자기 참조 세 도구로 쓰면 인스턴스가 늘어도 규칙이 늘지 않는다. 사람이 손으로 동기화하는 IP 목록은 반드시 낡는다는 원리가 여기서도 그대로 적용된다.

트러블슈팅에서는 순서를 고정한다. 증상으로 계층을 먼저 가르고(timeout이면 네트워크, AccessDenied면 정책), 라우팅 → NACL → SG(목적지) → SG(출발지) → 정책 → 호스트 순으로 좁힌다. 그리고 하나만 기억한다면 이것이다 — 비대칭 실패(요청은 가는데 응답이 안 온다)는 SG가 만들 수 없고 NACL만 만든다.

실무 전략은 명확하다 — 정밀 통제는 SG로, 절대 금지 규칙(특정 IP 차단, 광역 deny)만 NACL로. 다음 글에서는 이 트래픽이 실제로 어떻게 흘렀는지 VPC Flow Logs로 들여다보며, 오늘 배운 SG/NACL 진단을 로그 위에서 확인하는 법을 본다.

📝 연습 문제

선택지를 클릭하면 정답·해설이 펼쳐집니다.

문제 1

한 엔지니어가 웹 서버 서브넷의 NACL 인바운드에 TCP 443을 0.0.0.0/0으로 허용했다. 그런데 외부에서 HTTPS 응답을 받지 못한다. 가장 가능성 높은 원인은?

문제 2

단일 악성 IP 주소 하나를 서브넷 전체에서 명시적으로 차단해야 한다. 올바른 접근은?

문제 3

오토스케일링으로 IP가 수시로 바뀌는 백엔드 인스턴스 그룹에 대해, 특정 ALB에서 오는 트래픽만 허용하고 싶다. 가장 적절한 방법은?

문제 4

같은 서브넷 안에 있는 두 인스턴스 A, B 사이의 통신을 격리(차단)하려고 한다. 어떤 통제가 효과적인가?

문제 5

보안 그룹과 네트워크 ACL의 평가 방식에 대한 설명으로 옳은 것은?

문제 6

보안 사고 대응 중 진행 중인 악성 연결을 즉시 끊어야 한다. 가장 즉각적으로 차단되는 통제는?

이전VPC 보안 설계: 네트워크가 첫 번째 방어선이다Week 3 · Day 1다음 VPC Flow Logs와 트래픽 가시성: 로그로 침해를 읽는다Week 3 · Day 3

참고 공식 자료

  • SCS-C03 공식 시험 안내(새 탭에서 열림)
  • Elastic Load Balancing 공식 문서(새 탭에서 열림)
  • Amazon VPC 공식 문서(새 탭에서 열림)

이 페이지

  • 두 방화벽의 위치: 어디에 붙는가
  • Stateful vs Stateless: 가장 중요한 차이
  • 연결 추적이 실제로 하는 일과, 하지 않는 일
  • NACL의 평가 순서: 규칙 번호가 운명을 가른다
  • 규칙 번호를 설계한다는 것
  • 보안 그룹을 설계하는 도구들
  • 평가 흐름: 패킷이 거치는 순서
  • 실무 트러블슈팅 매트릭스
  • 좁혀 들어가는 순서를 고정해 둔다
  • 정리
  • 연습 문제