클라우드

보안 그룹에선 되는데 네트워크 ACL에선 응답이 막히는 이유

보안 그룹은 허용한 연결의 응답을 기억해서 통과시키지만, 네트워크 ACL은 패킷을 하나하나 따로 판단한다.
그래서 네트워크 ACL에서는 응답이 돌아가는 임시 포트까지 규칙으로 열어야 한다.

이 글의 목차보안 그룹은 인스턴스에, 네트워크 ACL은 서브넷에7
  1. 보안 그룹은 인스턴스에, 네트워크 ACL은 서브넷에
  2. 응답은 어느 포트로 돌아가는가
  3. 보안 그룹은 연결을 기억한다
  4. 네트워크 ACL은 패킷을 하나하나 따로 본다
  5. 네트워크 ACL에는 거부 규칙과 번호가 있다
  6. 보안 그룹 규칙에는 다른 보안 그룹을 적을 수 있다
  7. 네트워크 ACL은 언제 손대는가

VPC 콘솔의 왼쪽 메뉴에서 ‘보안’ 아래를 보면 ‘네트워크 ACL’⁠과 ‘보안 그룹’⁠이 나란히 있다.
둘 다 인바운드 규칙과 아웃바운드 규칙을 적는 화면이라, 처음 보면 같은 기능이 두 번 들어 있는 것 같다.

그래서 보안 그룹을 다루던 감각으로 네트워크 ACL을 새로 만들고, 인바운드에 443번을 열고 아웃바운드에도 443번만 열어 두는 경우가 있다.
그러면 웹 서버가 요청은 받는데 응답을 돌려보내지 못한다.

규칙만 보면 빠진 것이 없어 보인다.
차이는 두 장치가 연결을 다루는 방식에 있다.
각각 어디에 붙는지부터 정리한다.

보안 그룹은 인스턴스에, 네트워크 ACL은 서브넷에

VPC는 AWS 안에 만드는 나만의 사설 네트워크다.
그 주소 범위를 다시 잘게 나눈 구획을 서브넷이라고 하고, EC2 인스턴스는 언제나 서브넷 하나 안에서 실행된다.

보안 그룹은 인스턴스에 붙어서 그 인스턴스로 드나드는 트래픽을 거르고, 네트워크 ACL⁠은 서브넷 경계에서 그 서브넷으로 드나드는 트래픽을 거른다.
AWS 문서의 비교표도 앞의 것을 인스턴스 수준, 뒤의 것을 서브넷 수준으로 적어 둔다.

인터넷에서 온 요청은 서브넷의 네트워크 ACL을 먼저 지나고, 그다음 인스턴스의 보안 그룹을 지난다.
두 곳 중 한 곳에서만 막혀도 인스턴스에 닿지 못한다.

헷갈리기 쉬운 것이 하나 있다.
네트워크 ACL은 트래픽이 서브넷에 들어오고 나갈 때만 평가된다.
같은 서브넷 안의 인스턴스끼리 주고받는 트래픽에는 적용되지 않는다.

네트워크 ACL과 보안 그룹이 거르는 자리 인터넷에서 온 요청은 서브넷 경계의 네트워크 ACL을 지난 뒤 인스턴스의 보안 그룹을 지나고, 같은 서브넷 안의 트래픽은 보안 그룹만 지난다. 개념 도해 네트워크 ACL과 보안 그룹이 거르는 자리 트래픽이 지나는 경계 인터넷 ① 네트워크 ACL 서브넷 경계 ② 보안 그룹 인스턴스 경계 인스턴스 A 보안 그룹 인스턴스 경계 인스턴스 B 같은 서브넷 출발지별로 평가하는 경계 ① 네트워크 ACL ② 보안 그룹 인터넷 → 인스턴스 A 서브넷 경계를 넘는 트래픽 평가 평가 인스턴스 B → 인스턴스 A 같은 서브넷 안의 트래픽 평가하지 않음 평가 인터넷에서 온 요청은 서브넷 경계의 네트워크 ACL을 지난 뒤 인스턴스의 보안 그룹을 지나고, 같은 서브넷 안의 트래픽은 보안 그룹만 지난다. SOSHIN · DEV NOTES
인스턴스 B에서 A로 가는 트래픽은 서브넷 경계를 넘지 않으니 네트워크 ACL이 평가하지 않는다.

