- Published on
Azure VM SSH 타임아웃 - NSG·UDR 진단 체크리스트
- Authors
- Name
- 스타차일드
- https://x.com/ETFBITX
서버에 ssh user@<public-ip>를 쳤는데 비밀번호 프롬프트조차 못 보고 타임아웃이 난다면, 대개 “패킷이 VM까지 못 가거나(ingress)”, “VM이 응답을 못 내보내거나(egress/return path)”, “중간에서 드롭(NSG/UDR/NVA)”되는 문제입니다. 특히 Azure에서는 NSG(Network Security Group) 와 UDR(User Defined Route, 라우트 테이블) 조합에서 흔히 사고가 납니다.
이 글은 VM 내부에서 sshd가 죽었는지 같은 OS 레벨 이전에, 네트워크 레이어에서 SSH 타임아웃을 가장 빠르게 진단하는 체크리스트입니다.
> VM 자체가 부팅/에이전트 문제로 접속이 안 되는 케이스(Serial Console/Boot Diagnostics 필요)는 아래 글도 참고하세요: Azure VM 부팅 불가? Boot Diagnostics로 복구
1) 증상 분류: “거절(REFUSED)” vs “타임아웃(TIMEOUT)”
먼저 로컬에서 다음처럼 확인합니다.
# 타임아웃/라우팅/방화벽 드롭 계열이면 보통 여기서 오래 멈춤
ssh -vvv -o ConnectTimeout=5 azureuser@<PUBLIC_IP>
# 포트 레벨로 빠르게 확인
nc -vz -w 3 <PUBLIC_IP> 22
- Connection refused: VM까지는 갔는데(또는 중간 장비가 RST), VM/방화벽/sshd 문제일 가능성이 큼.
- Connection timed out: 중간에서 드롭(NSG/UDR/NVA/온프레 방화벽) 가능성이 큼.
이 글은 “타임아웃”에 집중합니다.
2) 가장 흔한 원인: NSG 인바운드 22 미허용(또는 우선순위에 막힘)
Azure NSG는 우선순위 숫자가 낮을수록 먼저 적용됩니다. “Allow SSH 22”를 만들었는데도 타임아웃이면 아래를 봐야 합니다.
2-1) NSG가 어디에 붙어 있는지부터 확인
NSG는 서브넷에도 붙고 NIC(네트워크 인터페이스) 에도 붙을 수 있습니다. 둘 다 붙어 있으면 둘 다 통과해야 합니다.
- VM → Networking → Network interface 클릭
- NIC의 Effective security rules 확인
- Subnet의 NSG도 확인
CLI로도 확인 가능합니다.
# NIC에 연결된 NSG 확인
az network nic show -g <RG> -n <NIC_NAME> --query "networkSecurityGroup.id" -o tsv
# 서브넷에 연결된 NSG 확인
az network vnet subnet show -g <RG> --vnet-name <VNET> -n <SUBNET> --query "networkSecurityGroup.id" -o tsv
2-2) “Source”가 내 공인 IP인지, 아니면 Any인지
회사/집 IP가 바뀌었는데 NSG는 예전 IP를 허용하고 있으면 그대로 타임아웃이 납니다.
권장 패턴:
- 운영 환경:
Source = <내 고정 공인 IP>/32또는 Bastion/Jumpbox만 허용 - 임시 진단: 잠깐
Source = Any로 열어 원인 분리 (진단 후 즉시 원복)
2-3) Deny 규칙이 Allow보다 우선 적용되는지
예: DenyAllInbound (priority 100) 같은 규칙이 있으면, AllowSSH (priority 300)은 영원히 적용되지 않습니다.
포털의 NSG 규칙 목록에서 Priority를 반드시 확인하세요.
3) UDR(라우트 테이블)로 인해 “돌아오는 길(return path)”이 끊기는 문제
SSH는 TCP이므로 3-way handshake가 성립해야 합니다.
- Client → VM: SYN
- VM → Client: SYN-ACK
- Client → VM: ACK
여기서 VM의 응답(SYN-ACK)이 엉뚱한 곳으로 라우팅되면, 클라이언트는 타임아웃으로 보게 됩니다. UDR이 대표 원인입니다.
3-1) 서브넷에 Route table이 연결돼 있는지 확인
az network vnet subnet show -g <RG> --vnet-name <VNET> -n <SUBNET> --query "routeTable.id" -o tsv
연결돼 있다면 해당 라우트 테이블의 라우트를 확인합니다.
az network route-table route list -g <RG> --route-table-name <ROUTE_TABLE> -o table
3-2) 0.0.0.0/0을 NVA(방화벽/가상 어플라이언스)로 보내는 경우
가장 흔한 형태:
0.0.0.0/0 -> Virtual appliance (10.x.x.x)
이 구성 자체는 흔하지만, 아래 중 하나면 SSH가 타임아웃 납니다.
- NVA가 인바운드(22) 세션을 허용하지 않음
- NVA가 SNAT/대칭 라우팅을 보장하지 않음
- NVA가 장애/미구성 상태
특히 “인바운드는 Public IP로 들어오는데, 아웃바운드는 NVA로 나간다” 같은 비대칭 경로(asymmetric routing) 는 TCP 세션을 망가뜨립니다.
4) Effective Routes / Effective Security Rules로 “실제 적용 상태”를 본다
Azure 네트워크 문제는 “설정 화면”보다 Effective(유효) 뷰가 훨씬 정확합니다. NIC 기준으로 확인하세요.
4-1) NIC의 Effective routes 확인
az network nic show-effective-route-table -g <RG> -n <NIC_NAME> -o table
여기서 체크할 것:
0.0.0.0/0의 NextHop이 무엇인지 (Internet? VirtualAppliance?)- 내 클라이언트 공인 IP로의 리턴 트래픽이 어떤 경로로 나가는지(대개 기본 경로에 의존)
4-2) NIC의 Effective NSG rules 확인
az network nic list-effective-nsg -g <RG> -n <NIC_NAME> -o json
여기서 DestinationPortRange=22, Direction=Inbound, Access=Allow가 실제로 존재하는지, 그리고 더 높은 우선순위의 Deny가 없는지 확인합니다.
5) Network Watcher로 “NSG가 막는지/라우팅이 이상한지” 즉시 판별
포털에서 Network Watcher가 꺼져 있으면 켜야 합니다(리전별).
5-1) IP Flow Verify: NSG 관점에서 허용/차단 확인
- Network Watcher → IP flow verify
- VM, NIC 선택
- Direction: Inbound
- Protocol: TCP
- Local port: 22
- Remote IP: 내 공인 IP
CLI 예시:
az network watcher test-ip-flow \
--resource-group <RG> \
--vm <VM_NAME> \
--direction Inbound \
--protocol TCP \
--local <VM_PRIVATE_IP> \
--local-port 22 \
--remote <MY_PUBLIC_IP> \
--remote-port 50000
결과가 Deny면 NSG(또는 ASG) 규칙 문제입니다.
5-2) Next Hop: UDR/NVA로 어디로 가는지 확인
az network watcher show-next-hop \
--resource-group <RG> \
--vm <VM_NAME> \
--source-ip <VM_PRIVATE_IP> \
--dest-ip 8.8.8.8
- NextHopType이
VirtualAppliance로 나오면 기본 경로가 NVA로 향하고 있다는 뜻입니다. - 이때 NVA가 리턴 트래픽을 정상 처리하는지(정책/라우팅/상태)를 함께 봐야 합니다.
5-3) Connection troubleshoot: end-to-end로 막힌 지점 찾기
- Network Watcher → Connection troubleshoot
- Source: 내 환경(보통은 Azure 내 다른 VM을 Source로 두는 게 정확)
- Destination: 문제 VM의 22
외부 PC에서 Azure VM으로의 경로는 Azure가 100% 관측하지 못하므로, 가능하면 같은 VNet/피어링된 VNet의 테스트 VM에서 진단하는 편이 좋습니다.
6) “Public IP로 접속”인데도 UDR이 영향을 주는 이유
헷갈리는 지점이 하나 있습니다.
- 인바운드: Public IP → Azure LB(SNAT/DNAT) → VM NIC
- 아웃바운드(리턴): VM NIC → 서브넷 라우팅(UDR) → Internet 또는 NVA
즉, 인바운드는 들어왔는데 리턴이 UDR 때문에 Internet이 아닌 NVA로 빠져나가 세션이 깨질 수 있습니다. 그래서 SSH가 타임아웃처럼 보입니다.
이 패턴은 EKS에서 “Pod는 정상인데 egress만 막히는” 상황과 원인 구조가 비슷합니다(경로/보안 정책의 불일치). 네트워크 경로를 분리해 점검하는 관점은 아래 글도 도움이 됩니다: EKS에서 Pod는 정상인데 egress만 막힐 때 점검
7) 진단 순서(실전): 10분 안에 원인 좁히기
7-1) 1단계: VM 상태/공인 IP 매핑 확인
- VM이 Running인지
- NIC에 Public IP가 연결돼 있는지
- Public IP가 바뀌지 않았는지(동적 할당이면 재시작/재배포로 변경 가능)
az vm show -g <RG> -n <VM_NAME> --show-details --query "{power:powerState, publicIps:publicIps, privateIps:privateIps}" -o yaml
7-2) 2단계: NSG에서 22 인바운드 허용 확인(Effective 기준)
- NIC Effective security rules
- Subnet NSG 포함 여부
- Source IP, Priority, Deny 선행 여부
7-3) 3단계: UDR/Next hop 확인
- Effective route table
0.0.0.0/0이 VirtualAppliance로 가는지- NVA/Firewall 정책에서 22 세션/리턴 허용하는지
7-4) 4단계: Network Watcher로 교차검증
- IP Flow Verify로 NSG 결론
- Next Hop으로 UDR 결론
여기까지에서 대부분 결론이 납니다.
8) 자주 나오는 케이스별 처방
케이스 A) NSG에 Allow 22가 있는데도 타임아웃
- Allow 규칙 Priority가 Deny보다 뒤에 있지 않은지
- NIC/서브넷 양쪽 NSG 모두 통과하는지
- Source가 내 IP로 정확한지
케이스 B) UDR로 0.0.0.0/0을 방화벽(NVA)로 보낸 뒤부터 접속 불가
- 방화벽에서 DNAT/SNAT/세션 테이블 정책 확인
- 방화벽 장애 여부 확인
- 임시로 진단하려면:
- 문제 서브넷에서 UDR 분리(테스트 서브넷)
- 또는 특정 관리 대역만 Internet으로 예외 라우트(조직 정책에 맞게)
케이스 C) 특정 네트워크(회사)에서만 타임아웃
- 회사 방화벽에서 22 outbound 차단 가능
- 회사 NAT 공인 IP가 바뀌어 NSG Source mismatch
- 해결: Azure Bastion / VPN / 허용 IP 업데이트
9) 최소한의 보안 권장안(운영 기준)
- 22를 Internet 전체에 개방하지 말 것
- 가능하면 Azure Bastion 또는 Jumpbox(관리 전용 서브넷) 사용
- NSG는
Source=<관리망>/32,DestinationPort=22,Priority명확히 - UDR로 NVA를 쓸 경우 대칭 라우팅과 SNAT 정책을 설계 단계에서 확정
10) 마무리: “NSG냐 UDR이냐”를 빠르게 가르는 핵심
- IP Flow Verify가 Deny면: 거의 확실히 NSG(또는 상위 정책) 문제
- IP Flow Verify가 Allow인데도 타임아웃이면: UDR/NVA/비대칭 라우팅/중간 방화벽 문제일 확률이 큼
- 최종적으로는 NIC의 Effective routes와 Network Watcher의 Next hop이 결론을 줍니다.
SSH 타임아웃은 답답하지만, Azure에서는 관측 도구가 잘 갖춰져 있습니다. “설정 화면”을 믿기보다 Effective(유효) 상태와 경로(Next hop) 를 기준으로 보면, 원인을 체계적으로 좁힐 수 있습니다.