VPC 안에서 트래픽이 인스턴스에 도달하기 전에 두 단계의 방어선을 통과한다 — Subnet 경계의 NACL과 인스턴스 경계의 Security Group. 같은 “방화벽 규칙"처럼 보이지만 둘은 적용 단위, 평가 방식, 상태성이 모두 다르다. 차이를 이해하지 못한 채 운영하면 “outbound는 허용했는데 응답이 막힌다” 같은 함정에 자주 빠진다.

Security Group

Security Group(SG)은 인스턴스 또는 ENI(Elastic Network Interface) 단위에 부착되는 규칙 묶음이다. 한 인스턴스에 여러 SG를 부착할 수 있고, 그 경우 규칙은 합집합으로 적용된다.

가장 큰 특징은 stateful이라는 점이다. 한 번 허용된 연결의 return traffic은 별도 규칙 없이도 자동으로 허용된다. inbound로 들어온 요청에 대한 응답을 outbound 규칙에 별도로 명시할 필요가 없다는 뜻이다.

SG는 allow-only다. deny 규칙 자체가 없고, 명시적으로 허용한 트래픽만 통과한다. 기본값은 outbound 전체 허용, inbound 전체 차단. 새 SG를 만들면 우선 외부와의 모든 inbound가 막혀 있고, 필요한 포트와 출발지를 하나씩 추가해 가는 모델이다.

SG의 source/destination에는 IP CIDR 외에도 다른 SG의 ID를 지정할 수 있다. 같은 VPC 안의 자원끼리 “이 SG가 부착된 자원만 허용” 같은 의미적 규칙을 직접 표현할 수 있어, 인스턴스 IP가 바뀌어도 규칙이 깨지지 않는다.

NACL

NACL(Network ACL)은 Subnet 단위에 부착된다. 한 Subnet에는 하나의 NACL이 붙고, 그 Subnet에 속한 모든 자원이 같은 NACL의 영향을 받는다.

NACL은 stateless다. inbound와 outbound 규칙이 완전히 분리돼 있어, 한쪽에서 허용된 트래픽의 응답이라도 반대쪽에서 명시적으로 허용되지 않으면 차단된다. SG에서는 자동으로 허용되던 return traffic이 NACL에서는 별도 규칙을 요구한다.

NACL은 allow와 deny 모두 표현할 수 있다. 규칙에는 번호가 매겨지고, 번호 오름차순으로 평가하다가 첫 매칭에서 결정이 난다. 명시적으로 차단해야 할 트래픽이 있을 때 NACL이 필요한 이유다.

기본값은 두 가지로 갈린다. VPC 생성 시 자동으로 만들어지는 default NACL은 모두 허용, 사용자가 직접 만든 custom NACL은 모두 차단으로 시작한다.

평가 순서

외부에서 들어오는 트래픽과 내부에서 나가는 트래픽이 두 계층을 거치는 순서는 다음과 같다.

flowchart LR
    Ext["외부"] -->|"inbound"| NACL_in["NACL
(Subnet inbound)"] NACL_in --> SG_in["SG
(Instance inbound)"] SG_in --> VM["VM"] VM --> SG_out["SG
(Instance outbound)"] SG_out --> NACL_out["NACL
(Subnet outbound)"] NACL_out -->|"outbound"| Ext2["외부"]

외부에서 시작된 요청은 Subnet 경계의 NACL inbound를 먼저 통과한 뒤, 인스턴스 경계의 SG inbound에서 다시 평가된다. 응답은 반대 순서 — SG outbound를 거쳐 NACL outbound를 통과한다. 두 계층을 모두 통과해야 트래픽이 끝까지 도달한다.

SG는 stateful이라 인스턴스 입장에서 return traffic이 자동 허용되지만, NACL은 stateless라 응답 트래픽도 별도 규칙으로 명시해야 한다. 흔한 트러블슈팅 함정이 여기서 나온다.

함정 시나리오

outbound는 허용했는데 응답이 막힌다

NACL의 outbound는 허용했지만, inbound 규칙에서 응답 트래픽의 destination port를 허용하지 않은 경우다. 응답은 일반적으로 ephemeral port(1024-65535) 범위로 돌아오므로, NACL inbound 규칙에 그 범위가 포함돼 있지 않으면 응답이 차단된다.

SG만 쓰는 환경에서는 stateful이라 이 문제가 보이지 않다가, NACL을 추가로 도입한 순간부터 새로 등장한다. NACL에서 양방향 ephemeral port 범위를 함께 허용해야 한다.

SG 규칙이 적용되지 않는 것처럼 보인다

규칙을 추가했는데도 트래픽이 막혀 있다면, 같은 인스턴스에 부착된 다른 SG가 충돌하는 게 아니라 NACL에서 차단되고 있을 가능성이 크다. SG는 인스턴스 단위라 하나의 SG가 차단해도 다른 SG가 허용하면 통과되는 데 비해, NACL은 Subnet 전체에 걸리는 단일 규칙이다.

default NACL과 custom NACL의 기본값 차이

default NACL은 모두 허용으로 시작해 명시적으로 차단할 트래픽만 추가하는 형태고, custom NACL은 모두 차단으로 시작해 허용할 트래픽을 추가하는 형태다. 이 차이를 모르고 custom NACL로 교체하면 모든 트래픽이 차단되는 사고가 난다.

비교 표

두 메커니즘을 한 표에 놓으면 차이가 분명해진다.

항목Security GroupNACL
적용 단위인스턴스 / ENISubnet
상태성stateful (응답 자동 허용)stateless (응답도 별도 규칙)
규칙 종류allow onlyallow + deny
평가 방식모든 규칙 합집합 평가번호 순서, 첫 매칭으로 결정
기본값inbound 차단, outbound 허용default는 모두 허용 / custom은 모두 차단
Source 표현CIDR + 다른 SG의 ID 가능CIDR만

벤더 명칭 매핑

개념AWSGCPAzureAlibaba Cloud
인스턴스 단위 statefulSecurity GroupFirewall Rule (대상 태그)NSG (NIC 적용)Security Group
Subnet 단위 statelessNetwork ACL(해당 직접 모델 없음)NSG (Subnet 적용)Network ACL

GCP는 SG/NACL을 별도로 구분하지 않고 Firewall Rules라는 통합 모델로 다룬다. 인스턴스 태그·네트워크 태그·서비스 계정 등으로 적용 대상을 결정하는 방식이라, AWS·Azure·Alibaba와는 사고 모형이 한 단계 다르다.

Azure의 NSG는 같은 리소스가 NIC 또는 Subnet 어느 쪽에든 적용될 수 있어, AWS의 SG/NACL을 한 리소스로 합친 구조에 가깝다.

시리즈 마무리

VPC fundamentals 시리즈가 4편으로 마무리된다. 네 요소가 합쳐져 VPC라는 한 추상이 만들어진다.

  • 격리 (1편) — IP 공간, Subnet, Tenancy로 사설 네트워크 경계 시뮬레이션
  • 라우팅 (2편) — Route Table이 결정하는 트래픽 경로, IGW/NAT 두 종류의 출입구
  • 연결성 (3편) — VPC Peering, Transit Gateway, VPN, PrivateLink 네 메커니즘으로 외부 연결
  • 보안 (4편) — Security Group과 NACL이 만드는 두 계층의 방어선

벤더 명칭은 다르지만 추상은 거의 같다. 한 벤더의 멘탈 모델을 익혀두면 다른 벤더로 옮겨갈 때 방향을 잃지 않는다.