← 목록

Private Subnet 라우트 테이블에 특정 IP 라우트를 추가해야 하는 이유

보안 그룹을 열었는데도 접속이 안 되는 이유를 응답 경로에서 찾은 과정. 비대칭 라우팅과 Longest Prefix Match, 그리고 이 방식의 한계

2026-04-20AWSNetworkingTroubleshooting

배경

운영 환경의 EC2 인스턴스들은 Private Subnet에 있다. 사내에서 특정 서버에 직접 붙어야 할 일이 생겨 보안 그룹 인바운드에 내 공인 IP와 포트를 열었다. 그런데 접속이 되지 않았다. 거부(refused)도 아니고 타임아웃이었다.

처음엔 보안 그룹을 잘못 넣었나 싶어 몇 번을 다시 확인했다. 규칙은 맞았다. 원인은 요청이 아니라 응답이 나가는 길에 있었다.


증상: 요청은 도착하는데 응답이 안 온다

접속이 안 될 때 거부와 타임아웃은 의미가 다르다.

증상대체로 의미하는 것
Connection refused패킷은 도착했고, 그 포트에서 듣는 프로세스가 없다
Connection timeout응답이 돌아오지 않는다. 차단됐거나, 길이 없거나, 길이 다르다

타임아웃이었으니 후자였다. 인스턴스 안에서 패킷을 직접 확인해보면 상황이 분명해진다. 들어오는 SYN은 찍히고, 인스턴스도 SYN-ACK을 내보낸다. 그런데 클라이언트에는 그 응답이 도착하지 않는다.

[클라이언트]  --- SYN --->  [EC2]        도착한다
[클라이언트]  <--- ???  ---  [EC2]        내보내는데 안 온다

서버는 자기 할 일을 했다고 생각하고, 클라이언트는 아무것도 못 받은 채 기다린다. 이 상태에서 보안 그룹만 다시 들여다보면 답이 안 나온다.


현재 구조

Private Subnet의 라우트 테이블 구성이다.

목적지다음 홉설명
VPC CIDRlocalVPC 내부 통신
0.0.0.0/0NAT Gateway기본 외부 통신
[my-ip-1]/32IGW특정 IP (수동 추가)
[my-ip-2]/32IGW특정 IP (수동 추가)

Dev 환경도 동일한 패턴으로 구성되어 있다.

Private RT 라우트 테이블 구성


왜 라우트 추가가 필요한가

들어오는 길과 나가는 길은 따로 정해진다

외부에서 EC2로 요청을 보내는 것 자체는 문제가 없다. 요청은 인터넷에서 IGW를 지나 Elastic IP를 가진 EC2까지 정상적으로 도착한다.

문제는 EC2가 응답을 돌려보낼 때다. 응답 패킷의 목적지는 요청자의 공인 IP이고, 이 패킷이 어디로 나갈지는 라우트 테이블이 정한다. 요청이 IGW로 들어왔다는 사실은 여기에 아무 영향을 주지 않는다.

라우트가 없을 때 NAT Gateway를 타는 흐름

들어올 때와 나갈 때 경로가 달라지는 이 상태를 비대칭 라우팅이라고 부른다. 상태를 추적하는 장비나 프로토콜이 중간에 있으면 대개 여기서 끊긴다.

NAT Gateway를 타면 왜 안 되는가

NAT Gateway로 응답이 나가면 출발지 IP가 EC2의 Elastic IP가 아니라 NAT Gateway의 IP로 변환(SNAT)된다. 요청자 입장에서는 A에게 요청했는데 B가 대답하는 셈이라, TCP 세션과 매칭되지 않아 응답이 버려진다.

NAT Gateway 쪽에서도 이 패킷은 낯설다. NAT는 자기가 내보낸 요청에 대한 응답을 되돌려 보내기 위해 세션 테이블을 유지하는데, 이 응답 패킷은 그 테이블에 없는 흐름이다. 안에서 밖으로 나가는 통신을 처리하도록 만들어진 장치라서, 밖에서 시작된 통신의 뒷부분만 떠맡을 수 없다.

IGW를 타면 왜 되는가

IGW는 Elastic IP와 Private IP 사이의 1:1 NAT만 수행한다. 응답이 IGW로 나가면 출발지 IP가 EC2의 Elastic IP로 유지되고, 요청자는 자기가 요청한 그 주소에서 온 응답으로 인식한다. 그래서 세션이 성립한다.

라우트 추가 후 IGW를 타는 정상 흐름


Longest Prefix Match 원리

라우트 테이블은 가장 구체적인 경로를 우선 적용한다.

따라서 [my-ip]/32 → IGW가 0.0.0.0/0 → NAT GW보다 항상 우선한다. 해당 IP와의 통신만 IGW를 타고, 나머지 트래픽은 그대로 NAT Gateway를 통해 나간다.

이 성질 덕분에 이 방식이 안전하다. 서브넷 전체의 기본 경로를 바꾸지 않고 특정 IP 하나에만 예외를 만드는 것이라서, 나머지 통신에는 영향이 없다.


외부에서 접근하기 위한 작업 순서

  1. 라우트 테이블에 IP 추가: 대상 Private RT에 [접근할 IP]/32 → IGW 라우트를 추가한다
  2. 보안 그룹에 IP 허용: 해당 EC2의 보안 그룹 인바운드에 IP와 포트(SSH 22, RDP 3389 등)를 추가한다
  3. IP 변경 시 양쪽 모두 갱신: ISP에 의해 공인 IP가 바뀌면 라우트 테이블과 보안 그룹을 함께 고쳐야 한다

둘 중 하나만 하면 증상이 다르게 나타난다. 보안 그룹만 열면 이 글의 타임아웃이 되고, 라우트만 추가하면 보안 그룹에서 막혀 역시 타임아웃이 된다. 증상이 같아서 헷갈리기 쉬우니, 접속이 안 되면 두 가지를 같이 확인하는 편이 빠르다.


이 방식의 한계

동작하지만 관리 비용이 붙는다는 점은 분명히 해두는 게 좋다.

그래서 상시 접근이 필요하다면 SSM Session Manager처럼 인바운드를 열지 않고 붙는 방법이나, Bastion 또는 VPN으로 진입점을 하나로 모으는 쪽이 낫다. 이 글의 방식은 임시로 열어야 할 때, 혹은 고정 IP를 가진 특정 대상에만 쓰는 예외 수단으로 보는 게 맞다.


참고


배운 점

허용과 경로는 다른 문제였다. 보안 그룹만 열어두고 접속이 안 될 때 한참을 헤맸던 이유는 둘을 같은 것으로 생각했기 때문이다. 보안 그룹은 들어오는 것을 허용할 뿐이고, 응답이 어느 길로 나가는지는 라우트 테이블이 정한다. 요청은 들어왔는데 응답이 NAT로 나가면 연결은 성립하지 않는다.

그래서 네트워크 문제는 방향을 나눠서 본다. 들어오는 경로와 나가는 경로는 별개이고, 둘 다 맞아야 통신이 된다. 타임아웃이라는 증상 앞에서 "막혔나"만 묻지 않고 "돌아오는 길이 있나"를 같이 묻게 된 게 이 일의 소득이다.

경로는 동작만이 아니라 비용과 보안도 결정한다. 같은 원리가 비용으로 드러난 사례가 S3 VPC Gateway Endpoint 점검이고, 기본값으로 잡힌 경로가 통신을 끊은 사례가 Docker 네트워크가 사내 네트워크를 망가뜨렸던 날이다. 세 글 모두 결론은 같다. 트래픽이 어느 길로 가는지 모르면 설계가 끝난 게 아니다.


이어 읽기