VPC를 만들면 기본 네트워크 ACL이 함께 생기는데, 이 기본 ACL은 모든 트래픽을 들이고 내보내도록 설정돼 있다.
네트워크 ACL을 건드린 적이 없다면 실제로 트래픽을 거르던 것은 보안 그룹뿐이다.

반대로 직접 새로 만든 네트워크 ACL은 처음에 모든 인바운드와 아웃바운드를 막는다.
규칙을 하나씩 더해야 트래픽이 흐르기 시작한다.

응답은 어느 포트로 돌아가는가

연결 하나에는 양쪽 끝의 IP 주소와 포트가 함께 적힌다.
브라우저가 웹 서버에 접속하면 목적지는 서버의 443번이고, 출발지는 사용자 컴퓨터의 IP와 운영체제가 그때 고른 번호다.

이렇게 잠깐 쓰고 버리는 출발지 번호를 임시 포트(ephemeral port)⁠라고 한다.
포트라는 개념 자체는 포트와 방화벽 글에서 기초부터 다룬다.

서버의 응답은 이 연결을 거꾸로 탄다.
출발지가 서버의 443번, 목적지가 사용자 컴퓨터의 임시 포트다.
응답 패킷의 목적지 포트는 443이 아니다.

처음 예에서 아웃바운드에 443번만 연 네트워크 ACL이 응답을 막은 이유가 여기에 있다.
응답은 사용자 쪽 임시 포트로 나가야 하는데, 그 번호를 허용하는 아웃바운드 규칙이 없다.

요청과 응답에 적힌 주소와 포트 응답 패킷의 목적지 포트는 사용자 쪽 임시 포트여서, 443번만 허용한 아웃바운드 규칙에는 맞지 않는다. 개념 도해 요청과 응답에 적힌 주소와 포트 연결 하나의 두 방향 사용자 컴퓨터 임시 포트 · 예: 50432 네트워크 ACL 서브넷 경계 웹 서버 포트 443 출발지 IP : 포트 목적지 IP : 포트 ① 요청 사용자 IP : 50432 서버 IP : 443 ② 응답 서버 IP : 443 사용자 IP : 50432 인바운드 아웃바운드 443만 허용한 네트워크 ACL의 판정 허용 규칙의 포트 패킷의 목적지 포트 판정 ① 요청 인바운드 규칙과 대조 443 443 통과 ② 응답 아웃바운드 규칙과 대조 443 50432 차단 응답 패킷의 목적지 포트는 사용자 쪽 임시 포트여서, 443번만 허용한 아웃바운드 규칙에는 맞지 않는다. SOSHIN · DEV NOTES
요청에서 목적지였던 443은 응답에서 출발지 자리로 옮겨 가고, 목적지 자리에는 사용자 쪽 임시 포트가 온다.

보안 그룹은 연결을 기억한다

보안 그룹에서는 이런 일이 생기지 않는다.
보안 그룹은 상태를 기억한다(stateful). 허용한 인바운드 요청의 응답은 아웃바운드 규칙과 상관없이 나가고, 인스턴스가 밖으로 보낸 요청의 응답은 인바운드 규칙과 상관없이 들어온다.

이 동작을 연결 추적(connection tracking)⁠이라고 부른다.
보안 그룹이 연결의 주소와 포트를 기록해 두고, 돌아오는 패킷은 이미 맺어진 연결의 일부로 보고 통과시키는 방식이다.

보안 그룹만 다룬다면 임시 포트를 신경 쓸 일이 없다.
인바운드 규칙에는 밖에서 먼저 연결을 걸어오는 경우만 적으면 된다.

네트워크 ACL은 패킷을 하나하나 따로 본다

