VirtualBox VPN 랩: 게이트웨이 VM 대 호스트 전용 네트워크
VirtualBox VPN 랩을 위해 라우팅된 게이트웨이 VM과 호스트 전용 세그먼트 중에서 고르고, 터널이 끊길 때 게스트가 닫힌 실패를 하도록 만드세요.
VPN 랩에 얼마나 많은 장치가 필요한지 결정해야 합니다. 두 VirtualBox 세그먼트 사이의 라우팅된 게이트웨이 VM은 실제 클라이언트가 뒤에 앉는 주소 변환, 반환 경로, 방화벽 위치를 재현합니다. 호스트 전용 세그먼트 하나는 통제된 문 하나를 줄 뿐 그 이상은 아닙니다. 게이트웨이 버전은 게스트 세 대와 유지해야 하는 라우팅 테이블이 들고, 호스트 전용 버전은 게스트 한 대와 정책 하나면 됩니다. 세 가지 질문이 둘을 가르며, 세 번째 질문이 테스트가 애초에 통과할 수 있는지를 결정합니다.
무엇이든 복제하기 전에 세 가지 질문에 답하세요
VPN 서버가 무엇을 관찰해야 하는지부터 시작하세요. 서버가 테스트 게스트의 것이 아닌 출발지 주소를 봐야 한다면, 둘 사이에서 무언가가 변환해야 하고, 그 무언가는 여러분이 통제하는 라우터여야 합니다. 호스트 전용 네트워킹은 게스트의 세그먼트에 호스트의 어댑터를 줄 뿐 변환기를 주지 않습니다. 그다음 게스트가 외부의 무언가에 도달해야 할 때 NAT 어댑터를 붙이는데, VirtualBox 자체의 NAT 엔진이 묻지도 않고 출발지를 다시 씁니다.
다음으로 게스트가 터널 외의 무언가에 도달해도 되는지 물으세요. 그 답이 내부 또는 호스트 전용을 고르며, 바로 이 질문을 대부분의 랩 글이 건너뜁니다. 마지막으로 터널이 끊길 때 무슨 일이 일어나야 하는지 물으세요. 그것이 토폴로지가 아니라 정책을 결정하며, 행복한 경로만 증명하는 랩은 거의 아무것도 시험하지 않은 것이기 때문입니다.
| What the test requires | Routed gateway VM | Host-only guest |
|---|---|---|
| Server sees a translated source address | Yes, from your own MASQUERADE rule | No, VirtualBox NAT does it instead |
| The guest has exactly one egress | Yes, while the second adapter faces the tunnel | Only until a NAT adapter is attached |
| Policy is testable during a tunnel failure | Rules live in one place | Rules live on each guest |
세 역할을 내부 네트워크로 배선하세요
게스트 세 대와 이름 있는 세그먼트 두 개를 사용하고, 게이트웨이는 두 곳 모두에 어댑터를 가진 유일한 머신이 되게 하세요:
VBoxManage modifyvm lab-client --nic1 intnet --intnet1 WAN
VBoxManage modifyvm lab-server --nic1 intnet --intnet1 LAN
VBoxManage modifyvm lab-gw --nic1 intnet --intnet1 WAN --nic2 intnet --intnet2 LAN
내부 네트워크에는 별도의 생성 단계가 없습니다. --intnet1의 문자열이 곧 세그먼트이며, 두 머신은 이름이 정확히 일치할 때만 그것을 공유하고 호스트의 어떤 것도 거기에 연결되지 않습니다. 바로 이 마지막 성질 때문에 랩이 깨끗하게 반복됩니다. 호스트의 경로, 호스트 자체의 VPN 클라이언트, 방화벽이 실수로 게스트에 닿을 수 없기 때문입니다. 내부 세그먼트에는 DHCP 서버도 없으므로(직접 추가하지 않는 한) 고정 주소가 가장 짧은 길입니다.
클라이언트에는 WAN 주소만 주고, 기본 게이트웨이는 게이트웨이의 WAN 주소를 가리키게 하세요. 서버는 LAN 주소를 받고 게이트웨이의 LAN 주소를 자신의 기본 게이트웨이로 사용합니다. 한 세그먼트에 두 주소를 유지하거나 다른 세그먼트로 향하는 잘못된 경로를 가진 게스트는 라우터를 우회하는 경로를 가지며, 아래 테스트는 여러분에게 거짓말을 할 것입니다.
저는 VM 이름 옆에 네 주소와 두 세그먼트 이름을 적은 텍스트 파일을 두고 모든 셸에 붙여 넣습니다. 몇 주 뒤 프로필 변경이 무언가를 깨뜨릴 때, 그 파일이 프로필을 디버깅하는 것과 제 기억을 디버깅하는 것의 차이가 됩니다.
누출되면 안 되는 세그먼트에는 내부 또는 호스트 전용을 고르세요
호스트 전용 모드는 호스트 자체에 가상 어댑터를 만들고(보통 vboxnet0), 호스트에 게스트 세그먼트의 주소를 줍니다. 이것은 관리에는 편리하고 격리 테스트에는 치명적입니다. 호스트가 이제 게스트에 직접 닿을 수 있고 호스트 측의 모든 서비스가 가능한 경로가 되기 때문입니다. 내부 모드에는 호스트 어댑터가 전혀 없습니다. 두 모드는 네트워크 설정 패널에서 혼동하기 쉬우므로 라벨이 아니라 문서화된 차이를 확인하세요(VirtualBox 네트워킹 세부 정보 페이지 참조).
터널을 반드시 사용해야 하는 게스트에는 내부가 더 안전한 기본값이며, 게이트웨이가 유일한 출구입니다. 호스트 전용을 유지한다면 호스트 어댑터를 관리 경로로 취급하고 그것을 소리 내어 말하세요. 호스트는 게스트에 닿을 수 있지만, 게스트는 호스트를 출구로 사용할 수 없어야 합니다.
VBoxManage modifyvm lab-client --nic1 hostonly --hostonlyadapter1 vboxnet0
증명할 수 있는 격리가 바로 여러분이 구성한 격리입니다. 내부 어댑터 하나, 게이트웨이의 기본 경로, NAT 어댑터 없음인 게스트에게는 게이트웨이를 우회하는 경로가 없습니다. 호스트 전용 어댑터와 NAT 어댑터를 가진 게스트에게는 두 경로가 있고, 그중 하나만이 여러분이 시험하려던 경로입니다.
게이트웨이에서 라우팅과 변환을 하고, 그다음 닫힌 실패를 시키세요
VirtualBox는 세그먼트 사이를 전달하지 않으며 전달하는 것은 게스트입니다. VPN 서버 VM이 게이트웨이 뒤에 있을 때 전달을 켜고, 클라이언트 트래픽이 서버 쪽으로 나갈 때 변환하세요:
sysctl -w net.ipv4.ip_forward=1
iptables -t nat -A POSTROUTING -o eth1 -j MASQUERADE
이 규칙으로 서버는 클라이언트 대신 게이트웨이의 LAN 주소를 봅니다. 통신사 NAT 뒤의 실제 클라이언트가 네트워크 헤드에 보이는 모습이 바로 이것입니다. sysctl 값을 /etc/sysctl.d/에, 규칙을 배포판이 쓰는 방화벽 서비스에 저장하지 않으면 재부팅이 랩을 조용히 라우팅되었지만 변환되지 않은 상태로 되돌립니다.
전달은 인가가 아닙니다. ACCEPT의 기본 FORWARD 정책 아래에서 기본 경로가 게이트웨이를 가리키는 게스트는 터널이 있든 없든 라우팅 테이블이 고르는 인터페이스로 나갑니다. 게이트웨이에 패키지 설치용 NAT 어댑터도 있다면, 그 어댑터는 터널이 끊기는 순간 작동하는 암호화되지 않은 출구이며, 여러분의 VPN 전용 테스트는 결코 VPN 전용 테스트가 아니었습니다.
서버가 멀리 있고 게이트웨이가 직접 터널을 종료할 때는, 같은 결정이 인터넷에 닿는 NIC가 아니라 터널 인터페이스를 가리킵니다:
iptables -P FORWARD DROP
iptables -A FORWARD -i eth0 -o tun0 -j ACCEPT
iptables -A FORWARD -i tun0 -o eth0 -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
터널 자체의 외부 전송과 대역 밖 관리 경로를 전달되는 트래픽과 분리해 두세요. 게이트웨이를 고치는 유일한 방법이 여러분이 디버깅하는 터널을 통하는 것이라면, 랩은 잠금 사고 연습이 됩니다. 시리얼 콘솔, 호스트 전용 관리 어댑터, 알려진 정상 상태의 스냅숏은 망가진 라우터를 손으로 복구하는 것보다 쌉니다.
경로는 호스트가 아니라 게스트에서 검증하세요
바깥으로 나아가며 작업하세요. 클라이언트가 게이트웨이의 WAN 주소에 닿는지, 다음으로 게이트웨이를 거쳐 서버에 닿는지, 다음으로 VPN 포트로 가는 연결이 나갔다 돌아오는지 확인하세요. 게이트웨이의 두 인터페이스에서 잡은 캡처는 응답이 도착하는지, 반환 경로에서 버려지는지를 보여 줍니다. 클라이언트에서만 잡은 캡처로는 구분할 수 없습니다:
tcpdump -ni eth0 udp port 1194
tcpdump -ni tun0 udp port 1194
그다음 게스트에서 주소 반사 서비스에 어떤 출발지가 보이는지 물어 게이트웨이 자체의 출구 주소와 비교하며 출구를 증명하세요. 답이 호스트의 주소와 일치하면 터널을 우회하는 경로가 존재합니다. 게스트가 실제로 어느 리졸버를 쓰는지 확인하고, IPv6는 따로 확인하세요. IPv6가 켜져 있는데 터널이 IPv4만 나르는 세그먼트는 우연이 아니라 설계로 새기 때문입니다.
마지막으로 일부러 망가뜨리세요. 터널을 멈추거나 바깥 포트를 막고, 게스트에서 새 연결을 여세요. 그것은 실패해야 하고, 이유는 여러분이 이름 붙일 수 있는 것이어야 합니다. 경로가 없거나, 거부 규칙이 있거나, 리졸버가 죽은 것입니다. 터널을 다시 시작하고 게스트가 네트워크를 다시 짓지 않고 회복하는지 확인하세요. Hamachi나 ZeroTier 같은 메시 VPN이 랩을 공유한다면, 브리지된 어댑터는 메시가 아니라 어댑터 이름을 따르므로 클라이언트가 자체 가상 어댑터를 설치한 뒤 브리지를 다시 향하게 해야 합니다.
VBoxManage list bridgedifs
VBoxManage modifyvm lab-client --bridgeadapter1 <mesh-adapter-name>
게스트의 터널을 호스트와 공유하는 것은 문제를 그대로 비춥니다. 호스트의 기본 경로를 게스트로 향하게 하는 것은 동작하며, 게스트 안의 프록시도 동작합니다. 호스트를 거치는 NAT는 호스트가 시작한 트래픽에 대해 게스트의 터널을 나르지 않습니다. 세그먼트 이름과 방화벽 규칙을 한곳에 저장하고, 동작하는 상태의 스냅숏을 찍고, 서버가 관찰한 출발지 주소를 기록하세요. 그러면 다음 프로필 변경은 다시 지은 랩이 아니라 스크립트 한 번으로 끝납니다.