네트워크 ACL은 상태를 기억하지 않는다(stateless). 들어온 요청과 나가는 응답을 서로 관계없는 패킷으로 보고 각각 규칙에 대어 본다.
그래서 허용한 요청의 응답도 반대 방향 규칙을 따로 통과해야 한다.

웹 서버가 있는 서브넷이라면 인바운드에 443번을 열고, 아웃바운드에는 사용자 쪽 임시 포트 범위를 열어야 한다.
서버가 밖으로 요청을 보내는 쪽일 때는 방향이 뒤집혀서, 아웃바운드에 443번을, 인바운드에 서버 자신의 임시 포트 범위를 연다.

임시 포트 범위는 연결을 시작한 쪽의 운영체제가 정한다.
리눅스는 기본으로 32768–60999번을, Windows Server 2008 이후는 49152–65535번을 쓰고, 로드밸런서와 NAT 게이트웨이에서 오는 요청은 1024–65535번을 쓴다.

인터넷의 여러 클라이언트를 받는 서버는 어떤 운영체제가 접속할지 알 수 없다.
그래서 AWS의 네트워크 ACL 문서는 이럴 때 1024–65535번을 통째로 열 수 있다고 안내한다.
촘촘하게 막으려고 고른 도구인데, 응답 때문에 오히려 넓은 범위를 열게 된다.

인바운드 규칙이 없어도 응답이 돌아올까

인스턴스가 외부 API에 HTTPS 요청을 보낸다. 아웃바운드는 443을 허용했고, 인바운드에는 규칙을 두지 않았다. 응답이 돌아오는지는 요청이 지나는 경계에 따라 다르다.

요청 통과

응답 통과 · 연결 기억

보안 그룹은 나간 요청을 기억해 인바운드 규칙 없이도 응답을 들여보낸다. 네트워크 ACL은 응답이 향하는 임시 포트를 인바운드 규칙으로 따로 열어야 한다.

규칙을 단순화한 예시다. 응답이 돌아오는 임시 포트의 범위는 요청을 보낸 쪽 운영체제에 따라 다르다. 보안 그룹과 네트워크 ACL을 함께 쓰면 트래픽은 두 경계를 모두 통과해야 한다.

응답 방향이 막히면 겉으로는 시간 초과로만 보인다.
요청은 서버까지 도착했을 수 있으니, 응답이 없다는 것만으로 요청이 들어오지 않았다고 단정하지 말고 들어오는 방향과 나가는 방향을 나눠 확인한다.

네트워크 ACL에는 거부 규칙과 번호가 있다

보안 그룹에는 허용 규칙만 적을 수 있다.
적지 않은 것은 모두 막히지만, 나머지는 열어 둔 채 특정 주소 하나만 골라 막는 일은 보안 그룹으로 할 수 없다.

네트워크 ACL에는 허용과 거부를 모두 적을 수 있다.
규칙마다 1부터 32766까지 번호가 붙고, 번호가 낮은 규칙부터 차례로 맞춰 보다가 처음 일치한 규칙을 적용한다.
그 뒤의 규칙은 보지 않는다.

규칙 번호에 따른 NACL 판정 지점 NACL은 가장 낮은 번호부터 처음 맞는 규칙의 허용·거부를 적용하고 뒤 규칙은 보지 않는다. 개념 도해 규칙 번호에 따른 NACL 판정 지점 규칙 평가 경로 트래픽 ① 낮은 번호 조건 불일치 ② 다음 번호 조건 일치 · 거부 ③ 판정 중단 거부 뒤 규칙 미평가 처음 일치 규칙과 판정 처음 일치 규칙 뒤 규칙 판정 결과 규칙 순서 가 낮은 번호 · 허용 높은 번호 · 거부 통과 규칙 순서 나 낮은 번호 · 거부 높은 번호 · 허용 차단 NACL은 가장 낮은 번호부터 처음 맞는 규칙의 허용·거부를 적용하고 뒤 규칙은 보지 않는다. SOSHIN · DEV NOTES
네트워크 ACL은 번호가 낮은 규칙부터 보고, 처음 맞는 규칙에서 판정을 끝낸다.

그래서 순서가 결과를 바꾼다.
임시 포트를 넓게 열어 둔 상태에서 그 안의 특정 포트만 막으려면, 거부 규칙에 넓은 허용 규칙보다 낮은 번호를 줘야 한다.

어느 번호에도 맞지 않은 패킷은 맨 끝의 별표(*) 규칙이 막는다.
이 규칙은 지울 수 없다.

보안 그룹 규칙에는 다른 보안 그룹을 적을 수 있다

보안 그룹에는 편한 점이 하나 더 있다.
규칙의 출발지에는 IP 범위 대신 다른 보안 그룹을 적을 수도 있다.
그러면 그 보안 그룹이 붙은 인스턴스들의 사설 IP 접속이 허용된다.

데이터베이스의 보안 그룹에 애플리케이션 서버의 IP를 적어 두면, 서버를 교체하거나 늘릴 때마다 규칙을 고쳐야 한다.
새 인스턴스는 대개 다른 사설 IP를 받는다.
고치는 것을 잊으면 새 서버만 데이터베이스에 접속하지 못한다.

출발지에 애플리케이션 서버의 보안 그룹을 적으면 규칙이 그 역할을 맡은 서버들을 가리킨다.
새 서버에 같은 보안 그룹만 붙이면 규칙은 그대로 둬도 된다.

네트워크 ACL에서는 이렇게 쓸 수 없다.
네트워크 ACL 규칙의 출발지와 목적지에는 IP 범위만 적는다.

어떻게 쓰나무엇을 표현하나무너지는 순간
출발지를 주소로 적는다지금 그 자리에 있는 기계교체나 증설 때 규칙이 어긋난다
출발지를 그룹으로 적는다그 역할을 맡은 것들그룹 배정을 빠뜨리면 조용히 막힌다
서브넷 단위로 막는다그 구획 전체응답용 규칙을 빠뜨리면 통신이 끊긴다

네트워크 ACL은 언제 손대는가

AWS는 네트워크 접근을 통제하는 주된 수단으로 보안 그룹을 쓰고, 네트워크 ACL은 필요할 때 큰 단위의 통제로 더하라고 권한다.
인스턴스는 보안 그룹만으로도 지킬 수 있다.

그래서 기본 네트워크 ACL은 모두 허용인 채로 두고, 접근 통제는 보안 그룹에서 해도 괜찮다.
네트워크 ACL을 따로 만드는 것은 서브넷 전체에서 특정 주소 범위를 막아야 할 때나, 보안 그룹을 잘못 붙인 인스턴스가 생겨도 서브넷에서 한 번 더 거르고 싶을 때다.

이미 맺어진 연결을 당장 끊어야 할 때도 쓰인다.
보안 그룹 규칙을 바꿔도 추적 중인 연결은 바로 끊기지 않고, 그 연결이 시간 초과로 정리될 때까지 패킷이 계속 오간다.
상태를 기억하지 않는 네트워크 ACL로 막으면 기존 연결도 끊긴다.

네트워크 ACL을 직접 만든다면 허용 규칙을 하나 적을 때마다 응답이 지나갈 반대 방향 규칙도 함께 적어 둔다.
로드밸런서나 NAT 게이트웨이를 거치는 트래픽이 있다면 그쪽이 쓰는 임시 포트 범위인 1024–65535번도 같이 챙긴다.

규칙이 쌓여서 어디서 막히는지 눈으로 찾기 어려워지면 VPC의 Reachability Analyzer가 도움이 된다.
두 자원 사이의 경로를 설정만으로 따져 보고, 막혔다면 어느 구성 요소에서 막혔는지 알려 준다.
빠뜨린 네트워크 ACL 규칙도 여기서 드러난다.

소신을 상징하는 까마귀 목판화 일러스트
작성자소신 · Soshin

웹과 서버를 만들고, 개발하며 배운 것들을 글로 남깁니다.

좌우로 움직여 보세요